From 761df3c5622d66029c68d28fb39b537cb482a080 Mon Sep 17 00:00:00 2001 From: Yuri Kuznetsov Date: Mon, 14 Mar 2022 12:41:21 +0200 Subject: [PATCH] type fixes --- .../Espo/Services/AdminNotifications.php | 6 ++++ application/Espo/Services/App.php | 12 ++++++-- application/Espo/Services/Attachment.php | 7 +++++ application/Espo/Services/Email.php | 9 ++++-- application/Espo/Services/ExternalAccount.php | 5 ++-- application/Espo/Services/GlobalSearch.php | 2 +- application/Espo/Services/Import.php | 2 +- application/Espo/Services/Language.php | 3 ++ application/Espo/Services/LastViewed.php | 9 +++++- application/Espo/Services/Layout.php | 8 +++++ application/Espo/Services/Metadata.php | 2 ++ application/Espo/Services/MysqlCharacter.php | 12 +++++--- application/Espo/Services/Notification.php | 6 ++++ application/Espo/Services/Pdf.php | 2 +- application/Espo/Services/Record.php | 2 ++ application/Espo/Services/RecordTree.php | 6 +++- application/Espo/Services/Settings.php | 1 + application/Espo/Services/Stream.php | 29 ++++++++++++++----- 18 files changed, 98 insertions(+), 25 deletions(-) diff --git a/application/Espo/Services/AdminNotifications.php b/application/Espo/Services/AdminNotifications.php index 8b7a73100d..984e52ac75 100644 --- a/application/Espo/Services/AdminNotifications.php +++ b/application/Espo/Services/AdminNotifications.php @@ -192,12 +192,18 @@ class AdminNotifications implements curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 60); + /** @var string|false */ $result = curl_exec($ch); $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); + if ($result === false) { + return null; + } + + if ($httpCode !== 200) { return null; } diff --git a/application/Espo/Services/App.php b/application/Espo/Services/App.php index dfbd8aa811..6ca8f5864c 100644 --- a/application/Espo/Services/App.php +++ b/application/Espo/Services/App.php @@ -164,7 +164,7 @@ class App ]; foreach (($this->metadata->get(['app', 'appParams']) ?? []) as $paramKey => $item) { - /** @var ?class-string */ + /** @var ?class-string */ $className = $item['className'] ?? null; if (!$className) { @@ -172,7 +172,13 @@ class App } try { - $itemParams = $this->injectableFactory->create($className)->get(); + $obj = $this->injectableFactory->create($className); + + if (!method_exists($obj, 'get')) { + continue; + } + + $itemParams = $obj->get(); } catch (Throwable $e) { $this->log->error("appParam {$paramKey}: " . $e->getMessage()); @@ -241,6 +247,7 @@ class App if (!$this->user->isAdmin()) { $data = unserialize(serialize($data)); + /** @var string[] */ $scopeList = array_keys($this->metadata->get(['scopes'], [])); foreach ($scopeList as $scope) { @@ -427,6 +434,7 @@ class App */ public function jobPopulateArrayValues(): void { + /** @var string[] */ $scopeList = array_keys($this->metadata->get(['scopes'])); $query = $this->entityManager->getQueryBuilder() diff --git a/application/Espo/Services/Attachment.php b/application/Espo/Services/Attachment.php index 1a59c4e477..b426c60419 100644 --- a/application/Espo/Services/Attachment.php +++ b/application/Espo/Services/Attachment.php @@ -429,8 +429,15 @@ class Attachment extends Record curl_setopt_array($ch, $opts); + /** @var string|false */ $response = curl_exec($ch); + if ($response === false) { + curl_close($ch); + + return null; + } + $headerSize = curl_getinfo($ch, \CURLINFO_HEADER_SIZE); $header = substr($response, 0, $headerSize); diff --git a/application/Espo/Services/Email.php b/application/Espo/Services/Email.php index e3316c5e66..0325cebe71 100644 --- a/application/Espo/Services/Email.php +++ b/application/Espo/Services/Email.php @@ -38,6 +38,8 @@ use Espo\Entities\Attachment; use Espo\Entities\UserData; use Espo\Repositories\UserData as UserDataRepository; +use Espo\Core\Utils\Json; + use Espo\{ ORM\Entity, Entities\User, @@ -332,7 +334,7 @@ class Email extends Record implements 'message' => $e->getMessage(), ]; - throw ErrorSilent::createWithBody('sendingFail', json_encode($errorData)); + throw ErrorSilent::createWithBody('sendingFail', Json::encode($errorData)); } $this->entityManager->saveEntity($entity, ['isJustSent' => true]); @@ -398,12 +400,13 @@ class Email extends Record implements return; } + /** @var class-string */ $handlerClassName = $smtpHandlers->$emailAddress; $handler = null; try { - $handler = $this->getInjection('injectableFactory')->create($handlerClassName); + $handler = $this->injectableFactory->create($handlerClassName); } catch (Throwable $e) { $this->log->error( @@ -952,7 +955,7 @@ class Email extends Record implements 'message' => $e->getMessage(), ]; - throw ErrorSilent::createWithBody('sendingFail', json_encode($errorData)); + throw ErrorSilent::createWithBody('sendingFail', Json::encode($errorData)); } return true; diff --git a/application/Espo/Services/ExternalAccount.php b/application/Espo/Services/ExternalAccount.php index be059eb7c3..d396db17e6 100644 --- a/application/Espo/Services/ExternalAccount.php +++ b/application/Espo/Services/ExternalAccount.php @@ -91,12 +91,11 @@ class ExternalAccount extends Record implements Di\HookManagerAware */ public function ping(string $integration, string $userId) { - $entity = $this->getExternalAccountEntity($integration, $userId); - try { $client = $this->getClient($integration, $userId); - if ($client) { + if ($client && method_exists($client, 'ping')) { + /** @var @bool */ return $client->ping(); } } diff --git a/application/Espo/Services/GlobalSearch.php b/application/Espo/Services/GlobalSearch.php index 0204364ee2..fa3dea1e86 100644 --- a/application/Espo/Services/GlobalSearch.php +++ b/application/Espo/Services/GlobalSearch.php @@ -112,7 +112,7 @@ class GlobalSearch implements $sth = $this->entityManager->getQueryExecutor()->execute($unionQuery); - $rows = $sth->fetchAll(PDO::FETCH_ASSOC); + $rows = $sth->fetchAll(PDO::FETCH_ASSOC) ?: []; $resultList = []; diff --git a/application/Espo/Services/Import.php b/application/Espo/Services/Import.php index bace138528..f0f2adbb45 100644 --- a/application/Espo/Services/Import.php +++ b/application/Espo/Services/Import.php @@ -72,7 +72,7 @@ class Import extends Record ->withSearchParams($searchParams) ->build(); - /** @var iterable<\Espo\ORM\Entity> */ + /** @var \Espo\ORM\Collection<\Espo\ORM\Entity> */ $collection = $this->getImportRepository()->findResultRecords($entity, $link, $query); $listLoadProcessor = $this->injectableFactory->create(ListLoadProcessor::class); diff --git a/application/Espo/Services/Language.php b/application/Espo/Services/Language.php index 672c840467..3e31c852b8 100644 --- a/application/Espo/Services/Language.php +++ b/application/Espo/Services/Language.php @@ -64,11 +64,13 @@ class Language // TODO use proxy protected function getDefaultLanguage(): LanguageUtil { + /** @var LanguageUtil */ return $this->container->get('defaultLanguage'); } protected function getLanguage(): LanguageUtil { + /** @var LanguageUtil */ return $this->container->get('language'); } @@ -120,6 +122,7 @@ class Language unset($data['Campaign']['presetFilters']); } else { + /** @var string[] */ $scopeList = array_keys($this->metadata->get(['scopes'], [])); foreach ($scopeList as $scope) { diff --git a/application/Espo/Services/LastViewed.php b/application/Espo/Services/LastViewed.php index bf1022fdde..f404656484 100644 --- a/application/Espo/Services/LastViewed.php +++ b/application/Espo/Services/LastViewed.php @@ -38,6 +38,8 @@ use Espo\Core\{ use Espo\Entities\User; +use ArrayAccess; + class LastViewed { private $metadata; @@ -105,7 +107,12 @@ class LastViewed $entity->set('id', Util::generateId()); } - if ($maxSize && is_countable($collection) && count($collection) > $maxSize) { + if ( + $maxSize && + is_countable($collection) && + count($collection) > $maxSize && + $collection instanceof ArrayAccess + ) { $total = -1; unset($collection[count($collection) - 1]); diff --git a/application/Espo/Services/Layout.php b/application/Espo/Services/Layout.php index 357941723d..4488ef9ccd 100644 --- a/application/Espo/Services/Layout.php +++ b/application/Espo/Services/Layout.php @@ -34,6 +34,7 @@ use Espo\Entities\LayoutRecord; use Espo\Core\{ Exceptions\NotFound, Exceptions\Forbidden, + Exceptions\Error, Acl, Acl\Exceptions\NotImplemented, Utils\Layout as LayoutUtil, @@ -223,6 +224,7 @@ class Layout $link = $item; if (is_object($item)) { + /** @var \stdClass $item */ $link = $item->name ?? null; } @@ -361,6 +363,10 @@ class Layout { $relationships = $this->getOriginal($scope, 'relationships') ?? []; + if (!is_array($relationships)) { + throw new Error("Bad 'relationships' layout."); + } + $result = (object) []; foreach ($relationships as $i => $item) { @@ -374,6 +380,8 @@ class Layout continue; } + /** @var stdClass $item */ + $item = clone $item; $item->index = 5 + 0.001 * $i; diff --git a/application/Espo/Services/Metadata.php b/application/Espo/Services/Metadata.php index d7b698257b..d34ef14eca 100644 --- a/application/Espo/Services/Metadata.php +++ b/application/Espo/Services/Metadata.php @@ -59,6 +59,7 @@ class Metadata return $data; } + /** @var string[] */ $scopeList = array_keys($this->metadata->get(['entityDefs'], [])); foreach ($scopeList as $scope) { @@ -151,6 +152,7 @@ class Metadata unset($data->entityDefs->Settings); + /** @var string[] */ $dashletList = array_keys($this->metadata->get(['dashlets'], [])); foreach ($dashletList as $item) { diff --git a/application/Espo/Services/MysqlCharacter.php b/application/Espo/Services/MysqlCharacter.php index c362f6eb36..a9a15cbb74 100644 --- a/application/Espo/Services/MysqlCharacter.php +++ b/application/Espo/Services/MysqlCharacter.php @@ -78,6 +78,7 @@ class MysqlCharacter extends \Espo\Core\Services\Base $tableName = \Espo\Core\Utils\Util::toUnderScore($entityName); // Get table columns params + /** @phpstan-ignore-next-line */ $query = "SHOW FULL COLUMNS FROM `". $tableName ."` WHERE `Collation` <> 'utf8mb4_unicode_ci'"; try { @@ -109,6 +110,7 @@ class MysqlCharacter extends \Espo\Core\Services\Base continue; } + /** @phpstan-ignore-next-line */ if (!isset($columnParams[$columnName]) || empty($columnParams[$columnName]['Type'])) { continue; } @@ -120,10 +122,12 @@ class MysqlCharacter extends \Espo\Core\Services\Base case 'text': case 'jsonObject': case 'jsonArray': - $query = "ALTER TABLE `".$tableName."` - CHANGE COLUMN `". $columnName ."` `". $columnName ."` ". $columnParams[$columnName]['Type'] ." - CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; - "; + /** @phpstan-ignore-next-line */ + $query = "ALTER TABLE `".$tableName."` ". + /** @phpstan-ignore-next-line */ + "CHANGE COLUMN `". $columnName ."` `". $columnName ."` ". $columnParams[$columnName]['Type'] . + /** @phpstan-ignore-next-line */ + " CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;"; break; } diff --git a/application/Espo/Services/Notification.php b/application/Espo/Services/Notification.php index 77a165bff6..5434cd3389 100644 --- a/application/Espo/Services/Notification.php +++ b/application/Espo/Services/Notification.php @@ -38,6 +38,8 @@ use Espo\Entities\User; use Espo\Tools\Stream\NoteAccessControl; +use ArrayAccess; + /** * @extends Record<\Espo\Entities\Notification> */ @@ -151,6 +153,10 @@ class Notification extends \Espo\Services\Record ->clone($query) ->find(); + if (!$collection instanceof ArrayAccess) { + throw new Error("Collection is not instance of ArrayAccess."); + } + $count = $this->entityManager ->getRDBRepository('Notification') ->clone($query) diff --git a/application/Espo/Services/Pdf.php b/application/Espo/Services/Pdf.php index 9853f4120f..9f83479625 100644 --- a/application/Espo/Services/Pdf.php +++ b/application/Espo/Services/Pdf.php @@ -256,7 +256,7 @@ class Pdf $contents = $printer->printCollection($collection, $params, $idDataMap); - $entityTypeTranslated = $this->defaultLanguage->translate($entityType, 'scopeNamesPlural'); + $entityTypeTranslated = $this->defaultLanguage->translateLabel($entityType, 'scopeNamesPlural'); $filename = Util::sanitizeFileName($entityTypeTranslated) . '.pdf'; diff --git a/application/Espo/Services/Record.php b/application/Espo/Services/Record.php index 3ca22e9193..7a0c0adb2a 100644 --- a/application/Espo/Services/Record.php +++ b/application/Espo/Services/Record.php @@ -344,6 +344,8 @@ class Record extends RecordService implements $list = []; + assert(is_string($this->entityType)); + foreach ($this->fieldUtil->getEntityTypeFieldList($this->entityType) as $field) { if ( $this->metadata diff --git a/application/Espo/Services/RecordTree.php b/application/Espo/Services/RecordTree.php index f68eeab6f1..3d0eb84126 100644 --- a/application/Espo/Services/RecordTree.php +++ b/application/Espo/Services/RecordTree.php @@ -46,6 +46,7 @@ use Espo\Core\{ use Espo\Core\Acl\Exceptions\NotImplemented; +use ArrayAccess; use stdClass; /** @@ -159,7 +160,10 @@ class RecordTree extends Record ->clone($selectBuilder->build()) ->find(); - if (!empty($params['onlyNotEmpty']) || $filterItems) { + if ( + (!empty($params['onlyNotEmpty']) || $filterItems) && + $collection instanceof ArrayAccess + ) { foreach ($collection as $i => $entity) { if ($this->checkItemIsEmpty($entity)) { unset($collection[$i]); diff --git a/application/Espo/Services/Settings.php b/application/Espo/Services/Settings.php index 6505acdbf4..889be0464c 100644 --- a/application/Espo/Services/Settings.php +++ b/application/Espo/Services/Settings.php @@ -222,6 +222,7 @@ class Settings { $entityTypeListParamList = $this->metadata->get(['app', 'config', 'entityTypeListParamList']) ?? []; + /** @var string[] */ $scopeList = array_keys($this->metadata->get(['entityDefs'], [])); foreach ($scopeList as $scope) { diff --git a/application/Espo/Services/Stream.php b/application/Espo/Services/Stream.php index b9d35b5128..a42edd616e 100644 --- a/application/Espo/Services/Stream.php +++ b/application/Espo/Services/Stream.php @@ -199,14 +199,18 @@ class Stream if (is_null($this->statusFields)) { $this->statusFields = []; + /** @var array> */ $scopes = $this->metadata->get('scopes', []); foreach ($scopes as $scope => $data) { - if (empty($data['statusField'])) { + /** @var ?string */ + $statusField = $data['statusField'] ?? null; + + if (!$statusField) { continue; } - $this->statusFields[$scope] = $data['statusField']; + $this->statusFields[$scope] = $statusField; } } @@ -1204,7 +1208,7 @@ class Stream $countBuilder = clone $builder; $builder - ->limit($params['offset'], $params['maxSize']) + ->limit($params['offset'] ?? 0, $params['maxSize']) ->order('number', 'DESC'); /** @var iterable */ @@ -1731,12 +1735,13 @@ class Stream return $this->auditedFieldsCache[$entityType]; } + /** @var array> */ $fields = $this->metadata->get('entityDefs.' . $entityType . '.fields'); $auditedFields = []; - foreach ($fields as $field => $d) { - if (empty($d['audited'])) { + foreach ($fields as $field => $defs) { + if (empty($defs['audited'])) { continue; } @@ -1744,6 +1749,13 @@ class Stream continue; } + /** @var ?string */ + $type = $defs['type'] ?? null; + + if (!$type) { + continue; + } + $auditedFields[$field] = []; $auditedFields[$field]['actualList'] = @@ -1752,7 +1764,7 @@ class Stream $auditedFields[$field]['notActualList'] = $this->fieldUtil->getNotActualAttributeList($entityType, $field); - $auditedFields[$field]['fieldType'] = $d['type']; + $auditedFields[$field]['fieldType'] = $type; } $this->auditedFieldsCache[$entityType] = $auditedFields; @@ -1953,6 +1965,7 @@ class Stream ]; foreach ($userList as $user) { + /** @var string */ $id = $user->getId(); $data['idList'][] = $id; @@ -2238,7 +2251,7 @@ class Stream if ($usersAttributeIsChanged || $forceProcessNoteNotifications) { if ($fieldDefs->getType() === 'linkMultiple') { - $userIdList = $entity->getLinkMultipleIdList($ownerUserField); + $userIdList = $entity->getLinkMultipleIdList($ownerUserField) ?? []; } else { $userId = $entity->get($ownerUserIdAttribute); @@ -2254,7 +2267,7 @@ class Stream } if ($teamsAttributeIsChanged || $forceProcessNoteNotifications) { - $teamIdList = $entity->getLinkMultipleIdList('teams'); + $teamIdList = $entity->getLinkMultipleIdList('teams') ?? []; } }