From 4546a4af512fb4df12de005ed2c2d97e6be5fbec Mon Sep 17 00:00:00 2001 From: Art4 Date: Mon, 24 Feb 2025 13:17:34 +0000 Subject: [PATCH 01/46] Run PHPStan with level 3 --- .phpstan.neon | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/.phpstan.neon b/.phpstan.neon index 8dfd10deae..bf01c3cc07 100644 --- a/.phpstan.neon +++ b/.phpstan.neon @@ -3,10 +3,10 @@ # SPDX-License-Identifier: CC0-1.0 parameters: - level: 2 + level: 3 paths: - - addon/ + # - addon/ - bin/auth_ejabberd.php - bin/console.php - bin/daemon.php @@ -47,26 +47,26 @@ parameters: message: '(^Parameter .+ has invalid type IMAP\\Connection\.$)' path: src - - + # - # Ignore missing SMTP class in PHPMailer 5.2.21 # see https://github.com/PHPMailer/PHPMailer/blob/v5.2.21/class.smtp.php - message: '(^.+ an unknown class SMTP\.$)' - path: addon/mailstream/phpmailer + # message: '(^.+ an unknown class SMTP\.$)' + # path: addon/mailstream/phpmailer - - + # - # Ignore missing SMTP class in PHPMailer 5.2.21 # see https://github.com/PHPMailer/PHPMailer/blob/v5.2.21/class.smtp.php - message: '(^Property .+ has unknown class SMTP as its type\.$)' - path: addon/mailstream/phpmailer + # message: '(^Property .+ has unknown class SMTP as its type\.$)' + # path: addon/mailstream/phpmailer - - + # - # Ignore missing SMTP class in PHPMailer 5.2.21 # see https://github.com/PHPMailer/PHPMailer/blob/v5.2.21/class.smtp.php - message: '(^Method .+ has invalid return type SMTP\.$)' - path: addon/mailstream/phpmailer + # message: '(^Method .+ has invalid return type SMTP\.$)' + # path: addon/mailstream/phpmailer - - + # - # Ignore missing SMTP class in PHPMailer 5.2.21 # see https://github.com/PHPMailer/PHPMailer/blob/v5.2.21/class.smtp.php - message: '(^Instantiated class SMTP not found\.$)' - path: addon/mailstream/phpmailer + # message: '(^Instantiated class SMTP not found\.$)' + # path: addon/mailstream/phpmailer From ca3d98b9f5047e650f5a025836df687c266fb3a7 Mon Sep 17 00:00:00 2001 From: Art4 Date: Mon, 24 Feb 2025 15:15:26 +0000 Subject: [PATCH 02/46] Fix 11 errors --- src/Util/HTTPSignature.php | 13 ++++++------- src/Util/JsonLD.php | 7 ++----- src/Util/ReversedFileReader.php | 5 +++-- src/Util/Strings.php | 4 ++-- src/Util/Temporal.php | 2 +- src/Util/XML.php | 2 +- 6 files changed, 15 insertions(+), 18 deletions(-) diff --git a/src/Util/HTTPSignature.php b/src/Util/HTTPSignature.php index bb5d8c6b5a..058d83d62a 100644 --- a/src/Util/HTTPSignature.php +++ b/src/Util/HTTPSignature.php @@ -7,6 +7,7 @@ namespace Friendica\Util; +use Exception; use Friendica\Core\Protocol; use Friendica\Database\Database; use Friendica\Database\DBA; @@ -213,7 +214,7 @@ class HTTPSignature $headers = []; foreach ($matches as $match) { - $headers[$match[1]] = trim($match[2] ?: $match[3], '"'); + $headers[$match[1]] = trim((string) $match[2], '"'); } // if the header is encrypted, decrypt with (default) site private key and continue @@ -537,14 +538,12 @@ class HTTPSignature if (!empty($uid)) { $owner = User::getOwnerDataById($uid); - if (!$owner) { - return; - } } else { $owner = User::getSystemAccount(); - if (!$owner) { - return; - } + } + + if (!$owner) { + throw new Exception('Could not find owner for uid ' . $uid); } if (!empty($owner['uprvkey'])) { diff --git a/src/Util/JsonLD.php b/src/Util/JsonLD.php index 3301ca1b40..afca8d79ba 100644 --- a/src/Util/JsonLD.php +++ b/src/Util/JsonLD.php @@ -243,14 +243,11 @@ class JsonLD return json_decode(json_encode($json, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE)); } + /** * Fetches an element array from a JSON array * - * @param $array - * @param $element - * @param $key - * - * @return array fetched element + * @return array|null fetched element or null */ public static function fetchElementArray($array, $element, $key = null, $type = null, $type_value = null) { diff --git a/src/Util/ReversedFileReader.php b/src/Util/ReversedFileReader.php index 779933cbc6..57800ab561 100644 --- a/src/Util/ReversedFileReader.php +++ b/src/Util/ReversedFileReader.php @@ -26,13 +26,13 @@ class ReversedFileReader implements \Iterator /** @var int */ private $pos = -1; - /** @var array */ + /** @var array|null */ private $buffer = null; /** @var int */ private $key = -1; - /** @var string */ + /** @var string|null */ private $value = null; /** @@ -53,6 +53,7 @@ class ReversedFileReader implements \Iterator $this->buffer = null; $this->key = -1; $this->value = null; + return $this; } diff --git a/src/Util/Strings.php b/src/Util/Strings.php index efa0994ec3..9dbf361761 100644 --- a/src/Util/Strings.php +++ b/src/Util/Strings.php @@ -209,7 +209,7 @@ class Strings { // If this method is called for an infinite (== unlimited) amount of bytes: if ($bytes == INF) { - return INF; + return 'INF'; } $units = ['B', 'KiB', 'MiB', 'GiB', 'TiB']; @@ -509,7 +509,7 @@ class Strings function ($matches) use ($blocks) { $return = $matches[0]; if (isset($blocks[intval($matches[1])])) { - $return = $blocks[$matches[1]]; + $return = $blocks[intval($matches[1])]; } return $return; }, diff --git a/src/Util/Temporal.php b/src/Util/Temporal.php index 3e9ea157d5..cc9baa53a9 100644 --- a/src/Util/Temporal.php +++ b/src/Util/Temporal.php @@ -405,7 +405,7 @@ class Temporal */ public static function getDaysInMonth(int $y, int $m): int { - return date('t', mktime(0, 0, 0, $m, 1, $y)); + return (int) date('t', mktime(0, 0, 0, $m, 1, $y)); } /** diff --git a/src/Util/XML.php b/src/Util/XML.php index cf5689c361..4c099fb78e 100644 --- a/src/Util/XML.php +++ b/src/Util/XML.php @@ -184,7 +184,7 @@ class XML * @param integer $recursion_depth recursion counter for internal use - default 0 * internal use, recursion counter * - * @return array | string The array from the xml element or the string + * @return array|string|null The array from the xml element or the string */ public static function elementToArray($xml_element, int &$recursion_depth = 0) { From f6d5cd039e70f6368a8da32416056e9996b8607c Mon Sep 17 00:00:00 2001 From: Art4 Date: Tue, 25 Feb 2025 07:48:38 +0000 Subject: [PATCH 03/46] Fix 2 PHPStan errors --- src/User/Settings/Repository/UserGServer.php | 46 ++++++++------------ src/Util/Crypto.php | 5 +-- src/Util/HTTPSignature.php | 2 +- 3 files changed, 20 insertions(+), 33 deletions(-) diff --git a/src/User/Settings/Repository/UserGServer.php b/src/User/Settings/Repository/UserGServer.php index dd097c7af2..016f2ea70d 100644 --- a/src/User/Settings/Repository/UserGServer.php +++ b/src/User/Settings/Repository/UserGServer.php @@ -8,28 +8,27 @@ namespace Friendica\User\Settings\Repository; use Exception; -use Friendica\BaseCollection; -use Friendica\BaseEntity; +use Friendica\BaseRepository; use Friendica\Content\Pager; use Friendica\Database\Database; use Friendica\Federation\Repository\GServer; use Friendica\Network\HTTPException\InternalServerErrorException; use Friendica\Network\HTTPException\NotFoundException; -use Friendica\User\Settings\Collection; -use Friendica\User\Settings\Entity; -use Friendica\User\Settings\Factory; +use Friendica\User\Settings\Collection\UserGServers as UserGServersCollection; +use Friendica\User\Settings\Entity\UserGServer as UserGServerEntity; +use Friendica\User\Settings\Factory\UserGServer as UserGServerFactory; use Psr\Log\LoggerInterface; -class UserGServer extends \Friendica\BaseRepository +class UserGServer extends BaseRepository { protected static $table_name = 'user-gserver'; - /** @var Factory\UserGServer */ + /** @var UserGServerFactory */ protected $factory; /** @var GServer */ protected $gserverRepository; - public function __construct(GServer $gserverRepository, Database $database, LoggerInterface $logger, Factory\UserGServer $factory) + public function __construct(GServer $gserverRepository, Database $database, LoggerInterface $logger, UserGServerFactory $factory) { parent::__construct($database, $logger, $factory); @@ -39,12 +38,9 @@ class UserGServer extends \Friendica\BaseRepository /** * Returns an existing UserGServer entity or create one on the fly * - * @param int $uid - * @param int $gsid * @param bool $hydrate Populate the related GServer entity - * @return Entity\UserGServer */ - public function getOneByUserAndServer(int $uid, int $gsid, bool $hydrate = true): Entity\UserGServer + public function getOneByUserAndServer(int $uid, int $gsid, bool $hydrate = true): UserGServerEntity { try { return $this->selectOneByUserAndServer($uid, $gsid, $hydrate); @@ -54,18 +50,15 @@ class UserGServer extends \Friendica\BaseRepository } /** - * @param int $uid - * @param int $gsid * @param bool $hydrate Populate the related GServer entity - * @return Entity\UserGServer * @throws NotFoundException */ - public function selectOneByUserAndServer(int $uid, int $gsid, bool $hydrate = true): Entity\UserGServer + public function selectOneByUserAndServer(int $uid, int $gsid, bool $hydrate = true): UserGServerEntity { return $this->_selectOne(['uid' => $uid, 'gsid' => $gsid], [], $hydrate); } - public function save(Entity\UserGServer $userGServer): Entity\UserGServer + public function save(UserGServerEntity $userGServer): UserGServerEntity { $fields = [ 'uid' => $userGServer->uid, @@ -78,7 +71,7 @@ class UserGServer extends \Friendica\BaseRepository return $userGServer; } - public function selectByUserWithPagination(int $uid, Pager $pager): Collection\UserGServers + public function selectByUserWithPagination(int $uid, Pager $pager): UserGServersCollection { return $this->_select(['uid' => $uid], ['limit' => [$pager->getStart(), $pager->getItemsPerPage()]]); } @@ -94,20 +87,18 @@ class UserGServer extends \Friendica\BaseRepository } /** - * @param Entity\UserGServer $userGServer - * @return bool * @throws InternalServerErrorException in case the underlying storage cannot delete the record */ - public function delete(Entity\UserGServer $userGServer): bool + public function delete(UserGServerEntity $userGServer): bool { try { return $this->db->delete(self::$table_name, ['uid' => $userGServer->uid, 'gsid' => $userGServer->gsid]); - } catch (\Exception $exception) { + } catch (Exception $exception) { throw new InternalServerErrorException('Cannot delete the UserGServer', $exception); } } - protected function _selectOne(array $condition, array $params = [], bool $hydrate = true): BaseEntity + protected function _selectOne(array $condition, array $params = [], bool $hydrate = true): UserGServerEntity { $fields = $this->db->selectFirst(static::$table_name, [], $condition, $params); if (!$this->db->isResult($fields)) { @@ -118,16 +109,13 @@ class UserGServer extends \Friendica\BaseRepository } /** - * @param array $condition - * @param array $params - * @return Collection\UserGServers * @throws Exception */ - protected function _select(array $condition, array $params = [], bool $hydrate = true): BaseCollection + protected function _select(array $condition, array $params = [], bool $hydrate = true): UserGServersCollection { $rows = $this->db->selectToArray(static::$table_name, [], $condition, $params); - $Entities = new Collection\UserGServers(); + $Entities = new UserGServersCollection(); foreach ($rows as $fields) { $Entities[] = $this->factory->createFromTableRow($fields, $hydrate ? $this->gserverRepository->selectOneById($fields['gsid']) : null); } @@ -135,7 +123,7 @@ class UserGServer extends \Friendica\BaseRepository return $Entities; } - public function listIgnoredByUser(int $uid): Collection\UserGServers + public function listIgnoredByUser(int $uid): UserGServersCollection { return $this->_select(['uid' => $uid, 'ignored' => 1], [], false); } diff --git a/src/Util/Crypto.php b/src/Util/Crypto.php index 084ae567ea..084bd21808 100644 --- a/src/Util/Crypto.php +++ b/src/Util/Crypto.php @@ -225,19 +225,18 @@ class Crypto } /** - * * Ported from Hubzilla: https://framagit.org/hubzilla/core/blob/master/include/crypto.php * * @param array $data ['iv' => $iv, 'key' => $key, 'alg' => $alg, 'data' => $data] * @param string $prvkey The private key used for decryption. * - * @return string|boolean The decrypted string or false on failure. + * @return string|false The decrypted string or false on failure. * @throws \Exception */ public static function unencapsulate(array $data, $prvkey) { if (!$data) { - return; + return false; } $alg = $data['alg'] ?? 'aes256cbc'; diff --git a/src/Util/HTTPSignature.php b/src/Util/HTTPSignature.php index 058d83d62a..a779a59a86 100644 --- a/src/Util/HTTPSignature.php +++ b/src/Util/HTTPSignature.php @@ -248,7 +248,7 @@ class HTTPSignature private static function decryptSigheader(array $headers, string $prvkey): string { if (!empty($headers['iv']) && !empty($headers['key']) && !empty($headers['data'])) { - return Crypto::unencapsulate($headers, $prvkey); + return (string) Crypto::unencapsulate($headers, $prvkey); } return ''; From 83f64b49312051030f1ae50f78916d26fa1dc9af Mon Sep 17 00:00:00 2001 From: Art4 Date: Tue, 25 Feb 2025 07:59:39 +0000 Subject: [PATCH 04/46] Fix PHPStan error in Security class --- src/Security/Security.php | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/src/Security/Security.php b/src/Security/Security.php index 6b0deb75ec..9056596f27 100644 --- a/src/Security/Security.php +++ b/src/Security/Security.php @@ -45,25 +45,25 @@ class Security return true; } elseif ($verified === 1) { return false; + } + + $user = User::getById($owner); + if (!$user || $user['blockwall']) { + $verified = 1; + return false; + } + + $contact = Contact::getById($cid); + if (!is_array($contact) || $contact['blocked'] || $contact['readonly'] || $contact['pending']) { + $verified = 1; + return false; + } + + if (in_array($contact['rel'], [Contact::SHARING, Contact::FRIEND]) || ($user['page-flags'] == User::PAGE_FLAGS_COMMUNITY)) { + $verified = 2; + return true; } else { - $user = User::getById($owner); - if (!$user || $user['blockwall']) { - $verified = 1; - return false; - } - - $contact = Contact::getById($cid); - if ($contact || $contact['blocked'] || $contact['readonly'] || $contact['pending']) { - $verified = 1; - return false; - } - - if (in_array($contact['rel'], [Contact::SHARING, Contact::FRIEND]) || ($user['page-flags'] == User::PAGE_FLAGS_COMMUNITY)) { - $verified = 2; - return true; - } else { - $verified = 1; - } + $verified = 1; } } From 2254bee74d071e9c0717e219ab2cf3faa8efbca2 Mon Sep 17 00:00:00 2001 From: Art4 Date: Tue, 25 Feb 2025 08:30:27 +0000 Subject: [PATCH 05/46] Refactory PermissionSet Repository, add BaseRepository::_selectFirstRowAsArray() --- src/BaseRepository.php | 19 ++++++ .../Repository/PermissionSet.php | 59 ++++++------------- 2 files changed, 38 insertions(+), 40 deletions(-) diff --git a/src/BaseRepository.php b/src/BaseRepository.php index 068a9f4b63..afbb688bd9 100644 --- a/src/BaseRepository.php +++ b/src/BaseRepository.php @@ -129,6 +129,24 @@ abstract class BaseRepository return $Entities; } + /** + * Selects the fields of the first row as array + * + * @throws NotFoundException + * + * @return array The resulted fields as array + */ + protected function _selectFirstRowAsArray(array $condition, array $params = []): array + { + $fields = $this->db->selectFirst(static::$table_name, [], $condition, $params); + + if (!$this->db->isResult($fields)) { + throw new NotFoundException(); + } + + return $fields; + } + /** * @param array $condition * @param array $params @@ -138,6 +156,7 @@ abstract class BaseRepository protected function _selectOne(array $condition, array $params = []): BaseEntity { $fields = $this->db->selectFirst(static::$table_name, [], $condition, $params); + if (!$this->db->isResult($fields)) { throw new NotFoundException(); } diff --git a/src/Security/PermissionSet/Repository/PermissionSet.php b/src/Security/PermissionSet/Repository/PermissionSet.php index ec3e2745ec..c77baf0f2e 100644 --- a/src/Security/PermissionSet/Repository/PermissionSet.php +++ b/src/Security/PermissionSet/Repository/PermissionSet.php @@ -15,9 +15,9 @@ use Friendica\Model\Circle; use Friendica\Network\HTTPException\NotFoundException; use Friendica\Security\PermissionSet\Exception\PermissionSetNotFoundException; use Friendica\Security\PermissionSet\Exception\PermissionSetPersistenceException; -use Friendica\Security\PermissionSet\Factory; -use Friendica\Security\PermissionSet\Collection; -use Friendica\Security\PermissionSet\Entity; +use Friendica\Security\PermissionSet\Factory\PermissionSet as PermissionSetFactory; +use Friendica\Security\PermissionSet\Collection\PermissionSets as PermissionSetsCollection; +use Friendica\Security\PermissionSet\Entity\PermissionSet as PermissionSetEntity; use Friendica\Util\ACLFormatter; use Psr\Log\LoggerInterface; @@ -26,7 +26,7 @@ class PermissionSet extends BaseRepository /** @var int Virtual permission set id for public permission */ const PUBLIC = 0; - /** @var Factory\PermissionSet */ + /** @var PermissionSetFactory */ protected $factory; protected static $table_name = 'permissionset'; @@ -34,7 +34,7 @@ class PermissionSet extends BaseRepository /** @var ACLFormatter */ private $aclFormatter; - public function __construct(Database $database, LoggerInterface $logger, Factory\PermissionSet $factory, ACLFormatter $aclFormatter) + public function __construct(Database $database, LoggerInterface $logger, PermissionSetFactory $factory, ACLFormatter $aclFormatter) { parent::__construct($database, $logger, $factory); @@ -42,34 +42,28 @@ class PermissionSet extends BaseRepository } /** - * @param array $condition - * @param array $params - * - * @return Entity\PermissionSet * @throws NotFoundException * @throws Exception */ - private function selectOne(array $condition, array $params = []): Entity\PermissionSet + private function selectOne(array $condition, array $params = []): PermissionSetEntity { - return parent::_selectOne($condition, $params); + $fields = parent::_selectFirstRowAsArray($condition, $params); + + return $this->factory->createFromTableRow($fields); } /** * @throws Exception */ - private function select(array $condition, array $params = []): Collection\PermissionSets + private function select(array $condition, array $params = []): PermissionSetsCollection { - return new Collection\PermissionSets(parent::_select($condition, $params)->getArrayCopy()); + return new PermissionSetsCollection(parent::_select($condition, $params)->getArrayCopy()); } /** * Converts a given PermissionSet into a DB compatible row array - * - * @param Entity\PermissionSet $permissionSet - * - * @return array */ - protected function convertToTableRow(Entity\PermissionSet $permissionSet): array + protected function convertToTableRow(PermissionSetEntity $permissionSet): array { return [ 'uid' => $permissionSet->uid, @@ -83,12 +77,11 @@ class PermissionSet extends BaseRepository /** * @param int $id A PermissionSet table row id or self::PUBLIC * @param int $uid The owner of the PermissionSet - * @return Entity\PermissionSet * * @throws PermissionSetNotFoundException * @throws PermissionSetPersistenceException */ - public function selectOneById(int $id, int $uid): Entity\PermissionSet + public function selectOneById(int $id, int $uid): PermissionSetEntity { if ($id === self::PUBLIC) { return $this->factory->createFromString($uid); @@ -109,11 +102,9 @@ class PermissionSet extends BaseRepository * @param int $cid Contact id of the visitor * @param int $uid User id whom the items belong, used for ownership check. * - * @return Collection\PermissionSets - * * @throws PermissionSetPersistenceException */ - public function selectByContactId(int $cid, int $uid): Collection\PermissionSets + public function selectByContactId(int $cid, int $uid): PermissionSetsCollection { try { $cdata = Contact::getPublicAndUserContactID($cid, $uid); @@ -162,16 +153,14 @@ class PermissionSet extends BaseRepository * * @param int $uid * - * @return Entity\PermissionSet - * * @throws PermissionSetPersistenceException */ - public function selectDefaultForUser(int $uid): Entity\PermissionSet + public function selectDefaultForUser(int $uid): PermissionSetEntity { try { $self_contact = Contact::selectFirst(['id'], ['uid' => $uid, 'self' => true]); } catch (Exception $exception) { - throw new PermissionSetPersistenceException(sprintf('Cannot select Contact for user %d', $uid)); + throw new PermissionSetPersistenceException(sprintf('Cannot select Contact for user %d', $uid), $exception); } if (!$this->db->isResult($self_contact)) { @@ -188,10 +177,8 @@ class PermissionSet extends BaseRepository * Fetch the public PermissionSet * * @param int $uid - * - * @return Entity\PermissionSet */ - public function selectPublicForUser(int $uid): Entity\PermissionSet + public function selectPublicForUser(int $uid): PermissionSetEntity { return $this->factory->createFromString($uid, '', '', '', '', self::PUBLIC); } @@ -199,13 +186,9 @@ class PermissionSet extends BaseRepository /** * Selects or creates a PermissionSet based on its fields * - * @param Entity\PermissionSet $permissionSet - * - * @return Entity\PermissionSet - * * @throws PermissionSetPersistenceException */ - public function selectOrCreate(Entity\PermissionSet $permissionSet): Entity\PermissionSet + public function selectOrCreate(PermissionSetEntity $permissionSet): PermissionSetEntity { if ($permissionSet->id) { return $permissionSet; @@ -226,13 +209,9 @@ class PermissionSet extends BaseRepository } /** - * @param Entity\PermissionSet $permissionSet - * - * @return Entity\PermissionSet - * * @throws PermissionSetPersistenceException */ - public function save(Entity\PermissionSet $permissionSet): Entity\PermissionSet + public function save(PermissionSetEntity $permissionSet): PermissionSetEntity { // Don't save/update the common public PermissionSet if ($permissionSet->isPublic()) { From 16cbaf890a6d3c7e6365cc423a8fbd6c08fa141f Mon Sep 17 00:00:00 2001 From: Art4 Date: Tue, 25 Feb 2025 08:39:31 +0000 Subject: [PATCH 06/46] Deprecate BaseRepository::_selectOne() --- src/BaseRepository.php | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/src/BaseRepository.php b/src/BaseRepository.php index afbb688bd9..ead4bf73bf 100644 --- a/src/BaseRepository.php +++ b/src/BaseRepository.php @@ -148,18 +148,13 @@ abstract class BaseRepository } /** - * @param array $condition - * @param array $params - * @return BaseEntity + * @deprecated 2025.05 Use `\Friendica\BaseRepository::_selectFirstRowAsArray()` instead + * * @throws NotFoundException */ protected function _selectOne(array $condition, array $params = []): BaseEntity { - $fields = $this->db->selectFirst(static::$table_name, [], $condition, $params); - - if (!$this->db->isResult($fields)) { - throw new NotFoundException(); - } + $fields = $this->_selectFirstRowAsArray( $condition, $params); return $this->factory->createFromTableRow($fields); } From 459ad05137c68dddbd10e7610709a9cbbc02e644 Mon Sep 17 00:00:00 2001 From: Art4 Date: Tue, 25 Feb 2025 09:26:08 +0000 Subject: [PATCH 07/46] Refactor DisporaContact Repository, fix PHPStan error --- .../Diaspora/Repository/DiasporaContact.php | 87 +++++++++---------- 1 file changed, 40 insertions(+), 47 deletions(-) diff --git a/src/Protocol/Diaspora/Repository/DiasporaContact.php b/src/Protocol/Diaspora/Repository/DiasporaContact.php index b680fedea1..6d92b066f8 100644 --- a/src/Protocol/Diaspora/Repository/DiasporaContact.php +++ b/src/Protocol/Diaspora/Repository/DiasporaContact.php @@ -7,6 +7,9 @@ namespace Friendica\Protocol\Diaspora\Repository; +use DateTime; +use DateTimeZone; +use Exception; use Friendica\BaseRepository; use Friendica\Database\Database; use Friendica\Database\Definition\DbaDefinition; @@ -14,11 +17,12 @@ use Friendica\Model\APContact; use Friendica\Model\Contact; use Friendica\Model\Item; use Friendica\Model\ItemURI; -use Friendica\Network\HTTPException; -use Friendica\Protocol\Diaspora\Entity; -use Friendica\Protocol\Diaspora\Factory; +use Friendica\Network\HTTPException\NotFoundException; +use Friendica\Protocol\Diaspora\Entity\DiasporaContact as DiasporaContactEntity; +use Friendica\Protocol\Diaspora\Factory\DiasporaContact as DiasporaContactFactory; use Friendica\Protocol\WebFingerUri; use Friendica\Util\DateTimeFormat; +use InvalidArgumentException; use Psr\Http\Message\UriInterface; use Psr\Log\LoggerInterface; @@ -30,12 +34,12 @@ class DiasporaContact extends BaseRepository protected static $table_name = 'diaspora-contact-view'; - /** @var Factory\DiasporaContact */ + /** @var DiasporaContactFactory */ protected $factory; /** @var DbaDefinition */ private $definition; - public function __construct(DbaDefinition $definition, Database $database, LoggerInterface $logger, Factory\DiasporaContact $factory) + public function __construct(DbaDefinition $definition, Database $database, LoggerInterface $logger, DiasporaContactFactory $factory) { parent::__construct($database, $logger, $factory); @@ -43,67 +47,58 @@ class DiasporaContact extends BaseRepository } /** - * @param array $condition - * @param array $params - * @return Entity\DiasporaContact - * @throws HTTPException\NotFoundException + * @throws NotFoundException */ - public function selectOne(array $condition, array $params = []): Entity\DiasporaContact + public function selectOne(array $condition, array $params = []): DiasporaContactEntity { - return parent::_selectOne($condition, $params); + $fields = $this->_selectFirstRowAsArray( $condition, $params); + + return $this->factory->createFromTableRow($fields); } /** - * @param int $uriId - * @return Entity\DiasporaContact - * @throws HTTPException\NotFoundException + * @throws NotFoundException */ - public function selectOneByUriId(int $uriId): Entity\DiasporaContact + public function selectOneByUriId(int $uriId): DiasporaContactEntity { return $this->selectOne(['uri-id' => $uriId]); } /** - * @param UriInterface $uri - * @return Entity\DiasporaContact - * @throws HTTPException\NotFoundException + * @throws NotFoundException */ - public function selectOneByUri(UriInterface $uri): Entity\DiasporaContact + public function selectOneByUri(UriInterface $uri): DiasporaContactEntity { try { return $this->selectOne(['url' => (string) $uri]); - } catch (HTTPException\NotFoundException $e) { + } catch (NotFoundException $e) { } try { return $this->selectOne(['addr' => (string) $uri]); - } catch (HTTPException\NotFoundException $e) { + } catch (NotFoundException $e) { } return $this->selectOne(['alias' => (string) $uri]); } /** - * @param WebFingerUri $uri - * @return Entity\DiasporaContact - * @throws HTTPException\NotFoundException + * @throws NotFoundException */ - public function selectOneByAddr(WebFingerUri $uri): Entity\DiasporaContact + public function selectOneByAddr(WebFingerUri $uri): DiasporaContactEntity { return $this->selectOne(['addr' => $uri->getAddr()]); } /** - * @param int $uriId - * @return bool - * @throws \Exception + * @throws Exception */ public function existsByUriId(int $uriId): bool { return $this->db->exists(self::$table_name, ['uri-id' => $uriId]); } - public function save(Entity\DiasporaContact $DiasporaContact): Entity\DiasporaContact + public function save(DiasporaContactEntity $DiasporaContact): DiasporaContactEntity { $uriId = $DiasporaContact->uriId ?? ItemURI::insert(['uri' => $DiasporaContact->url, 'guid' => $DiasporaContact->guid]); @@ -145,10 +140,9 @@ class DiasporaContact extends BaseRepository * * @param WebFingerUri $uri Profile address * @param boolean $update true = always update, false = never update, null = update when not found or outdated - * @return Entity\DiasporaContact - * @throws HTTPException\NotFoundException + * @throws NotFoundException */ - public function getByAddr(WebFingerUri $uri, ?bool $update = self::UPDATE_IF_MISSING_OR_OUTDATED): Entity\DiasporaContact + public function getByAddr(WebFingerUri $uri, ?bool $update = self::UPDATE_IF_MISSING_OR_OUTDATED): DiasporaContactEntity { if ($update !== self::ALWAYS_UPDATE) { try { @@ -156,7 +150,7 @@ class DiasporaContact extends BaseRepository if ($update === self::NEVER_UPDATE) { return $dcontact; } - } catch (HTTPException\NotFoundException $e) { + } catch (NotFoundException $e) { if ($update === self::NEVER_UPDATE) { throw $e; } @@ -169,7 +163,7 @@ class DiasporaContact extends BaseRepository $contact = Contact::getByURL($uri, $update, ['uri-id']); if (empty($contact['uri-id'])) { - throw new HTTPException\NotFoundException('Diaspora profile with URI ' . $uri . ' not found'); + throw new NotFoundException('Diaspora profile with URI ' . $uri . ' not found'); } return self::selectOneByUriId($contact['uri-id']); @@ -180,10 +174,9 @@ class DiasporaContact extends BaseRepository * * @param UriInterface $uri Profile URL * @param boolean $update true = always update, false = never update, null = update when not found or outdated - * @return Entity\DiasporaContact - * @throws HTTPException\NotFoundException + * @throws NotFoundException */ - public function getByUrl(UriInterface $uri, ?bool $update = self::UPDATE_IF_MISSING_OR_OUTDATED): Entity\DiasporaContact + public function getByUrl(UriInterface $uri, ?bool $update = self::UPDATE_IF_MISSING_OR_OUTDATED): DiasporaContactEntity { if ($update !== self::ALWAYS_UPDATE) { try { @@ -191,7 +184,7 @@ class DiasporaContact extends BaseRepository if ($update === self::NEVER_UPDATE) { return $dcontact; } - } catch (HTTPException\NotFoundException $e) { + } catch (NotFoundException $e) { if ($update === self::NEVER_UPDATE) { throw $e; } @@ -204,7 +197,7 @@ class DiasporaContact extends BaseRepository $contact = Contact::getByURL($uri, $update, ['uri-id']); if (empty($contact['uri-id'])) { - throw new HTTPException\NotFoundException('Diaspora profile with URI ' . $uri . ' not found'); + throw new NotFoundException('Diaspora profile with URI ' . $uri . ' not found'); } return self::selectOneByUriId($contact['uri-id']); @@ -214,27 +207,27 @@ class DiasporaContact extends BaseRepository * Update or create a diaspora-contact entry via a probe array * * @param array $data Probe array - * @return Entity\DiasporaContact - * @throws \Exception + * @throws Exception */ - public function updateFromProbeArray(array $data): Entity\DiasporaContact + public function updateFromProbeArray(array $data): DiasporaContactEntity { if (empty($data['url'])) { - throw new \InvalidArgumentException('Missing url key in Diaspora probe data array'); + throw new InvalidArgumentException('Missing url key in Diaspora probe data array'); } if (empty($data['guid'])) { - throw new \InvalidArgumentException('Missing guid key in Diaspora probe data array'); + throw new InvalidArgumentException('Missing guid key in Diaspora probe data array'); } if (empty($data['pubkey'])) { - throw new \InvalidArgumentException('Missing pubkey key in Diaspora probe data array'); + throw new InvalidArgumentException('Missing pubkey key in Diaspora probe data array'); } $uriId = ItemURI::insert(['uri' => $data['url'], 'guid' => $data['guid']]); $contact = Contact::getByUriId($uriId, ['id', 'created']); $apcontact = APContact::getByURL($data['url'], false); + if (!empty($apcontact)) { $interacting_count = $apcontact['followers_count']; $interacted_count = $apcontact['following_count']; @@ -250,7 +243,7 @@ class DiasporaContact extends BaseRepository $DiasporaContact = $this->factory->createfromProbeData( $data, $uriId, - new \DateTime($contact['created'] ?? 'now', new \DateTimeZone('UTC')), + new DateTime($contact['created'] ?? 'now', new DateTimeZone('UTC')), $interacting_count ?? 0, $interacted_count ?? 0, $post_count ?? 0 @@ -269,7 +262,7 @@ class DiasporaContact extends BaseRepository * @param string $guid Hexadecimal string guid * * @return string the contact url or null - * @throws \Exception + * @throws Exception */ public function getUrlByGuid(string $guid): ?string { From c1653877fb4d4c9ca44d5cd47830960b8f5b0572 Mon Sep 17 00:00:00 2001 From: Art4 Date: Tue, 25 Feb 2025 11:36:32 +0000 Subject: [PATCH 08/46] fix 17 PHPStan errors --- src/Protocol/ATProtocol/Processor.php | 6 +- src/Protocol/ActivityPub/Receiver.php | 2 +- src/Protocol/DFRN.php | 108 +++++++++++++------------- src/Protocol/Diaspora.php | 8 +- 4 files changed, 62 insertions(+), 62 deletions(-) diff --git a/src/Protocol/ATProtocol/Processor.php b/src/Protocol/ATProtocol/Processor.php index f551f6a273..3a21ff3dd4 100755 --- a/src/Protocol/ATProtocol/Processor.php +++ b/src/Protocol/ATProtocol/Processor.php @@ -279,7 +279,7 @@ class Processor $uri = $this->getUri($post); if ($uri_id = $this->fetchUriId($uri, $uid)) { - return $uri_id; + return (int) $uri_id; } if (empty($post->record)) { @@ -322,7 +322,7 @@ class Processor $this->logger->warning('Fetched post was not inserted', ['guid' => $item['guid'], 'uri' => $item['uri']]); } - return $this->fetchUriId($uri, $uid); + return (int) $this->fetchUriId($uri, $uid); } private function getHeaderFromJetstream(stdClass $data, int $uid, int $protocol = Conversation::PARCEL_JETSTREAM): array @@ -860,7 +860,7 @@ class Processor $this->logger->debug('Post with extid exists', ['uri' => $uri]); return $reply['uri-id']; } - return 0; + return '0'; } private function getPostUids(string $uri, bool $with_public_user): array diff --git a/src/Protocol/ActivityPub/Receiver.php b/src/Protocol/ActivityPub/Receiver.php index 34732022b5..76f4d31d3d 100644 --- a/src/Protocol/ActivityPub/Receiver.php +++ b/src/Protocol/ActivityPub/Receiver.php @@ -250,7 +250,7 @@ class Receiver * @param string $object_id Object ID of the provided object * @param integer $uid User ID * - * @return string with object type or NULL + * @return string|null string with object type or NULL * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \ImagickException */ diff --git a/src/Protocol/DFRN.php b/src/Protocol/DFRN.php index be6dfc206d..56cafc1a97 100644 --- a/src/Protocol/DFRN.php +++ b/src/Protocol/DFRN.php @@ -607,64 +607,64 @@ class DFRN * @param string $element Element name for the activity * @param string $activity activity value * @param int $uriid Uri-Id of the post - * @return DOMElement XML activity object + * @return DOMElement|false XML activity object or false on error * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @todo Find proper type-hints */ private static function createActivity(DOMDocument $doc, string $element, string $activity, int $uriid) { - if ($activity) { - $entry = $doc->createElement($element); - - $r = XML::parseString($activity); - if (!$r) { - return false; - } - - if ($r->type) { - XML::addElement($doc, $entry, "activity:object-type", $r->type); - } - - if ($r->id) { - XML::addElement($doc, $entry, "id", $r->id); - } - - if ($r->title) { - XML::addElement($doc, $entry, "title", $r->title); - } - - if ($r->link) { - if (substr($r->link, 0, 1) == '<') { - if (strstr($r->link, '&') && (! strstr($r->link, '&'))) { - $r->link = str_replace('&', '&', $r->link); - } - - $r->link = preg_replace('/\/', '', $r->link); - - // XML does need a single element as root element so we add a dummy element here - $data = XML::parseString("" . $r->link . ""); - if (is_object($data)) { - foreach ($data->link as $link) { - $attributes = []; - foreach ($link->attributes() as $parameter => $value) { - $attributes[$parameter] = $value; - } - XML::addElement($doc, $entry, "link", "", $attributes); - } - } - } else { - $attributes = ["rel" => "alternate", "type" => "text/html", "href" => $r->link]; - XML::addElement($doc, $entry, "link", "", $attributes); - } - } - if ($r->content) { - XML::addElement($doc, $entry, "content", BBCode::convertForUriId($uriid, $r->content, BBCode::EXTERNAL), ["type" => "html"]); - } - - return $entry; + if (!$activity) { + return false; } - return false; + $entry = $doc->createElement($element); + + $r = XML::parseString($activity); + if (!$r) { + return false; + } + + if ($r->type) { + XML::addElement($doc, $entry, "activity:object-type", $r->type); + } + + if ($r->id) { + XML::addElement($doc, $entry, "id", $r->id); + } + + if ($r->title) { + XML::addElement($doc, $entry, "title", $r->title); + } + + if ($r->link) { + if (substr($r->link, 0, 1) == '<') { + if (strstr($r->link, '&') && (! strstr($r->link, '&'))) { + $r->link = str_replace('&', '&', $r->link); + } + + $r->link = preg_replace('/\/', '', $r->link); + + // XML does need a single element as root element so we add a dummy element here + $data = XML::parseString("" . $r->link . ""); + if (is_object($data)) { + foreach ($data->link as $link) { + $attributes = []; + foreach ($link->attributes() as $parameter => $value) { + $attributes[$parameter] = $value; + } + XML::addElement($doc, $entry, "link", "", $attributes); + } + } + } else { + $attributes = ["rel" => "alternate", "type" => "text/html", "href" => $r->link]; + XML::addElement($doc, $entry, "link", "", $attributes); + } + } + if ($r->content) { + XML::addElement($doc, $entry, "content", BBCode::convertForUriId($uriid, $r->content, BBCode::EXTERNAL), ["type" => "html"]); + } + + return $entry; } /** @@ -1925,7 +1925,7 @@ class DFRN // Check if the message is wanted if (!self::isSolicitedMessage($item, $importer)) { DBA::delete('item-uri', ['uri' => $item['uri']]); - return 403; + return; } // Get the type of the item (Top level post, reply or remote reply) @@ -2051,7 +2051,7 @@ class DFRN Item::distribute($posted_id); } - return true; + return; } } else { // $entrytype == self::TOP_LEVEL if (($item['uid'] != 0) && !Contact::isSharing($item['owner-id'], $item['uid']) && !Contact::isSharing($item['author-id'], $item['uid'])) { @@ -2099,7 +2099,7 @@ class DFRN } if (!$uri || !$importer['id']) { - return false; + return; } $condition = ['uri' => $uri, 'uid' => $importer['importer_uid']]; diff --git a/src/Protocol/Diaspora.php b/src/Protocol/Diaspora.php index a8db02f045..0166e65f9d 100644 --- a/src/Protocol/Diaspora.php +++ b/src/Protocol/Diaspora.php @@ -337,7 +337,7 @@ class Diaspora * @param string $xml urldecoded Diaspora salmon * @param string $privKey The private key of the importer * - * @return array + * @return array|false array with decoded data or false on error * 'message' -> decoded Diaspora XML message * 'author' -> author diaspora handle * 'key' -> author public key (converted to pkcs#8) @@ -1051,7 +1051,7 @@ class Diaspora * @param string $server The url of the server * @param int $level Endless loop prevention * - * @return array + * @return array|false The message as array or false on error * 'message' => The message XML * 'author' => The author handle * 'key' => The public key of the author @@ -2795,7 +2795,7 @@ class Diaspora // without a public key nothing will work if (!$pubkey) { DI::logger()->notice('pubkey missing: contact id: ' . $contact['id']); - return false; + return ''; } $aes_key = random_bytes(32); @@ -2809,7 +2809,7 @@ class Diaspora $encrypted_key_bundle = ''; if (!@openssl_public_encrypt($json, $encrypted_key_bundle, $pubkey)) { - return false; + return ''; } $json_object = json_encode( From cea8cf1f6c5aaea5b99eae799719930f28ab409d Mon Sep 17 00:00:00 2001 From: Art4 Date: Tue, 25 Feb 2025 13:51:13 +0000 Subject: [PATCH 09/46] Fix 27 PHPStan errors --- .../Notifications/Entity/Notify.php | 3 ++- src/Object/Api/Mastodon/Status.php | 18 ++++++------- src/Object/Api/Twitter/DirectMessage.php | 4 +-- src/Object/Api/Twitter/Media.php | 2 +- src/Object/Api/Twitter/Mention.php | 3 +-- src/Object/Api/Twitter/Status.php | 10 ++++---- src/Object/Log/ParsedLogLine.php | 2 +- src/Object/Post.php | 4 +-- src/Object/Thread.php | 3 +-- .../ProfileField/Collection/ProfileFields.php | 25 ++++++++----------- 10 files changed, 34 insertions(+), 40 deletions(-) diff --git a/src/Navigation/Notifications/Entity/Notify.php b/src/Navigation/Notifications/Entity/Notify.php index 3ff478633e..297ecbdd98 100644 --- a/src/Navigation/Notifications/Entity/Notify.php +++ b/src/Navigation/Notifications/Entity/Notify.php @@ -33,7 +33,8 @@ use Psr\Http\Message\UriInterface; * @property-read int|null $parentUriId * @property-read int|null $id * - * @deprecated since 2022.05 Use \Friendica\Navigation\Notifications\Entity\Notification instead + * @deprecated 2022.05 Use \Friendica\Navigation\Notifications\Entity\Notification instead + * @see \Friendica\Navigation\Notifications\Entity\Notification */ class Notify extends BaseEntity { diff --git a/src/Object/Api/Mastodon/Status.php b/src/Object/Api/Mastodon/Status.php index 0e487a989c..474db28dc0 100644 --- a/src/Object/Api/Mastodon/Status.php +++ b/src/Object/Api/Mastodon/Status.php @@ -30,7 +30,7 @@ class Status extends BaseDataTransferObject protected $edited_at; /** @var string|null */ protected $in_reply_to_id = null; - /** @var Status|null - Fedilab extension, see issue https://github.com/friendica/friendica/issues/12672 */ + /** @var Status[]|null - Fedilab extension, see issue https://github.com/friendica/friendica/issues/12672 */ protected $in_reply_to_status = null; /** @var string|null */ protected $in_reply_to_account_id = null; @@ -64,25 +64,25 @@ class Status extends BaseDataTransferObject protected $pinned = false; /** @var string */ protected $content; - /** @var Status|null */ + /** @var Status[]|null */ protected $reblog = null; - /** @var Status|null - Akkoma extension, see issue https://github.com/friendica/friendica/issues/12603 */ + /** @var Status[]|null - Akkoma extension, see issue https://github.com/friendica/friendica/issues/12603 */ protected $quote = null; /** @var Application */ protected $application = null; - /** @var Account */ + /** @var array */ protected $account; - /** @var Attachment */ + /** @var Attachment[] */ protected $media_attachments = []; - /** @var Mention */ + /** @var Mention[] */ protected $mentions = []; - /** @var Tag */ + /** @var Tag[] */ protected $tags = []; /** @var Emoji[] */ protected $emojis = []; - /** @var Card|null */ + /** @var array|null */ protected $card = null; - /** @var Poll|null */ + /** @var array|null */ protected $poll = null; /** @var FriendicaExtension */ protected $friendica; diff --git a/src/Object/Api/Twitter/DirectMessage.php b/src/Object/Api/Twitter/DirectMessage.php index 10bea34290..199d9462ed 100644 --- a/src/Object/Api/Twitter/DirectMessage.php +++ b/src/Object/Api/Twitter/DirectMessage.php @@ -29,9 +29,9 @@ class DirectMessage extends BaseDataTransferObject protected $sender_screen_name = null; /** @var string */ protected $recipient_screen_name = null; - /** @var User */ + /** @var array */ protected $sender; - /** @var User */ + /** @var array */ protected $recipient; /** @var string|null */ protected $title; diff --git a/src/Object/Api/Twitter/Media.php b/src/Object/Api/Twitter/Media.php index 19f98f1a29..589aebcfc1 100644 --- a/src/Object/Api/Twitter/Media.php +++ b/src/Object/Api/Twitter/Media.php @@ -31,7 +31,7 @@ class Media extends BaseDataTransferObject protected $media_url; /** @var string */ protected $media_url_https; - /** @var string */ + /** @var array> */ protected $sizes; /** @var string */ protected $type; diff --git a/src/Object/Api/Twitter/Mention.php b/src/Object/Api/Twitter/Mention.php index e5d257e9d3..d2a4d5065f 100644 --- a/src/Object/Api/Twitter/Mention.php +++ b/src/Object/Api/Twitter/Mention.php @@ -7,7 +7,6 @@ namespace Friendica\Object\Api\Twitter; -use Friendica\App\BaseURL; use Friendica\BaseDataTransferObject; /** @@ -37,7 +36,7 @@ class Mention extends BaseDataTransferObject */ public function __construct(array $tag, array $contact, array $indices) { - $this->id = (string)($contact['id'] ?? 0); + $this->id = (int)($contact['id'] ?? 0); $this->id_str = (string)($contact['id'] ?? 0); $this->indices = $indices; $this->name = $tag['name']; diff --git a/src/Object/Api/Twitter/Status.php b/src/Object/Api/Twitter/Status.php index 793f32fb01..1c8a4ef7ae 100644 --- a/src/Object/Api/Twitter/Status.php +++ b/src/Object/Api/Twitter/Status.php @@ -45,11 +45,11 @@ class Status extends BaseDataTransferObject protected $geo; /** @var bool */ protected $favorited = false; - /** @var User */ + /** @var array */ protected $user; - /** @var User */ + /** @var array */ protected $friendica_author; - /** @var User */ + /** @var array */ protected $friendica_owner; /** @var bool */ protected $friendica_private; @@ -67,9 +67,9 @@ class Status extends BaseDataTransferObject protected $friendica_html; /** @var int */ protected $friendica_comments; - /** @var Status|null */ + /** @var array|null */ protected $retweeted_status = null; - /** @var Status|null */ + /** @var array|null */ protected $quoted_status = null; /** @var array */ protected $attachments; diff --git a/src/Object/Log/ParsedLogLine.php b/src/Object/Log/ParsedLogLine.php index 1d9802bb32..8e552008a4 100644 --- a/src/Object/Log/ParsedLogLine.php +++ b/src/Object/Log/ParsedLogLine.php @@ -29,7 +29,7 @@ class ParsedLogLine /** @var string */ public $message = null; - /** @var string */ + /** @var string|null */ public $data = null; /** @var string */ diff --git a/src/Object/Post.php b/src/Object/Post.php index b5ad33f56e..abf617e214 100644 --- a/src/Object/Post.php +++ b/src/Object/Post.php @@ -49,7 +49,7 @@ class Post private $parent = null; /** - * @var Thread + * @var Thread|null */ private $thread = null; private $redirect_url = null; @@ -816,7 +816,7 @@ class Post * Get a child by its ID * * @param integer $id The child id - * @return Thread|null Thread or NULL if not found + * @return Post|null Post or NULL if not found */ public function getChild(int $id) { diff --git a/src/Object/Thread.php b/src/Object/Thread.php index 453e4c3421..070d8c1281 100644 --- a/src/Object/Thread.php +++ b/src/Object/Thread.php @@ -77,8 +77,7 @@ class Thread break; default: DI::logger()->info('[ERROR] Conversation::setMode : Unhandled mode ('. $mode .').'); - return false; - break; + return; } $this->mode = $mode; } diff --git a/src/Profile/ProfileField/Collection/ProfileFields.php b/src/Profile/ProfileField/Collection/ProfileFields.php index fa39a6f355..dcf5498df3 100644 --- a/src/Profile/ProfileField/Collection/ProfileFields.php +++ b/src/Profile/ProfileField/Collection/ProfileFields.php @@ -8,31 +8,26 @@ namespace Friendica\Profile\ProfileField\Collection; use Friendica\BaseCollection; -use Friendica\Profile\ProfileField\Entity; +use Friendica\Profile\ProfileField\Entity\ProfileField as ProfileFieldEntity; class ProfileFields extends BaseCollection { - public function current(): Entity\ProfileField + public function current(): ProfileFieldEntity { return parent::current(); } - /** - * @param callable $callback - * @return ProfileFields (as an extended form of BaseCollection) - */ - public function map(callable $callback): BaseCollection + public function map(callable $callback): ProfileFields { - return parent::map($callback); + $class = get_class($this); + + return new $class(array_map($callback, $this->getArrayCopy()), $this->getTotalCount()); } - /** - * @param callable|null $callback - * @param int $flag - * @return ProfileFields as an extended version of BaseCollection - */ - public function filter(callable $callback = null, int $flag = 0): BaseCollection + public function filter(?callable $callback = null, int $flag = 0): ProfileFields { - return parent::filter($callback, $flag); + $class = get_class($this); + + return new $class(array_filter($this->getArrayCopy(), $callback, $flag)); } } From f6ac16d5139b4278565c75bd41787316e36b54f8 Mon Sep 17 00:00:00 2001 From: Art4 Date: Tue, 25 Feb 2025 14:03:52 +0000 Subject: [PATCH 10/46] Fix 11 PHPStan errors --- .../Notifications/Entity/Notify.php | 2 +- src/Object/Api/Friendica/Notification.php | 38 +++++++++---------- src/Object/Api/Mastodon/Field.php | 2 +- src/Object/Api/Mastodon/Notification.php | 4 +- src/Object/Api/Mastodon/Poll.php | 2 +- src/Object/Api/Mastodon/Relationship.php | 4 +- src/Object/Api/Mastodon/ScheduledStatus.php | 2 +- src/Object/Api/Mastodon/Status.php | 2 +- 8 files changed, 27 insertions(+), 29 deletions(-) diff --git a/src/Navigation/Notifications/Entity/Notify.php b/src/Navigation/Notifications/Entity/Notify.php index 297ecbdd98..71308772a9 100644 --- a/src/Navigation/Notifications/Entity/Notify.php +++ b/src/Navigation/Notifications/Entity/Notify.php @@ -14,7 +14,7 @@ use Friendica\Core\Renderer; use Psr\Http\Message\UriInterface; /** - * @property-read string $type + * @property-read int $type * @property-read string $name * @property-read UriInterface $url * @property-read UriInterface $photo diff --git a/src/Object/Api/Friendica/Notification.php b/src/Object/Api/Friendica/Notification.php index bff10accae..f83cd9cc2c 100644 --- a/src/Object/Api/Friendica/Notification.php +++ b/src/Object/Api/Friendica/Notification.php @@ -62,29 +62,29 @@ class Notification extends BaseDataTransferObject /** @var string Message (Plaintext) */ protected $msg_plain; - public function __construct(Notify $Notify) + public function __construct(Notify $notify) { - $this->id = $Notify->id; - $this->type = $Notify->type; - $this->name = $Notify->name; - $this->url = $Notify->url->__toString(); - $this->photo = $Notify->photo->__toString(); - $this->date = DateTimeFormat::local($Notify->date->format(DateTimeFormat::MYSQL)); - $this->msg = $Notify->msg; - $this->uid = $Notify->uid; - $this->link = $Notify->link->__toString(); - $this->iid = $Notify->itemId; - $this->parent = $Notify->parent; - $this->seen = $Notify->seen; - $this->verb = $Notify->verb; - $this->otype = $Notify->otype; - $this->name_cache = $Notify->name_cache; - $this->msg_cache = $Notify->msg_cache; - $this->timestamp = $Notify->date->format('U'); + $this->id = $notify->id; + $this->type = $notify->type; + $this->name = $notify->name; + $this->url = $notify->url->__toString(); + $this->photo = $notify->photo->__toString(); + $this->date = DateTimeFormat::local($notify->date->format(DateTimeFormat::MYSQL)); + $this->msg = $notify->msg; + $this->uid = $notify->uid; + $this->link = $notify->link->__toString(); + $this->iid = $notify->itemId; + $this->parent = $notify->parent; + $this->seen = $notify->seen; + $this->verb = $notify->verb; + $this->otype = $notify->otype; + $this->name_cache = $notify->name_cache; + $this->msg_cache = $notify->msg_cache; + $this->timestamp = (int) $notify->date->format('U'); $this->date_rel = Temporal::getRelativeDate($this->date); try { - $this->msg_html = BBCode::convertForUriId($Notify->uriId, $this->msg, BBCode::EXTERNAL); + $this->msg_html = BBCode::convertForUriId($notify->uriId, $this->msg, BBCode::EXTERNAL); } catch (\Exception $e) { $this->msg_html = ''; } diff --git a/src/Object/Api/Mastodon/Field.php b/src/Object/Api/Mastodon/Field.php index cf1983f2fe..846aac4d0f 100644 --- a/src/Object/Api/Mastodon/Field.php +++ b/src/Object/Api/Mastodon/Field.php @@ -20,7 +20,7 @@ class Field extends BaseDataTransferObject protected $name; /** @var string (HTML) */ protected $value; - /** @var string (Datetime)*/ + /** @var string|null (Datetime)*/ protected $verified_at; public function __construct(string $name, string $value) diff --git a/src/Object/Api/Mastodon/Notification.php b/src/Object/Api/Mastodon/Notification.php index e5593bfc82..b18a7f1e9e 100644 --- a/src/Object/Api/Mastodon/Notification.php +++ b/src/Object/Api/Mastodon/Notification.php @@ -44,9 +44,9 @@ class Notification extends BaseDataTransferObject protected $created_at; /** @var bool */ protected $dismissed; - /** @var Account */ + /** @var array */ protected $account; - /** @var Status|null */ + /** @var array|null */ protected $status = null; /** diff --git a/src/Object/Api/Mastodon/Poll.php b/src/Object/Api/Mastodon/Poll.php index 3d2e6c8f25..a17e8c57b5 100644 --- a/src/Object/Api/Mastodon/Poll.php +++ b/src/Object/Api/Mastodon/Poll.php @@ -32,7 +32,7 @@ class Poll extends BaseDataTransferObject /** @var bool|null */ protected $voted = false; /** @var array|null */ - protected $own_votes = false; + protected $own_votes = null; /** @var array */ protected $options = []; /** @var Emoji[] */ diff --git a/src/Object/Api/Mastodon/Relationship.php b/src/Object/Api/Mastodon/Relationship.php index 1d708425cd..2e9faf4d0b 100644 --- a/src/Object/Api/Mastodon/Relationship.php +++ b/src/Object/Api/Mastodon/Relationship.php @@ -18,7 +18,7 @@ use Friendica\Util\Network; */ class Relationship extends BaseDataTransferObject { - /** @var int */ + /** @var string */ protected $id; /** @var bool */ protected $following = false; @@ -88,7 +88,5 @@ class Relationship extends BaseDataTransferObject $this->blocking = (bool)($contactRecord['blocked'] ?? false) || $blocked; $this->note = $contactRecord['info']; } - - return $this; } } diff --git a/src/Object/Api/Mastodon/ScheduledStatus.php b/src/Object/Api/Mastodon/ScheduledStatus.php index ac4bf029c2..630ebd7839 100644 --- a/src/Object/Api/Mastodon/ScheduledStatus.php +++ b/src/Object/Api/Mastodon/ScheduledStatus.php @@ -35,7 +35,7 @@ class ScheduledStatus extends BaseDataTransferObject 'in_reply_to_id' => null, 'application_id' => '' ]; - /** @var Attachment */ + /** @var array */ protected $media_attachments = []; /** diff --git a/src/Object/Api/Mastodon/Status.php b/src/Object/Api/Mastodon/Status.php index 474db28dc0..77b49f685d 100644 --- a/src/Object/Api/Mastodon/Status.php +++ b/src/Object/Api/Mastodon/Status.php @@ -68,7 +68,7 @@ class Status extends BaseDataTransferObject protected $reblog = null; /** @var Status[]|null - Akkoma extension, see issue https://github.com/friendica/friendica/issues/12603 */ protected $quote = null; - /** @var Application */ + /** @var array */ protected $application = null; /** @var array */ protected $account; From fead4466240f1b14842d0ec7309972e69336e9e6 Mon Sep 17 00:00:00 2001 From: Art4 Date: Tue, 25 Feb 2025 14:29:57 +0000 Subject: [PATCH 11/46] Split phpstan.neon files for addon checks --- .phpstan-addons.neon | 52 ++++++++++++++++++++++++++++++++++++++++++++ .phpstan.neon | 32 --------------------------- composer.json | 1 + 3 files changed, 53 insertions(+), 32 deletions(-) create mode 100644 .phpstan-addons.neon diff --git a/.phpstan-addons.neon b/.phpstan-addons.neon new file mode 100644 index 0000000000..801db2ab6a --- /dev/null +++ b/.phpstan-addons.neon @@ -0,0 +1,52 @@ +# SPDX-FileCopyrightText: 2010 - 2024 the Friendica project +# +# SPDX-License-Identifier: CC0-1.0 + +parameters: + level: 2 + + paths: + - addon/ + + excludePaths: + analyse: + - addon/*/lang/* + - addon/*/vendor/* + - addon/convert/UnitConvertor.php + - addon/pumpio/oauth/* + + scanDirectories: + - mod + - src + - static + - vendor + - view + + dynamicConstantNames: + - DB_UPDATE_VERSION + + ignoreErrors: + + - + # Ignore missing SMTP class in PHPMailer 5.2.21 + # see https://github.com/PHPMailer/PHPMailer/blob/v5.2.21/class.smtp.php + message: '(^.+ an unknown class SMTP\.$)' + path: addon/mailstream/phpmailer + + - + # Ignore missing SMTP class in PHPMailer 5.2.21 + # see https://github.com/PHPMailer/PHPMailer/blob/v5.2.21/class.smtp.php + message: '(^Property .+ has unknown class SMTP as its type\.$)' + path: addon/mailstream/phpmailer + + - + # Ignore missing SMTP class in PHPMailer 5.2.21 + # see https://github.com/PHPMailer/PHPMailer/blob/v5.2.21/class.smtp.php + message: '(^Method .+ has invalid return type SMTP\.$)' + path: addon/mailstream/phpmailer + + - + # Ignore missing SMTP class in PHPMailer 5.2.21 + # see https://github.com/PHPMailer/PHPMailer/blob/v5.2.21/class.smtp.php + message: '(^Instantiated class SMTP not found\.$)' + path: addon/mailstream/phpmailer diff --git a/.phpstan.neon b/.phpstan.neon index bf01c3cc07..fb731728b8 100644 --- a/.phpstan.neon +++ b/.phpstan.neon @@ -6,7 +6,6 @@ parameters: level: 3 paths: - # - addon/ - bin/auth_ejabberd.php - bin/console.php - bin/daemon.php @@ -15,13 +14,6 @@ parameters: - index.php - src/ - excludePaths: - analyse: - - addon/*/lang/* - - addon/*/vendor/* - - addon/convert/UnitConvertor.php - - addon/pumpio/oauth/* - scanDirectories: - mod - static @@ -46,27 +38,3 @@ parameters: # Ignore missing IMAP\Connection class in PHP <= 8.0 message: '(^Parameter .+ has invalid type IMAP\\Connection\.$)' path: src - - # - - # Ignore missing SMTP class in PHPMailer 5.2.21 - # see https://github.com/PHPMailer/PHPMailer/blob/v5.2.21/class.smtp.php - # message: '(^.+ an unknown class SMTP\.$)' - # path: addon/mailstream/phpmailer - - # - - # Ignore missing SMTP class in PHPMailer 5.2.21 - # see https://github.com/PHPMailer/PHPMailer/blob/v5.2.21/class.smtp.php - # message: '(^Property .+ has unknown class SMTP as its type\.$)' - # path: addon/mailstream/phpmailer - - # - - # Ignore missing SMTP class in PHPMailer 5.2.21 - # see https://github.com/PHPMailer/PHPMailer/blob/v5.2.21/class.smtp.php - # message: '(^Method .+ has invalid return type SMTP\.$)' - # path: addon/mailstream/phpmailer - - # - - # Ignore missing SMTP class in PHPMailer 5.2.21 - # see https://github.com/PHPMailer/PHPMailer/blob/v5.2.21/class.smtp.php - # message: '(^Instantiated class SMTP not found\.$)' - # path: addon/mailstream/phpmailer diff --git a/composer.json b/composer.json index a2c9eea3c9..5e5344eeab 100644 --- a/composer.json +++ b/composer.json @@ -163,6 +163,7 @@ "test:unit": "phpunit -c tests/phpunit.xml --testsuite unit", "phpmd": "phpmd src/ text .phpmd-ruleset.xml --color --cache", "phpstan": "phpstan analyze --memory-limit 1024M --configuration .phpstan.neon", + "phpstan-addons": "phpstan analyze --memory-limit 1024M --configuration .phpstan-addons.neon", "lint": "find . -name \\*.php -not -path './vendor/*' -not -path './view/asset/*' -print0 | xargs -0 -n1 php -l", "docker:translate": "docker run --rm -v $PWD:/data -w /data friendicaci/transifex bin/run_xgettext.sh", "lang:recreate": "bin/run_xgettext.sh", From 8e7676bfd8152271e120a46145bf8cf76639bed4 Mon Sep 17 00:00:00 2001 From: Art4 Date: Tue, 25 Feb 2025 14:33:56 +0000 Subject: [PATCH 12/46] Add CI step for PHPStan in addons folder --- .github/workflows/code-quality.yml | 32 ++++++++++++++++++++++++++++++ .woodpecker/.phpunit.yml | 9 ++++++++- 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/.github/workflows/code-quality.yml b/.github/workflows/code-quality.yml index 9c8e20ee5f..bcca97c908 100644 --- a/.github/workflows/code-quality.yml +++ b/.github/workflows/code-quality.yml @@ -76,6 +76,38 @@ jobs: - name: Run PHPStan run: composer run phpstan + phpstan-addons: + name: PHPStan in addons (PHP ${{ matrix.php }}) + runs-on: ubuntu-latest + + strategy: + fail-fast: false + matrix: + operating-system: ['ubuntu-latest'] + php: ['8.4'] + + steps: + - name: Checkout + uses: actions/checkout@v3 + with: + fetch-depth: 2 + + - name: Setup PHP with composer and extensions + uses: shivammathur/setup-php@v2 #https://github.com/shivammathur/setup-php + with: + php-version: ${{ matrix.php }} + coverage: xdebug + tools: none + + - name: Clone addon repository + run: git clone -b develop --single-branch https://git.friendi.ca/friendica/friendica-addons.git addon + + - name: Install Composer dependencies + uses: "ramsey/composer-install@v2" + + - name: Run PHPStan in addons + run: composer run phpstan-addons + phpmd: name: PHPMD (PHP ${{ matrix.php }}) runs-on: ubuntu-latest diff --git a/.woodpecker/.phpunit.yml b/.woodpecker/.phpunit.yml index 04c66bcb97..3b8f466d13 100644 --- a/.woodpecker/.phpunit.yml +++ b/.woodpecker/.phpunit.yml @@ -64,9 +64,16 @@ steps: image: friendicaci/php${PHP_MAJOR_VERSION}:php${PHP_VERSION} when: matrix: - PHP_MAJOR_VERSION: 8.2 + PHP_MAJOR_VERSION: 8.3 commands: - bin/composer.phar run phpstan; + phpstan-addons: + image: friendicaci/php${PHP_MAJOR_VERSION}:php${PHP_VERSION} + when: + matrix: + PHP_MAJOR_VERSION: 8.3 + commands: + - bin/composer.phar run phpstan-addons; test: image: friendicaci/php${PHP_MAJOR_VERSION}:php${PHP_VERSION} environment: From 35d95b991bd51cf0f27691f2e03ae92941261d76 Mon Sep 17 00:00:00 2001 From: Art4 Date: Tue, 25 Feb 2025 15:26:16 +0000 Subject: [PATCH 13/46] Fix 4 PHPStan errors --- .../Notifications/Repository/Notification.php | 55 +++++++----------- .../Notifications/Repository/Notify.php | 29 ++++------ .../ValueObject/Introduction.php | 58 +++++++++---------- .../HTTPClient/Response/CurlResult.php | 2 +- .../HTTPClient/Response/GuzzleResponse.php | 2 +- 5 files changed, 65 insertions(+), 81 deletions(-) diff --git a/src/Navigation/Notifications/Repository/Notification.php b/src/Navigation/Notifications/Repository/Notification.php index 11d3bd6b54..e0e1d2aa98 100644 --- a/src/Navigation/Notifications/Repository/Notification.php +++ b/src/Navigation/Notifications/Repository/Notification.php @@ -15,8 +15,8 @@ use Friendica\Database\Database; use Friendica\Database\DBA; use Friendica\Model\Post\UserNotification; use Friendica\Model\Verb; -use Friendica\Navigation\Notifications\Collection; -use Friendica\Navigation\Notifications\Entity; +use Friendica\Navigation\Notifications\Collection\Notifications as NotificationsCollection; +use Friendica\Navigation\Notifications\Entity\Notification as NotificationEntity; use Friendica\Navigation\Notifications\Factory; use Friendica\Network\HTTPException\NotFoundException; use Friendica\Protocol\Activity; @@ -41,19 +41,18 @@ class Notification extends BaseRepository } /** - * @param array $condition - * @param array $params - * @return Entity\Notification * @throws NotFoundException */ - private function selectOne(array $condition, array $params = []): Entity\Notification + private function selectOne(array $condition, array $params = []): NotificationEntity { - return parent::_selectOne($condition, $params); + $fields = $this->_selectFirstRowAsArray( $condition, $params); + + return $this->factory->createFromTableRow($fields); } - private function select(array $condition, array $params = []): Collection\Notifications + private function select(array $condition, array $params = []): NotificationsCollection { - return new Collection\Notifications(parent::_select($condition, $params)->getArrayCopy()); + return new NotificationsCollection(parent::_select($condition, $params)->getArrayCopy()); } public function countForUser($uid, array $condition, array $params = []): int @@ -71,23 +70,21 @@ class Notification extends BaseRepository } /** - * @param int $id - * @return Entity\Notification * @throws NotFoundException */ - public function selectOneById(int $id): Entity\Notification + public function selectOneById(int $id): NotificationEntity { return $this->selectOne(['id' => $id]); } - public function selectOneForUser(int $uid, array $condition, array $params = []): Entity\Notification + public function selectOneForUser(int $uid, array $condition, array $params = []): NotificationEntity { $condition = DBA::mergeConditions($condition, ['uid' => $uid]); return $this->selectOne($condition, $params); } - public function selectForUser(int $uid, array $condition = [], array $params = []): Collection\Notifications + public function selectForUser(int $uid, array $condition = [], array $params = []): NotificationsCollection { $condition = DBA::mergeConditions($condition, ['uid' => $uid]); @@ -98,12 +95,9 @@ class Notification extends BaseRepository /** * Returns only the most recent notifications for the same conversation or contact * - * @param int $uid - * - * @return Collection\Notifications * @throws Exception */ - public function selectDetailedForUser(int $uid): Collection\Notifications + public function selectDetailedForUser(int $uid): NotificationsCollection { $notify_type = $this->pconfig->get($uid, 'system', 'notify_type'); if (!is_null($notify_type)) { @@ -113,11 +107,11 @@ class Notification extends BaseRepository } if (!$this->pconfig->get($uid, 'system', 'notify_like')) { - $condition = DBA::mergeConditions($condition, ['NOT `vid` IN (?, ?)', Verb::getID(\Friendica\Protocol\Activity::LIKE), Verb::getID(\Friendica\Protocol\Activity::DISLIKE)]); + $condition = DBA::mergeConditions($condition, ['NOT `vid` IN (?, ?)', Verb::getID(Activity::LIKE), Verb::getID(Activity::DISLIKE)]); } if (!$this->pconfig->get($uid, 'system', 'notify_announce')) { - $condition = DBA::mergeConditions($condition, ['`vid` != ?', Verb::getID(\Friendica\Protocol\Activity::ANNOUNCE)]); + $condition = DBA::mergeConditions($condition, ['`vid` != ?', Verb::getID(Activity::ANNOUNCE)]); } return $this->selectForUser($uid, $condition, ['limit' => 50, 'order' => ['id' => true]]); @@ -126,12 +120,9 @@ class Notification extends BaseRepository /** * Returns only the most recent notifications for the same conversation or contact * - * @param int $uid - * - * @return Collection\Notifications * @throws Exception */ - public function selectDigestForUser(int $uid): Collection\Notifications + public function selectDigestForUser(int $uid): NotificationsCollection { $values = [$uid]; @@ -145,14 +136,14 @@ class Notification extends BaseRepository $like_condition = ''; if (!$this->pconfig->get($uid, 'system', 'notify_like')) { $like_condition = 'AND NOT `vid` IN (?, ?)'; - $values[] = Verb::getID(\Friendica\Protocol\Activity::LIKE); - $values[] = Verb::getID(\Friendica\Protocol\Activity::DISLIKE); + $values[] = Verb::getID(Activity::LIKE); + $values[] = Verb::getID(Activity::DISLIKE); } $announce_condition = ''; if (!$this->pconfig->get($uid, 'system', 'notify_announce')) { $announce_condition = 'AND vid != ?'; - $values[] = Verb::getID(\Friendica\Protocol\Activity::ANNOUNCE); + $values[] = Verb::getID(Activity::ANNOUNCE); } $rows = $this->db->p(" @@ -171,7 +162,7 @@ class Notification extends BaseRepository LIMIT 50 ", ...$values); - $Entities = new Collection\Notifications(); + $Entities = new NotificationsCollection(); foreach ($rows as $fields) { $Entities[] = $this->factory->createFromTableRow($fields); } @@ -179,7 +170,7 @@ class Notification extends BaseRepository return $Entities; } - public function selectAllForUser(int $uid): Collection\Notifications + public function selectAllForUser(int $uid): NotificationsCollection { return $this->selectForUser($uid); } @@ -199,7 +190,7 @@ class Notification extends BaseRepository { $BaseCollection = parent::_selectByBoundaries($condition, $params, $min_id, $max_id, $limit); - return new Collection\Notifications($BaseCollection->getArrayCopy(), $BaseCollection->getTotalCount()); + return new NotificationsCollection($BaseCollection->getArrayCopy(), $BaseCollection->getTotalCount()); } public function setAllSeenForUser(int $uid, array $condition = []): bool @@ -217,11 +208,9 @@ class Notification extends BaseRepository } /** - * @param Entity\Notification $Notification - * @return Entity\Notification * @throws Exception */ - public function save(Entity\Notification $Notification): Entity\Notification + public function save(NotificationEntity $Notification): NotificationEntity { $fields = [ 'uid' => $Notification->uid, diff --git a/src/Navigation/Notifications/Repository/Notify.php b/src/Navigation/Notifications/Repository/Notify.php index 1c793faaee..8c8cde1333 100644 --- a/src/Navigation/Notifications/Repository/Notify.php +++ b/src/Navigation/Notifications/Repository/Notify.php @@ -20,7 +20,8 @@ use Friendica\Database\DBA; use Friendica\Factory\Api\Mastodon\Notification as NotificationFactory; use Friendica\Model; use Friendica\Navigation\Notifications\Collection; -use Friendica\Navigation\Notifications\Entity; +use Friendica\Navigation\Notifications\Entity\Notification as NotificationEntity; +use Friendica\Navigation\Notifications\Entity\Notify as NotifyEntity; use Friendica\Navigation\Notifications\Exception; use Friendica\Navigation\Notifications\Factory; use Friendica\Network\HTTPException; @@ -31,7 +32,7 @@ use Friendica\Util\Emailer; use Psr\Log\LoggerInterface; /** - * @deprecated since 2022.05 Use \Friendica\Navigation\Notifications\Repository\Notification instead + * @deprecated 2022.05 Use `\Friendica\Navigation\Notifications\Repository\Notification` instead */ class Notify extends BaseRepository { @@ -71,15 +72,13 @@ class Notify extends BaseRepository } /** - * @param array $condition - * @param array $params - * - * @return Entity\Notify * @throws HTTPException\NotFoundException */ - private function selectOne(array $condition, array $params = []): Entity\Notify + private function selectOne(array $condition, array $params = []): NotifyEntity { - return parent::_selectOne($condition, $params); + $fields = $this->_selectFirstRowAsArray( $condition, $params); + + return $this->factory->createFromTableRow($fields); } private function select(array $condition, array $params = []): Collection\Notifies @@ -104,10 +103,9 @@ class Notify extends BaseRepository /** * @param int $id * - * @return Entity\Notify * @throws HTTPException\NotFoundException */ - public function selectOneById(int $id): Entity\Notify + public function selectOneById(int $id): NotifyEntity { return $this->selectOne(['id' => $id]); } @@ -139,14 +137,11 @@ class Notify extends BaseRepository } /** - * @param Entity\Notify $Notify - * - * @return Entity\Notify * @throws HTTPException\NotFoundException * @throws HTTPException\InternalServerErrorException * @throws Exception\NotificationCreationInterceptedException */ - public function save(Entity\Notify $Notify): Entity\Notify + public function save(NotifyEntity $Notify): NotifyEntity { $fields = [ 'type' => $Notify->type, @@ -181,7 +176,7 @@ class Notify extends BaseRepository return $Notify; } - public function setAllSeenForRelatedNotify(Entity\Notify $Notify): bool + public function setAllSeenForRelatedNotify(NotifyEntity $Notify): bool { $condition = [ '(`link` = ? OR (`parent` != 0 AND `parent` = ? AND `otype` = ?)) AND `uid` = ?', @@ -670,7 +665,7 @@ class Notify extends BaseRepository return false; } - public function shouldShowOnDesktop(Entity\Notification $Notification, string $type = null): bool + public function shouldShowOnDesktop(NotificationEntity $Notification, string $type = null): bool { if (is_null($type)) { $type = NotificationFactory::getType($Notification); @@ -702,7 +697,7 @@ class Notify extends BaseRepository return false; } - public function createFromNotification(Entity\Notification $Notification): bool + public function createFromNotification(NotificationEntity $Notification): bool { $this->logger->info('Start', ['uid' => $Notification->uid, 'id' => $Notification->id, 'type' => $Notification->type]); diff --git a/src/Navigation/Notifications/ValueObject/Introduction.php b/src/Navigation/Notifications/ValueObject/Introduction.php index 587daa8f4e..6e2c24d340 100644 --- a/src/Navigation/Notifications/ValueObject/Introduction.php +++ b/src/Navigation/Notifications/ValueObject/Introduction.php @@ -61,6 +61,34 @@ class Introduction implements \JsonSerializable /** @var string */ private $about; + public function __construct(array $data = []) + { + $this->label = $data['label'] ?? ''; + $this->type = $data['str_type'] ?? ''; + $this->intro_id = $data['intro_id'] ?? -1; + $this->madeBy = $data['madeBy'] ?? ''; + $this->madeByUrl = $data['madeByUrl'] ?? ''; + $this->madeByZrl = $data['madeByZrl'] ?? ''; + $this->madeByAddr = $data['madeByAddr'] ?? ''; + $this->contactId = $data['contactId'] ?? -1; + $this->photo = $data['photo'] ?? ''; + $this->name = $data['name'] ?? ''; + $this->url = $data['url'] ?? ''; + $this->zrl = $data['zrl'] ?? ''; + $this->hidden = $data['hidden'] ?? false; + $this->postNewFriend = $data['postNewFriend'] ?? ''; + $this->knowYou = $data['knowYou'] ?? false; + $this->note = $data['note'] ?? ''; + $this->request = $data['request'] ?? ''; + $this->dfrnId = -1; + $this->addr = $data['addr'] ?? ''; + $this->network = $data['network'] ?? ''; + $this->uid = $data['uid'] ?? -1; + $this->keywords = $data['keywords'] ?? ''; + $this->location = $data['location'] ?? ''; + $this->about = $data['about'] ?? ''; + } + public function getLabel(): string { return $this->label; @@ -131,7 +159,7 @@ class Introduction implements \JsonSerializable return $this->postNewFriend; } - public function getKnowYou(): string + public function getKnowYou(): bool { return $this->knowYou; } @@ -181,34 +209,6 @@ class Introduction implements \JsonSerializable return $this->about; } - public function __construct(array $data = []) - { - $this->label = $data['label'] ?? ''; - $this->type = $data['str_type'] ?? ''; - $this->intro_id = $data['intro_id'] ?? -1; - $this->madeBy = $data['madeBy'] ?? ''; - $this->madeByUrl = $data['madeByUrl'] ?? ''; - $this->madeByZrl = $data['madeByZrl'] ?? ''; - $this->madeByAddr = $data['madeByAddr'] ?? ''; - $this->contactId = $data['contactId'] ?? -1; - $this->photo = $data['photo'] ?? ''; - $this->name = $data['name'] ?? ''; - $this->url = $data['url'] ?? ''; - $this->zrl = $data['zrl'] ?? ''; - $this->hidden = $data['hidden'] ?? false; - $this->postNewFriend = $data['postNewFriend'] ?? ''; - $this->knowYou = $data['knowYou'] ?? false; - $this->note = $data['note'] ?? ''; - $this->request = $data['request'] ?? ''; - $this->dfrnId = -1; - $this->addr = $data['addr'] ?? ''; - $this->network = $data['network'] ?? ''; - $this->uid = $data['uid'] ?? -1; - $this->keywords = $data['keywords'] ?? ''; - $this->location = $data['location'] ?? ''; - $this->about = $data['about'] ?? ''; - } - /** * @inheritDoc */ diff --git a/src/Network/HTTPClient/Response/CurlResult.php b/src/Network/HTTPClient/Response/CurlResult.php index a79023132a..30b8be3830 100644 --- a/src/Network/HTTPClient/Response/CurlResult.php +++ b/src/Network/HTTPClient/Response/CurlResult.php @@ -246,7 +246,7 @@ class CurlResult implements ICanHandleHttpResponses /** {@inheritDoc} */ public function getReturnCode(): string { - return $this->returnCode; + return (string) $this->returnCode; } /** {@inheritDoc} */ diff --git a/src/Network/HTTPClient/Response/GuzzleResponse.php b/src/Network/HTTPClient/Response/GuzzleResponse.php index 0e246a0cb0..fde67cdd8c 100644 --- a/src/Network/HTTPClient/Response/GuzzleResponse.php +++ b/src/Network/HTTPClient/Response/GuzzleResponse.php @@ -100,7 +100,7 @@ class GuzzleResponse extends Response implements ICanHandleHttpResponses, Respon /** {@inheritDoc} */ public function getReturnCode(): string { - return $this->getStatusCode(); + return (string) $this->getStatusCode(); } /** {@inheritDoc} */ From 1820bfc2b3edb4936acfa69c7da8ea3a9f8307a7 Mon Sep 17 00:00:00 2001 From: Art4 Date: Wed, 26 Feb 2025 08:11:50 +0000 Subject: [PATCH 14/46] Fix 5 PHPStan errors --- src/Database/Database.php | 2 +- .../Collection/Notifications.php | 40 +++++++++++++------ .../Notifications/Collection/Notifies.php | 18 +++++---- .../Notifications/Repository/Notification.php | 13 ++++-- 4 files changed, 47 insertions(+), 26 deletions(-) diff --git a/src/Database/Database.php b/src/Database/Database.php index 6ee4394901..14416a1899 100644 --- a/src/Database/Database.php +++ b/src/Database/Database.php @@ -474,7 +474,7 @@ class Database * * @param string $sql SQL statement * - * @return bool|object statement object or result object + * @return bool|mysqli_result|mysqli_stmt|object|PDOStatement statement object or result object * @throws \Exception */ public function p(string $sql) diff --git a/src/Navigation/Notifications/Collection/Notifications.php b/src/Navigation/Notifications/Collection/Notifications.php index 2174b213a9..4c32cf598b 100644 --- a/src/Navigation/Notifications/Collection/Notifications.php +++ b/src/Navigation/Notifications/Collection/Notifications.php @@ -8,36 +8,50 @@ namespace Friendica\Navigation\Notifications\Collection; use Friendica\BaseCollection; -use Friendica\Navigation\Notifications\Entity; +use Friendica\Navigation\Notifications\Entity\Notification as NotificationEntity; class Notifications extends BaseCollection { - /** - * @return Entity\Notification - */ - public function current(): Entity\Notification + public function current(): NotificationEntity { return parent::current(); } public function setSeen(): Notifications { - return $this->map(function (Entity\Notification $Notification) { - $Notification->setSeen(); - }); + $class = get_class($this); + + return new $class( + array_map( + function (NotificationEntity $notification) { + $notification->setSeen(); + }, + $this->getArrayCopy() + ), + $this->getTotalCount(), + ); } public function setDismissed(): Notifications { - return $this->map(function (Entity\Notification $Notification) { - $Notification->setDismissed(); - }); + $class = get_class($this); + + return new $class( + array_map( + function (NotificationEntity $notification) { + $notification->setDismissed(); + }, + $this->getArrayCopy(), + ), + $this->getTotalCount(), + ); + } public function countUnseen(): int { - return array_reduce($this->getArrayCopy(), function (int $carry, Entity\Notification $Notification) { - return $carry + ($Notification->seen ? 0 : 1); + return array_reduce($this->getArrayCopy(), function (int $carry, NotificationEntity $notification) { + return $carry + ($notification->seen ? 0 : 1); }, 0); } } diff --git a/src/Navigation/Notifications/Collection/Notifies.php b/src/Navigation/Notifications/Collection/Notifies.php index 4f41d2e261..fc97880de3 100644 --- a/src/Navigation/Notifications/Collection/Notifies.php +++ b/src/Navigation/Notifications/Collection/Notifies.php @@ -8,22 +8,24 @@ namespace Friendica\Navigation\Notifications\Collection; use Friendica\BaseCollection; -use Friendica\Navigation\Notifications\Entity; +use Friendica\Navigation\Notifications\Entity\Notify as NotifyEntity; class Notifies extends BaseCollection { - /** - * @return Entity\Notify - */ - public function current(): Entity\Notify + public function current(): NotifyEntity { return parent::current(); } public function setSeen(): Notifies { - return $this->map(function (Entity\Notify $Notify) { - $Notify->setSeen(); - }); + $class = get_class($this); + + return new $class(array_map( + function (NotifyEntity $notify) { + $notify->setSeen(); + }, + $this->getArrayCopy()), $this->getTotalCount(), + ); } } diff --git a/src/Navigation/Notifications/Repository/Notification.php b/src/Navigation/Notifications/Repository/Notification.php index e0e1d2aa98..49703bc1f9 100644 --- a/src/Navigation/Notifications/Repository/Notification.php +++ b/src/Navigation/Notifications/Repository/Notification.php @@ -162,12 +162,17 @@ class Notification extends BaseRepository LIMIT 50 ", ...$values); - $Entities = new NotificationsCollection(); - foreach ($rows as $fields) { - $Entities[] = $this->factory->createFromTableRow($fields); + $entities = new NotificationsCollection(); + + if (!is_iterable($rows)) { + return $entities; } - return $Entities; + foreach ($rows as $fields) { + $entities[] = $this->factory->createFromTableRow($fields); + } + + return $entities; } public function selectAllForUser(int $uid): NotificationsCollection From f64660ec255873840a7766fc3228a5a433f6c3ce Mon Sep 17 00:00:00 2001 From: Art4 Date: Wed, 26 Feb 2025 08:15:27 +0000 Subject: [PATCH 15/46] Deprecate BaseCollection::map() method --- src/BaseCollection.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/BaseCollection.php b/src/BaseCollection.php index b30dbfc6b0..36c6b9a63e 100644 --- a/src/BaseCollection.php +++ b/src/BaseCollection.php @@ -83,12 +83,16 @@ class BaseCollection extends \ArrayIterator /** * Apply a callback function on all elements in the collection and returns a new collection with the updated elements * + * @deprecated 2025.05 Use `array_map()` instead + * * @param callable $callback * @return BaseCollection * @see array_map() */ public function map(callable $callback): BaseCollection { + @trigger_error('`' . __METHOD__ . '()` is deprecated since 2025.05 and will be removed after 5 months, use `array_map()` instead.', E_USER_DEPRECATED); + $class = get_class($this); return new $class(array_map($callback, $this->getArrayCopy()), $this->getTotalCount()); From b6312f1dfcd637d9dbabd49a5ded8395616b3c7d Mon Sep 17 00:00:00 2001 From: Art4 Date: Wed, 26 Feb 2025 13:00:50 +0000 Subject: [PATCH 16/46] Fix 10 PHPStan errors --- src/Module/Api/Mastodon/Search.php | 5 +++++ src/Module/Api/Twitter/Lists/Ownership.php | 7 +++++-- src/Module/Conversation/Network.php | 4 ++-- src/Module/Filer/RemoveTag.php | 9 ++++----- 4 files changed, 16 insertions(+), 9 deletions(-) diff --git a/src/Module/Api/Mastodon/Search.php b/src/Module/Api/Mastodon/Search.php index 9301c60cdc..c054329dde 100644 --- a/src/Module/Api/Mastodon/Search.php +++ b/src/Module/Api/Mastodon/Search.php @@ -196,6 +196,11 @@ class Search extends BaseApi $tags = DBA::select('tag', ['name'], $condition, $params); $hashtags = []; + + if (!is_iterable($tags)) { + return $hashtags; + } + foreach ($tags as $tag) { if ($version == 1) { $hashtags[] = $tag['name']; diff --git a/src/Module/Api/Twitter/Lists/Ownership.php b/src/Module/Api/Twitter/Lists/Ownership.php index bdf34ed280..0b18f6bc18 100644 --- a/src/Module/Api/Twitter/Lists/Ownership.php +++ b/src/Module/Api/Twitter/Lists/Ownership.php @@ -48,8 +48,11 @@ class Ownership extends BaseApi // loop through all circles $lists = []; - foreach ($circles as $circle) { - $lists[] = $this->friendicaCircle->createFromId($circle['id']); + + if (is_iterable($circles)) { + foreach ($circles as $circle) { + $lists[] = $this->friendicaCircle->createFromId($circle['id']); + } } $this->response->addFormattedContent('statuses', ['lists' => ['lists' => $lists]], $this->parameters['extension'] ?? null, Contact::getPublicIdByUserId($uid)); diff --git a/src/Module/Conversation/Network.php b/src/Module/Conversation/Network.php index 86c2fcf736..629295f7c8 100644 --- a/src/Module/Conversation/Network.php +++ b/src/Module/Conversation/Network.php @@ -59,9 +59,9 @@ class Network extends Timeline protected $dateFrom; /** @var string */ protected $dateTo; - /** @var int */ + /** @var bool */ protected $star; - /** @var int */ + /** @var bool */ protected $mention; /** @var AppHelper */ diff --git a/src/Module/Filer/RemoveTag.php b/src/Module/Filer/RemoveTag.php index 330f6953a6..28666c8a44 100644 --- a/src/Module/Filer/RemoveTag.php +++ b/src/Module/Filer/RemoveTag.php @@ -11,7 +11,6 @@ use Friendica\App; use Friendica\BaseModule; use Friendica\Core\L10n; use Friendica\Core\Session\Capability\IHandleUserSessions; -use Friendica\Core\System; use Friendica\Database\DBA; use Friendica\Model\Post; use Friendica\Module\Response; @@ -59,15 +58,15 @@ class RemoveTag extends BaseModule } /** - * @param array $request The $_REQUEST array - * @param string|null $type Output parameter with the computed type - * @param string|null $term Output parameter with the computed term + * @param array $request The $_REQUEST array + * @param string|int|null $type Output parameter with the computed type + * @param string|null $term Output parameter with the computed term * * @return int The relevant HTTP code * * @throws \Exception */ - private function removeTag(array $request, string &$type = null, string &$term = null): int + private function removeTag(array $request, &$type = null, string &$term = null): int { $item_id = $this->parameters['id'] ?? 0; From 3bc3f5fe4d59fabeb2664c8a4b082f3c53f9e311 Mon Sep 17 00:00:00 2001 From: Art4 Date: Wed, 26 Feb 2025 15:06:57 +0000 Subject: [PATCH 17/46] Fix 2 PHPStan errors --- src/Moderation/Repository/Report.php | 33 +++++++++++++--------- src/Module/Api/Mastodon/Lists/Accounts.php | 2 +- 2 files changed, 20 insertions(+), 15 deletions(-) diff --git a/src/Moderation/Repository/Report.php b/src/Moderation/Repository/Report.php index 69ca81c167..9777e6b9cf 100644 --- a/src/Moderation/Repository/Report.php +++ b/src/Moderation/Repository/Report.php @@ -7,12 +7,14 @@ namespace Friendica\Moderation\Repository; -use Friendica\BaseEntity; use Friendica\Database\Database; -use Friendica\DI; use Friendica\Model\Post; -use Friendica\Moderation\Factory; -use Friendica\Moderation\Collection; +use Friendica\Moderation\Collection\Report\Posts as PostsCollection; +use Friendica\Moderation\Collection\Report\Rules as RulesCollection; +use Friendica\Moderation\Entity\Report as ReportEntity; +use Friendica\Moderation\Factory\Report as ReportFactory; +use Friendica\Moderation\Factory\Report\Post as PostFactory; +use Friendica\Moderation\Factory\Report\Rule as RuleFactory; use Friendica\Network\HTTPException\NotFoundException; use Friendica\Util\DateTimeFormat; use Psr\Log\LoggerInterface; @@ -21,14 +23,14 @@ final class Report extends \Friendica\BaseRepository { protected static $table_name = 'report'; - /** @var Factory\Report */ + /** @var ReportFactory */ protected $factory; - /** @var Factory\Report\Post */ + /** @var PostFactory */ protected $postFactory; - /** @var Factory\Report\Rule */ + /** @var RuleFactory */ protected $ruleFactory; - public function __construct(Database $database, LoggerInterface $logger, Factory\Report $factory, Factory\Report\Post $postFactory, Factory\Report\Rule $ruleFactory) + public function __construct(Database $database, LoggerInterface $logger, ReportFactory $factory, PostFactory $postFactory, RuleFactory $ruleFactory) { parent::__construct($database, $logger, $factory); @@ -37,12 +39,12 @@ final class Report extends \Friendica\BaseRepository $this->ruleFactory = $ruleFactory; } - public function selectOneById(int $lastInsertId): \Friendica\Moderation\Entity\Report + public function selectOneById(int $lastInsertId): ReportEntity { return $this->_selectOne(['id' => $lastInsertId]); } - public function save(\Friendica\Moderation\Entity\Report $Report): \Friendica\Moderation\Entity\Report + public function save(ReportEntity $Report): ReportEntity { $fields = [ 'reporter-id' => $Report->reporterCid, @@ -73,7 +75,7 @@ final class Report extends \Friendica\BaseRepository if (Post::exists(['uri-id' => $post->uriId])) { $this->db->insert('report-post', ['rid' => $newReportId, 'uri-id' => $post->uriId, 'status' => $post->status]); } else { - DI::logger()->notice('Post does not exist', ['uri-id' => $post->uriId, 'report' => $Report]); + $this->logger->notice('Post does not exist', ['uri-id' => $post->uriId, 'report' => $Report]); } } @@ -87,15 +89,18 @@ final class Report extends \Friendica\BaseRepository return $Report; } - protected function _selectOne(array $condition, array $params = []): BaseEntity + /** + * @throws NotFoundException + */ + protected function _selectOne(array $condition, array $params = []): ReportEntity { $fields = $this->db->selectFirst(self::$table_name, [], $condition, $params); if (!$this->db->isResult($fields)) { throw new NotFoundException(); } - $reportPosts = new Collection\Report\Posts(array_map([$this->postFactory, 'createFromTableRow'], $this->db->selectToArray('report-post', ['uri-id', 'status'], ['rid' => $condition['id'] ?? 0]))); - $reportRules = new Collection\Report\Rules(array_map([$this->ruleFactory, 'createFromTableRow'], $this->db->selectToArray('report-rule', ['line-id', 'text'], ['rid' => $condition['id'] ?? 0]))); + $reportPosts = new PostsCollection(array_map([$this->postFactory, 'createFromTableRow'], $this->db->selectToArray('report-post', ['uri-id', 'status'], ['rid' => $condition['id'] ?? 0]))); + $reportRules = new RulesCollection(array_map([$this->ruleFactory, 'createFromTableRow'], $this->db->selectToArray('report-rule', ['line-id', 'text'], ['rid' => $condition['id'] ?? 0]))); return $this->factory->createFromTableRow($fields, $reportPosts, $reportRules); } diff --git a/src/Module/Api/Mastodon/Lists/Accounts.php b/src/Module/Api/Mastodon/Lists/Accounts.php index 796ced67b8..65a76c78ea 100644 --- a/src/Module/Api/Mastodon/Lists/Accounts.php +++ b/src/Module/Api/Mastodon/Lists/Accounts.php @@ -31,7 +31,7 @@ class Accounts extends BaseApi $this->logAndJsonError(422, $this->errorFactory->UnprocessableEntity()); } - return Circle::removeMembers($this->parameters['id'], $request['account_ids']); + Circle::removeMembers($this->parameters['id'], $request['account_ids']); } protected function post(array $request = []) From 354d13167edb2138099e8e14ce64bcfdb6c97726 Mon Sep 17 00:00:00 2001 From: Artur Weigandt Date: Thu, 27 Feb 2025 12:50:19 +0100 Subject: [PATCH 18/46] Update src/Module/Api/Mastodon/Search.php Co-authored-by: Hypolite Petovan --- src/Module/Api/Mastodon/Search.php | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/Module/Api/Mastodon/Search.php b/src/Module/Api/Mastodon/Search.php index c054329dde..d7224ff950 100644 --- a/src/Module/Api/Mastodon/Search.php +++ b/src/Module/Api/Mastodon/Search.php @@ -193,14 +193,10 @@ class Search extends BaseApi $condition = ["`id` IN (SELECT `tid` FROM `post-tag` WHERE `type` = ?) AND `name` LIKE ?", Tag::HASHTAG, $q . '%']; - $tags = DBA::select('tag', ['name'], $condition, $params); + $tags = DBA::selectToArray('tag', ['name'], $condition, $params); $hashtags = []; - if (!is_iterable($tags)) { - return $hashtags; - } - foreach ($tags as $tag) { if ($version == 1) { $hashtags[] = $tag['name']; From 980beb4b1c0fcf09eeb622dd45b0cd2fe3a59af7 Mon Sep 17 00:00:00 2001 From: Art4 Date: Thu, 27 Feb 2025 12:47:25 +0000 Subject: [PATCH 19/46] Use selectToArray() instead of select() and is_iterable() --- src/Module/Api/Twitter/Lists/Ownership.php | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/Module/Api/Twitter/Lists/Ownership.php b/src/Module/Api/Twitter/Lists/Ownership.php index 0b18f6bc18..bea9367a6d 100644 --- a/src/Module/Api/Twitter/Lists/Ownership.php +++ b/src/Module/Api/Twitter/Lists/Ownership.php @@ -44,15 +44,13 @@ class Ownership extends BaseApi $this->checkAllowedScope(BaseApi::SCOPE_READ); $uid = BaseApi::getCurrentUserID(); - $circles = $this->dba->select('group', [], ['deleted' => false, 'uid' => $uid, 'cid' => null]); + $circles = $this->dba->selectToArray('group', [], ['deleted' => false, 'uid' => $uid, 'cid' => null]); // loop through all circles $lists = []; - if (is_iterable($circles)) { - foreach ($circles as $circle) { - $lists[] = $this->friendicaCircle->createFromId($circle['id']); - } + foreach ($circles as $circle) { + $lists[] = $this->friendicaCircle->createFromId($circle['id']); } $this->response->addFormattedContent('statuses', ['lists' => ['lists' => $lists]], $this->parameters['extension'] ?? null, Contact::getPublicIdByUserId($uid)); From 4ebabd5997fec5ea0fd1cb6db0375e1e38c18a67 Mon Sep 17 00:00:00 2001 From: Art4 Date: Wed, 5 Mar 2025 14:27:34 +0000 Subject: [PATCH 20/46] Fix 7 PHPStan errors --- src/Core/Hook.php | 2 +- src/Factory/Api/Friendica/Photo.php | 3 +-- src/Model/Item.php | 15 +++++++++++++-- src/Model/Log/ParsedLogIterator.php | 2 +- src/Model/Photo.php | 7 +++---- src/Model/Post/Delayed.php | 3 +-- 6 files changed, 20 insertions(+), 12 deletions(-) diff --git a/src/Core/Hook.php b/src/Core/Hook.php index 44dfad70bc..8c9f3ba910 100644 --- a/src/Core/Hook.php +++ b/src/Core/Hook.php @@ -172,7 +172,7 @@ class Hook * the provided data. * * @param string $name of the hook to call - * @param string|array &$data to transmit to the callback handler + * @param string|array|null $data to transmit to the callback handler * @return void * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ diff --git a/src/Factory/Api/Friendica/Photo.php b/src/Factory/Api/Friendica/Photo.php index 82c80ac7f3..051ae66a5d 100644 --- a/src/Factory/Api/Friendica/Photo.php +++ b/src/Factory/Api/Friendica/Photo.php @@ -41,7 +41,6 @@ class Photo extends BaseFactory * @param int $scale * @param int $uid * @param string $type - * @return Array */ public function createFromId(string $photo_id, int $scale = null, int $uid, string $type = 'json', bool $with_posts = true): array { @@ -66,7 +65,7 @@ class Photo extends BaseFactory $data['id'] = $data['resource-id']; if (is_int($scale)) { - $data['data'] = base64_encode(ModelPhoto::getImageDataForPhoto($data)); + $data['data'] = base64_encode(ModelPhoto::getImageDataForPhoto($data) ?? ''); } if ($type == 'xml') { diff --git a/src/Model/Item.php b/src/Model/Item.php index 31f8a8e22e..6500c8005c 100644 --- a/src/Model/Item.php +++ b/src/Model/Item.php @@ -672,7 +672,7 @@ class Item /** * Inserts item record * - * @param array $item Item array to be inserted + * @param array $item Item array to be inserted * @param int $notify Notification (type?) * @param bool $post_local (???) * @return int Zero means error, otherwise primary key (id) is being returned @@ -695,6 +695,7 @@ class Item // If it is a posting where users should get notifications, then define it as wall posting if ($notify) { + /** @var array */ $item = $itemHelper->prepareOriginPost($item); if (is_int($notify) && in_array($notify, Worker::PRIORITIES)) { @@ -708,6 +709,7 @@ class Item $item['network'] = trim(($item['network'] ?? '') ?: Protocol::PHANTOM); } + /** @var array */ $item = $itemHelper->prepareItemData($item, (bool) $notify); // Store conversation data @@ -749,6 +751,7 @@ class Item } } + /** @var array */ $item = $itemHelper->validateItemData($item); // Ensure that there is an avatar cache @@ -846,6 +849,7 @@ class Item $dummy_session = false; } + /** @var array */ $item = $eventDispatcher->dispatch( new ArrayFilterEvent(ArrayFilterEvent::POST_LOCAL, $item) )->getArray(); @@ -3061,7 +3065,14 @@ class Item { $appHelper = DI::appHelper(); $uid = DI::userSession()->getLocalUserId(); - Hook::callAll('prepare_body_init', $item); + + $item_copy = $item; + + Hook::callAll('prepare_body_init', $item_copy); + + if (is_array($item_copy)) { + $item = $item_copy; + } // In order to provide theme developers more possibilities, event items // are treated differently. diff --git a/src/Model/Log/ParsedLogIterator.php b/src/Model/Log/ParsedLogIterator.php index 44c98462c1..58c8bddb77 100644 --- a/src/Model/Log/ParsedLogIterator.php +++ b/src/Model/Log/ParsedLogIterator.php @@ -21,7 +21,7 @@ class ParsedLogIterator implements \Iterator /** @var ReversedFileReader */ private $reader; - /** @var ParsedLogLine current iterator value*/ + /** @var ParsedLogLine|null current iterator value*/ private $value = null; /** @var int max number of lines to read */ diff --git a/src/Model/Photo.php b/src/Model/Photo.php index c275753960..74edaf360d 100644 --- a/src/Model/Photo.php +++ b/src/Model/Photo.php @@ -244,7 +244,7 @@ class Photo * * @param array $photo Photo data. Needs at least 'id', 'type', 'backend-class', 'backend-ref' * - * @return \Friendica\Object\Image|null Image object or null on error + * @return string|null Image data as string or null on error */ public static function getImageDataForPhoto(array $photo) { @@ -254,7 +254,7 @@ class Photo try { $backendClass = DI::storageManager()->getByName($photo['backend-class'] ?? ''); - /// @todo refactoring this returning, because the storage returns a "string" which is casted in different ways - a check "instanceof Image" will fail! + return $backendClass->get($photo['backend-ref'] ?? ''); } catch (InvalidClassStorageException $storageException) { try { @@ -834,10 +834,9 @@ class Photo * - Sharing a post with a group will create a photo that only the group can see. * - Sharing a photo again that been shared non public before doesn't alter the permissions. * - * @return string * @throws \Exception */ - public static function setPermissionFromBody($body, $uid, $original_contact_id, $str_contact_allow, $str_circle_allow, $str_contact_deny, $str_circle_deny) + public static function setPermissionFromBody($body, $uid, $original_contact_id, $str_contact_allow, $str_circle_allow, $str_contact_deny, $str_circle_deny): bool { // Simplify image codes $img_body = preg_replace("/\[img\=([0-9]*)x([0-9]*)\](.*?)\[\/img\]/ism", '[img]$3[/img]', $body); diff --git a/src/Model/Post/Delayed.php b/src/Model/Post/Delayed.php index e4862c27c2..b0c5d09dcd 100644 --- a/src/Model/Post/Delayed.php +++ b/src/Model/Post/Delayed.php @@ -170,9 +170,8 @@ class Delayed * @param array $attachments * @param int $preparation_mode * @param string $uri - * @return bool */ - public static function publish(array $item, int $notify = 0, array $taglist = [], array $attachments = [], int $preparation_mode = self::PREPARED, string $uri = '') + public static function publish(array $item, int $notify = 0, array $taglist = [], array $attachments = [], int $preparation_mode = self::PREPARED, string $uri = ''): int { if (!empty($attachments)) { $item['attachments'] = $attachments; From 6b7dfa34e96455405e7200d4ed5720886c47d5d1 Mon Sep 17 00:00:00 2001 From: Art4 Date: Wed, 5 Mar 2025 15:15:18 +0000 Subject: [PATCH 21/46] fix 7 PHPStan errors in factoriy and Model --- src/Factory/Api/Mastodon/Attachment.php | 23 ++++++++++++++++------- src/Factory/Api/Twitter/Status.php | 2 +- src/Federation/Repository/GServer.php | 4 +++- src/Model/Contact/User.php | 5 ++--- src/Model/Event.php | 2 +- src/Model/GServer.php | 4 +--- 6 files changed, 24 insertions(+), 16 deletions(-) diff --git a/src/Factory/Api/Mastodon/Attachment.php b/src/Factory/Api/Mastodon/Attachment.php index ae0ebf1826..52361284ac 100644 --- a/src/Factory/Api/Mastodon/Attachment.php +++ b/src/Factory/Api/Mastodon/Attachment.php @@ -11,7 +11,7 @@ use Friendica\App\BaseURL; use Friendica\BaseFactory; use Friendica\Model\Attach; use Friendica\Model\Photo; -use Friendica\Network\HTTPException; +use Friendica\Network\HTTPException\InternalServerErrorException; use Friendica\Model\Post; use Friendica\Util\Images; use Friendica\Util\Proxy; @@ -32,7 +32,7 @@ class Attachment extends BaseFactory /** * @param int $uriId Uri-ID of the attachments * @return array - * @throws HTTPException\InternalServerErrorException + * @throws InternalServerErrorException */ public function createFromUriId(int $uriId): array { @@ -47,21 +47,30 @@ class Attachment extends BaseFactory /** * @param int $id id of the media * @return \Friendica\Object\Api\Mastodon\Attachment - * @throws HTTPException\InternalServerErrorException + * @throws InternalServerErrorException */ public function createFromId(int $id): \Friendica\Object\Api\Mastodon\Attachment { $attachment = Post\Media::getById($id); + if (empty($attachment)) { - return []; + $attachment = [ + 'id' => '', + 'description' => '', + 'url' => '', + 'mimetype' => '', + 'blurhash' => '', + 'type' => Post\Media::UNKNOWN, + ]; } + return $this->createFromMediaArray($attachment); } /** * @param array $attachment * @return \Friendica\Object\Api\Mastodon\Attachment - * @throws HTTPException\InternalServerErrorException + * @throws InternalServerErrorException */ private function createFromMediaArray(array $attachment): \Friendica\Object\Api\Mastodon\Attachment { @@ -100,7 +109,7 @@ class Attachment extends BaseFactory * @param int $id id of the photo * * @return array - * @throws HTTPException\InternalServerErrorException + * @throws InternalServerErrorException */ public function createFromPhoto(int $id): array { @@ -136,7 +145,7 @@ class Attachment extends BaseFactory * @param int $id id of the attachment * * @return array - * @throws HTTPException\InternalServerErrorException + * @throws InternalServerErrorException */ public function createFromAttach(int $id): array { diff --git a/src/Factory/Api/Twitter/Status.php b/src/Factory/Api/Twitter/Status.php index b31a89fc44..c83b0aa9ab 100644 --- a/src/Factory/Api/Twitter/Status.php +++ b/src/Factory/Api/Twitter/Status.php @@ -39,7 +39,7 @@ class Status extends BaseFactory private $mention; /** @var Activities entity */ private $activities; - /** @var Activities entity */ + /** @var Attachment entity */ private $attachment; /** @var ContentItem */ private $contentItem; diff --git a/src/Federation/Repository/GServer.php b/src/Federation/Repository/GServer.php index 5a12f3339b..8e9c7e9449 100644 --- a/src/Federation/Repository/GServer.php +++ b/src/Federation/Repository/GServer.php @@ -28,6 +28,8 @@ class GServer extends \Friendica\BaseRepository */ public function selectOneById(int $gsid): Entity\GServer { - return $this->_selectOne(['id' => $gsid]); + $fields = $this->_selectFirstRowAsArray( ['id' => $gsid]); + + return $this->factory->createFromTableRow($fields); } } diff --git a/src/Model/Contact/User.php b/src/Model/Contact/User.php index 17663e233b..aa85013811 100644 --- a/src/Model/Contact/User.php +++ b/src/Model/Contact/User.php @@ -30,9 +30,8 @@ class User * Insert a user-contact for a given contact array * * @param array $contact - * @return void */ - public static function insertForContactArray(array $contact) + public static function insertForContactArray(array $contact): bool { if (empty($contact['uid'])) { // We don't create entries for the public user - by now @@ -339,7 +338,7 @@ class User { $pcid = Contact::getPublicContactId($cid, $uid); if (!$pcid) { - return false; + return self::FREQUENCY_DEFAULT; } $public_contact = DBA::selectFirst('user-contact', ['channel-frequency'], ['cid' => $pcid, 'uid' => $uid]); diff --git a/src/Model/Event.php b/src/Model/Event.php index 6cb73f4c37..39aba01efd 100644 --- a/src/Model/Event.php +++ b/src/Model/Event.php @@ -305,7 +305,7 @@ class Event Hook::callAll("event_created", $event['id']); } - return $event['id']; + return (int) $event['id']; } public static function getItemArrayForId(int $event_id, array $item = []): array diff --git a/src/Model/GServer.php b/src/Model/GServer.php index 7029adbb53..8ead599408 100644 --- a/src/Model/GServer.php +++ b/src/Model/GServer.php @@ -2200,8 +2200,6 @@ class GServer * Converts input value to a boolean value * * @param string|integer $val - * - * @return boolean */ private static function toBoolean($val): bool { @@ -2211,7 +2209,7 @@ class GServer return false; } - return $val; + return (bool) $val; } /** From 77831aaf49770ed868d0d952caea4e15d3d2d642 Mon Sep 17 00:00:00 2001 From: Art4 Date: Thu, 6 Mar 2025 09:25:39 +0000 Subject: [PATCH 22/46] Handle missing attachment with correct response --- src/Factory/Api/Mastodon/Attachment.php | 9 +-------- src/Module/Api/Mastodon/Media.php | 13 ++++++++++++- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/src/Factory/Api/Mastodon/Attachment.php b/src/Factory/Api/Mastodon/Attachment.php index 52361284ac..bd16b61b38 100644 --- a/src/Factory/Api/Mastodon/Attachment.php +++ b/src/Factory/Api/Mastodon/Attachment.php @@ -54,14 +54,7 @@ class Attachment extends BaseFactory $attachment = Post\Media::getById($id); if (empty($attachment)) { - $attachment = [ - 'id' => '', - 'description' => '', - 'url' => '', - 'mimetype' => '', - 'blurhash' => '', - 'type' => Post\Media::UNKNOWN, - ]; + throw new InternalServerErrorException(); } return $this->createFromMediaArray($attachment); diff --git a/src/Module/Api/Mastodon/Media.php b/src/Module/Api/Mastodon/Media.php index 5dbcfc3687..f9d61e0db3 100644 --- a/src/Module/Api/Mastodon/Media.php +++ b/src/Module/Api/Mastodon/Media.php @@ -13,6 +13,7 @@ use Friendica\Model\Contact; use Friendica\Model\Photo; use Friendica\Model\Post; use Friendica\Module\BaseApi; +use Friendica\Network\HTTPException\InternalServerErrorException; use Friendica\Util\Strings; /** @@ -97,14 +98,24 @@ class Media extends BaseApi $photo = Photo::selectFirst(['resource-id'], ['id' => $this->parameters['id'], 'uid' => $uid]); if (empty($photo['resource-id'])) { $media = Post\Media::getById($this->parameters['id']); + if (empty($media['uri-id'])) { $this->logAndJsonError(404, $this->errorFactory->RecordNotFound()); } + if (!Post::exists(['uri-id' => $media['uri-id'], 'uid' => $uid, 'origin' => true])) { $this->logAndJsonError(404, $this->errorFactory->RecordNotFound()); } + Post\Media::updateById(['description' => $request['description']], $this->parameters['id']); - $this->jsonExit(DI::mstdnAttachment()->createFromId($this->parameters['id'])); + + try { + $attachment = DI::mstdnAttachment()->createFromId($this->parameters['id'] . '1'); + } catch (InternalServerErrorException $th) { + $this->logAndJsonError(404, $this->errorFactory->RecordNotFound()); + } + + $this->jsonExit($attachment); } Photo::update(['desc' => $request['description']], ['resource-id' => $photo['resource-id']]); From 39754918877405d8607430374e69c0a79ae566ee Mon Sep 17 00:00:00 2001 From: Art4 Date: Thu, 6 Mar 2025 11:57:29 +0000 Subject: [PATCH 23/46] Fix upload error handling for media see https://github.com/friendica/friendica/pull/14475 refs #14475 --- src/Module/Api/Mastodon/Media.php | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/Module/Api/Mastodon/Media.php b/src/Module/Api/Mastodon/Media.php index f9d61e0db3..df6c521008 100644 --- a/src/Module/Api/Mastodon/Media.php +++ b/src/Module/Api/Mastodon/Media.php @@ -44,12 +44,13 @@ class Media extends BaseApi if (in_array($type, [Post\Media::IMAGE, Post\Media::UNKNOWN, Post\Media::APPLICATION])) { $media = Photo::upload($uid, $request['file'], '', null, null, '', '', $request['description']); - if (!empty($media)) { - $this->logger->info('Uploaded photo', ['media' => $media]); - $this->jsonExit(DI::mstdnAttachment()->createFromPhoto($media['id'])); - } elseif ($type == Post\Media::IMAGE) { - $this->jsonExit(DI::mstdnAttachment()->createFromPhoto($media['id'])); + + if (empty($media)) { + $this->logAndJsonError(500, $this->errorFactory->InternalError('Error while uploading media.')); } + + $this->logger->info('Uploaded photo', ['media' => $media]); + $this->jsonExit(DI::mstdnAttachment()->createFromPhoto($media['id'])); } $tempFileName = $request['file']['tmp_name']; From eb37bcaa74903edb72665b69ef02a6d0beba66d1 Mon Sep 17 00:00:00 2001 From: Art4 Date: Fri, 7 Mar 2025 10:50:15 +0000 Subject: [PATCH 24/46] Change 500 response to 422 response see https://github.com/friendica/friendica/pull/14475 --- src/Module/Api/Mastodon/Media.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Module/Api/Mastodon/Media.php b/src/Module/Api/Mastodon/Media.php index df6c521008..31ab33c527 100644 --- a/src/Module/Api/Mastodon/Media.php +++ b/src/Module/Api/Mastodon/Media.php @@ -46,7 +46,7 @@ class Media extends BaseApi $media = Photo::upload($uid, $request['file'], '', null, null, '', '', $request['description']); if (empty($media)) { - $this->logAndJsonError(500, $this->errorFactory->InternalError('Error while uploading media.')); + $this->logAndJsonError(422, $this->errorFactory->UnprocessableEntity('Error while uploading media.')); } $this->logger->info('Uploaded photo', ['media' => $media]); From 38343ee417bd1cf4f37d76e13c59779451e8d12f Mon Sep 17 00:00:00 2001 From: Art4 Date: Fri, 7 Mar 2025 13:46:18 +0000 Subject: [PATCH 25/46] Refactor GServer Repository --- src/Federation/Repository/GServer.php | 29 +++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/src/Federation/Repository/GServer.php b/src/Federation/Repository/GServer.php index 8e9c7e9449..d9d7772582 100644 --- a/src/Federation/Repository/GServer.php +++ b/src/Federation/Repository/GServer.php @@ -8,27 +8,40 @@ namespace Friendica\Federation\Repository; use Friendica\Database\Database; -use Friendica\Federation\Factory; -use Friendica\Federation\Entity; +use Friendica\Federation\Entity\GServer as GServerEntity; +use Friendica\Federation\Factory\GServer as GServerFactory; +use Friendica\Network\HTTPException\NotFoundException; use Psr\Log\LoggerInterface; -class GServer extends \Friendica\BaseRepository +final class GServer { protected static $table_name = 'gserver'; - public function __construct(Database $database, LoggerInterface $logger, Factory\GServer $factory) + protected Database $db; + + protected LoggerInterface $logger; + + protected GServerFactory $factory; + + public function __construct(Database $database, LoggerInterface $logger, GServerFactory $factory) { - parent::__construct($database, $logger, $factory); + $this->db = $database; + $this->logger = $logger; + $this->factory = $factory; } /** * @param int $gsid - * @return Entity\GServer + * * @throws \Friendica\Network\HTTPException\NotFoundException */ - public function selectOneById(int $gsid): Entity\GServer + public function selectOneById(int $gsid): GServerEntity { - $fields = $this->_selectFirstRowAsArray( ['id' => $gsid]); + $fields = $this->db->selectFirst(static::$table_name, [], ['id' => $gsid], []); + + if (!$this->db->isResult($fields)) { + throw new NotFoundException(); + } return $this->factory->createFromTableRow($fields); } From 767ac778c96eebc048a30a939b66d2e257cb1a82 Mon Sep 17 00:00:00 2001 From: Art4 Date: Fri, 7 Mar 2025 13:49:22 +0000 Subject: [PATCH 26/46] simplify GServer repository --- src/Federation/Repository/GServer.php | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/src/Federation/Repository/GServer.php b/src/Federation/Repository/GServer.php index d9d7772582..d299210800 100644 --- a/src/Federation/Repository/GServer.php +++ b/src/Federation/Repository/GServer.php @@ -11,22 +11,18 @@ use Friendica\Database\Database; use Friendica\Federation\Entity\GServer as GServerEntity; use Friendica\Federation\Factory\GServer as GServerFactory; use Friendica\Network\HTTPException\NotFoundException; -use Psr\Log\LoggerInterface; final class GServer { - protected static $table_name = 'gserver'; + private string $table_name = 'gserver'; - protected Database $db; + private Database $db; - protected LoggerInterface $logger; + private GServerFactory $factory; - protected GServerFactory $factory; - - public function __construct(Database $database, LoggerInterface $logger, GServerFactory $factory) + public function __construct(Database $database, GServerFactory $factory) { $this->db = $database; - $this->logger = $logger; $this->factory = $factory; } @@ -37,7 +33,7 @@ final class GServer */ public function selectOneById(int $gsid): GServerEntity { - $fields = $this->db->selectFirst(static::$table_name, [], ['id' => $gsid], []); + $fields = $this->db->selectFirst($this->table_name, [], ['id' => $gsid], []); if (!$this->db->isResult($fields)) { throw new NotFoundException(); From bf530a00d7fe363b36c3e4727cb8cdb2c221b8a7 Mon Sep 17 00:00:00 2001 From: Art4 Date: Wed, 12 Mar 2025 15:02:50 +0000 Subject: [PATCH 27/46] Fix 2 PHPStan errors --- src/Factory/Api/Twitter/Status.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Factory/Api/Twitter/Status.php b/src/Factory/Api/Twitter/Status.php index c83b0aa9ab..b77ee801f7 100644 --- a/src/Factory/Api/Twitter/Status.php +++ b/src/Factory/Api/Twitter/Status.php @@ -165,7 +165,7 @@ class Status extends BaseFactory $urls = $this->url->createFromUriId($item['uri-id']); $mentions = $this->mention->createFromUriId($item['uri-id']); } else { - $attachments = $this->attachment->createFromUriId($item['uri-id'], $text); + $attachments = $this->attachment->createFromUriId($item['uri-id']); } $friendica_activities = $this->activities->createFromUriId($item['uri-id'], $uid); @@ -180,7 +180,7 @@ class Status extends BaseFactory $urls = array_merge($urls, $this->url->createFromUriId($shared_uri_id)); $mentions = array_merge($mentions, $this->mention->createFromUriId($shared_uri_id)); } else { - $attachments = array_merge($attachments, $this->attachment->createFromUriId($shared_uri_id, $text)); + $attachments = array_merge($attachments, $this->attachment->createFromUriId($shared_uri_id)); } } From a50383836d0bbbf87b695be8e1511222bc71d897 Mon Sep 17 00:00:00 2001 From: Art4 Date: Wed, 12 Mar 2025 15:03:15 +0000 Subject: [PATCH 28/46] Fix 13 PHPStan errors --- src/Database/Database.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Database/Database.php b/src/Database/Database.php index 14416a1899..6f42756302 100644 --- a/src/Database/Database.php +++ b/src/Database/Database.php @@ -60,7 +60,7 @@ class Database protected $syslock = null; protected $server_info = ''; - /** @var PDO|mysqli */ + /** @var PDO|mysqli|null */ protected $connection; protected $driver = ''; protected $pdo_emulate_prepares = false; @@ -253,7 +253,7 @@ class Database /** * Return the database object. * - * @return PDO|mysqli + * @return PDO|mysqli|null */ public function getConnection() { From 268d564930d3974607aa1c14f38a9baf43b50817 Mon Sep 17 00:00:00 2001 From: Art4 Date: Wed, 12 Mar 2025 15:50:24 +0000 Subject: [PATCH 29/46] remove deprecation of BaseCollection::map(), check return type of BaseCollection::map() --- src/BaseCollection.php | 4 -- .../Collection/Notifications.php | 45 ++++++++++--------- .../Notifications/Collection/Notifies.php | 20 ++++++--- .../ProfileField/Collection/ProfileFields.php | 17 ++++--- 4 files changed, 50 insertions(+), 36 deletions(-) diff --git a/src/BaseCollection.php b/src/BaseCollection.php index 36c6b9a63e..b30dbfc6b0 100644 --- a/src/BaseCollection.php +++ b/src/BaseCollection.php @@ -83,16 +83,12 @@ class BaseCollection extends \ArrayIterator /** * Apply a callback function on all elements in the collection and returns a new collection with the updated elements * - * @deprecated 2025.05 Use `array_map()` instead - * * @param callable $callback * @return BaseCollection * @see array_map() */ public function map(callable $callback): BaseCollection { - @trigger_error('`' . __METHOD__ . '()` is deprecated since 2025.05 and will be removed after 5 months, use `array_map()` instead.', E_USER_DEPRECATED); - $class = get_class($this); return new $class(array_map($callback, $this->getArrayCopy()), $this->getTotalCount()); diff --git a/src/Navigation/Notifications/Collection/Notifications.php b/src/Navigation/Notifications/Collection/Notifications.php index 4c32cf598b..e422283891 100644 --- a/src/Navigation/Notifications/Collection/Notifications.php +++ b/src/Navigation/Notifications/Collection/Notifications.php @@ -19,33 +19,38 @@ class Notifications extends BaseCollection public function setSeen(): Notifications { - $class = get_class($this); + $notifications = $this->map(function (NotificationEntity $notification) { + $notification->setSeen(); + }); - return new $class( - array_map( - function (NotificationEntity $notification) { - $notification->setSeen(); - }, - $this->getArrayCopy() - ), - $this->getTotalCount(), - ); + if (!$notifications instanceof Notifications) { + // Show the possible error explicitly + throw new \Exception(sprintf( + 'BaseCollection::map() should return instance of %s, but returns %s instead.', + Notifications::class, + get_class($notifications), + )); + } + + return $notifications; } public function setDismissed(): Notifications { - $class = get_class($this); + $notifications = $this->map(function (NotificationEntity $notification) { + $notification->setDismissed(); + }); - return new $class( - array_map( - function (NotificationEntity $notification) { - $notification->setDismissed(); - }, - $this->getArrayCopy(), - ), - $this->getTotalCount(), - ); + if (!$notifications instanceof Notifications) { + // Show the possible error explicitly + throw new \Exception(sprintf( + 'BaseCollection::map() should return instance of %s, but returns %s instead.', + Notifications::class, + get_class($notifications), + )); + } + return $notifications; } public function countUnseen(): int diff --git a/src/Navigation/Notifications/Collection/Notifies.php b/src/Navigation/Notifications/Collection/Notifies.php index fc97880de3..9c2f5dcc74 100644 --- a/src/Navigation/Notifications/Collection/Notifies.php +++ b/src/Navigation/Notifications/Collection/Notifies.php @@ -19,13 +19,19 @@ class Notifies extends BaseCollection public function setSeen(): Notifies { - $class = get_class($this); + $notifies = $this->map(function (NotifyEntity $notify) { + $notify->setSeen(); + }); - return new $class(array_map( - function (NotifyEntity $notify) { - $notify->setSeen(); - }, - $this->getArrayCopy()), $this->getTotalCount(), - ); + if (!$notifies instanceof Notifies) { + // Show the possible error explicitly + throw new \Exception(sprintf( + 'BaseCollection::map() should return instance of %s, but returns %s instead.', + Notifies::class, + get_class($notifies), + )); + } + + return $notifies; } } diff --git a/src/Profile/ProfileField/Collection/ProfileFields.php b/src/Profile/ProfileField/Collection/ProfileFields.php index dcf5498df3..44f13673d7 100644 --- a/src/Profile/ProfileField/Collection/ProfileFields.php +++ b/src/Profile/ProfileField/Collection/ProfileFields.php @@ -19,15 +19,22 @@ class ProfileFields extends BaseCollection public function map(callable $callback): ProfileFields { - $class = get_class($this); + $profileFields = parent::map($callback); - return new $class(array_map($callback, $this->getArrayCopy()), $this->getTotalCount()); + if (!$profileFields instanceof ProfileFields) { + // Show the possible error explicitly + throw new \Exception(sprintf( + 'BaseCollection::map() should return instance of %s, but returns %s instead.', + ProfileFields::class, + get_class($profileFields), + )); + } + + return $profileFields; } public function filter(?callable $callback = null, int $flag = 0): ProfileFields { - $class = get_class($this); - - return new $class(array_filter($this->getArrayCopy(), $callback, $flag)); + return new self(array_filter($this->getArrayCopy(), $callback, $flag)); } } From 7ce6afd1517f136f2b3796aad9ce36a096c66125 Mon Sep 17 00:00:00 2001 From: Art4 Date: Thu, 13 Mar 2025 09:14:48 +0000 Subject: [PATCH 30/46] Fix 10 PHPStan errors --- src/BaseCollection.php | 18 +++--- .../Repository/FriendSuggest.php | 33 ++++------- .../Introduction/Repository/Introduction.php | 58 +++++------------- .../Repository/LocalRelationship.php | 59 ++++++++----------- .../Repository/UserDefinedChannel.php | 26 ++++---- src/Content/Post/Entity/PostMedia.php | 3 +- src/Content/Post/Factory/PostMedia.php | 29 ++++----- src/Content/Post/Repository/PostMedia.php | 42 +++++++------ src/Core/Worker/Repository/Process.php | 21 +++---- 9 files changed, 122 insertions(+), 167 deletions(-) diff --git a/src/BaseCollection.php b/src/BaseCollection.php index b30dbfc6b0..d7d707960a 100644 --- a/src/BaseCollection.php +++ b/src/BaseCollection.php @@ -24,7 +24,7 @@ class BaseCollection extends \ArrayIterator * @param BaseEntity[] $entities * @param int|null $totalCount */ - public function __construct(array $entities = [], int $totalCount = null) + public function __construct(array $entities = [], ?int $totalCount = null) { parent::__construct($entities); @@ -102,7 +102,7 @@ class BaseCollection extends \ArrayIterator * @return BaseCollection * @see array_filter() */ - public function filter(callable $callback = null, int $flag = 0): BaseCollection + public function filter(?callable $callback = null, int $flag = 0): BaseCollection { $class = get_class($this); @@ -111,8 +111,6 @@ class BaseCollection extends \ArrayIterator /** * Reverse the orders of the elements in the collection - * - * @return $this */ public function reverse(): BaseCollection { @@ -125,7 +123,6 @@ class BaseCollection extends \ArrayIterator * Split the collection in smaller collections no bigger than the provided length * * @param int $length - * @return static[] */ public function chunk(int $length): array { @@ -133,11 +130,14 @@ class BaseCollection extends \ArrayIterator throw new \RangeException('BaseCollection->chunk(): Size parameter expected to be greater than 0'); } - return array_map(function ($array) { - $class = get_class($this); + return array_map( + function ($array) { + $class = get_class($this); - return new $class($array); - }, array_chunk($this->getArrayCopy(), $length)); + return new $class($array); + }, + array_chunk($this->getArrayCopy(), $length) + ); } diff --git a/src/Contact/FriendSuggest/Repository/FriendSuggest.php b/src/Contact/FriendSuggest/Repository/FriendSuggest.php index 1b22c7b797..a9f4610439 100644 --- a/src/Contact/FriendSuggest/Repository/FriendSuggest.php +++ b/src/Contact/FriendSuggest/Repository/FriendSuggest.php @@ -8,11 +8,11 @@ namespace Friendica\Contact\FriendSuggest\Repository; use Friendica\BaseRepository; -use Friendica\Contact\FriendSuggest\Collection; +use Friendica\Contact\FriendSuggest\Collection\FriendSuggests as FriendSuggestsCollection; use Friendica\Contact\FriendSuggest\Entity\FriendSuggest as FriendSuggestEntity; use Friendica\Contact\FriendSuggest\Exception\FriendSuggestNotFoundException; use Friendica\Contact\FriendSuggest\Exception\FriendSuggestPersistenceException; -use Friendica\Contact\FriendSuggest\Factory; +use Friendica\Contact\FriendSuggest\Factory\FriendSuggest as FriendSuggestFactory; use Friendica\Database\Database; use Friendica\Network\HTTPException\NotFoundException; use Friendica\Util\DateTimeFormat; @@ -20,12 +20,12 @@ use Psr\Log\LoggerInterface; class FriendSuggest extends BaseRepository { - /** @var Factory\FriendSuggest */ + /** @var FriendSuggestFactory */ protected $factory; protected static $table_name = 'fsuggest'; - public function __construct(Database $database, LoggerInterface $logger, Factory\FriendSuggest $factory) + public function __construct(Database $database, LoggerInterface $logger, FriendSuggestFactory $factory) { parent::__construct($database, $logger, $factory); } @@ -49,20 +49,17 @@ class FriendSuggest extends BaseRepository */ private function selectOne(array $condition, array $params = []): FriendSuggestEntity { - return parent::_selectOne($condition, $params); + $fields = $this->_selectFirstRowAsArray( $condition, $params); + + return $this->factory->createFromTableRow($fields); } /** - * @param array $condition - * @param array $params - * - * @return Collection\FriendSuggests - * * @throws \Exception */ - private function select(array $condition, array $params = []): Collection\FriendSuggests + private function select(array $condition, array $params = []): FriendSuggestsCollection { - return new Collection\FriendSuggests(parent::_select($condition, $params)->getArrayCopy()); + return new FriendSuggestsCollection(parent::_select($condition, $params)->getArrayCopy()); } /** @@ -78,13 +75,9 @@ class FriendSuggest extends BaseRepository } /** - * @param int $cid - * - * @return Collection\FriendSuggests - * * @throws FriendSuggestPersistenceException In case the underlying storage cannot select the suggestion */ - public function selectForContact(int $cid): Collection\FriendSuggests + public function selectForContact(int $cid): FriendSuggestsCollection { try { return $this->select(['cid' => $cid]); @@ -114,13 +107,9 @@ class FriendSuggest extends BaseRepository } /** - * @param Collection\FriendSuggests $fsuggests - * - * @return bool - * * @throws FriendSuggestNotFoundException in case the underlying storage cannot delete the suggestion */ - public function delete(Collection\FriendSuggests $fsuggests): bool + public function delete(FriendSuggestsCollection $fsuggests): bool { try { $ids = $fsuggests->column('id'); diff --git a/src/Contact/Introduction/Repository/Introduction.php b/src/Contact/Introduction/Repository/Introduction.php index 562b3c472f..dec2f2a246 100644 --- a/src/Contact/Introduction/Repository/Introduction.php +++ b/src/Contact/Introduction/Repository/Introduction.php @@ -10,9 +10,9 @@ namespace Friendica\Contact\Introduction\Repository; use Friendica\BaseRepository; use Friendica\Contact\Introduction\Exception\IntroductionNotFoundException; use Friendica\Contact\Introduction\Exception\IntroductionPersistenceException; -use Friendica\Contact\Introduction\Collection; -use Friendica\Contact\Introduction\Entity; -use Friendica\Contact\Introduction\Factory; +use Friendica\Contact\Introduction\Collection\Introductions as IntroductionsCollection; +use Friendica\Contact\Introduction\Entity\Introduction as IntroductionEntity; +use Friendica\Contact\Introduction\Factory\Introduction as IntroductionFactory; use Friendica\Database\Database; use Friendica\Network\HTTPException\NotFoundException; use Friendica\Util\DateTimeFormat; @@ -20,37 +20,30 @@ use Psr\Log\LoggerInterface; class Introduction extends BaseRepository { - /** @var Factory\Introduction */ + /** @var IntroductionFactory */ protected $factory; protected static $table_name = 'intro'; - public function __construct(Database $database, LoggerInterface $logger, Factory\Introduction $factory) + public function __construct(Database $database, LoggerInterface $logger, IntroductionFactory $factory) { parent::__construct($database, $logger, $factory); } /** - * @param array $condition - * @param array $params - * - * @return Entity\Introduction - * * @throws NotFoundException the underlying exception if there's no Introduction with the given conditions */ - private function selectOne(array $condition, array $params = []): Entity\Introduction + private function selectOne(array $condition, array $params = []): IntroductionEntity { - return parent::_selectOne($condition, $params); + $fields = $this->_selectFirstRowAsArray( $condition, $params); + + return $this->factory->createFromTableRow($fields); } /** * Converts a given Introduction into a DB compatible row array - * - * @param Entity\Introduction $introduction - * - * @return array */ - protected function convertToTableRow(Entity\Introduction $introduction): array + protected function convertToTableRow(IntroductionEntity $introduction): array { return [ 'uid' => $introduction->uid, @@ -65,14 +58,9 @@ class Introduction extends BaseRepository } /** - * @param int $id - * @param int $uid - * - * @return Entity\Introduction - * * @throws IntroductionNotFoundException in case there is no Introduction with this id */ - public function selectOneById(int $id, int $uid): Entity\Introduction + public function selectOneById(int $id, int $uid): IntroductionEntity { try { return $this->selectOne(['id' => $id, 'uid' => $uid]); @@ -88,10 +76,8 @@ class Introduction extends BaseRepository * @param int|null $min_id * @param int|null $max_id * @param int $limit - * - * @return Collection\Introductions */ - public function selectForUser(int $uid, int $min_id = null, int $max_id = null, int $limit = self::LIMIT): Collection\Introductions + public function selectForUser(int $uid, ?int $min_id = null, ?int $max_id = null, int $limit = self::LIMIT): IntroductionsCollection { try { $BaseCollection = parent::_selectByBoundaries( @@ -102,19 +88,15 @@ class Introduction extends BaseRepository throw new IntroductionPersistenceException(sprintf('Cannot select Introductions for used %d', $uid), $e); } - return new Collection\Introductions($BaseCollection->getArrayCopy(), $BaseCollection->getTotalCount()); + return new IntroductionsCollection($BaseCollection->getArrayCopy(), $BaseCollection->getTotalCount()); } /** * Selects the introduction for a given contact * - * @param int $cid - * - * @return Entity\Introduction - * * @throws IntroductionNotFoundException in case there is not Introduction for this contact */ - public function selectForContact(int $cid): Entity\Introduction + public function selectForContact(int $cid): IntroductionEntity { try { return $this->selectOne(['contact-id' => $cid]); @@ -150,13 +132,9 @@ class Introduction extends BaseRepository } /** - * @param Entity\Introduction $introduction - * - * @return bool - * * @throws IntroductionPersistenceException in case the underlying storage cannot delete the Introduction */ - public function delete(Entity\Introduction $introduction): bool + public function delete(IntroductionEntity $introduction): bool { if (!$introduction->id) { return false; @@ -170,13 +148,9 @@ class Introduction extends BaseRepository } /** - * @param Entity\Introduction $introduction - * - * @return Entity\Introduction - * * @throws IntroductionPersistenceException In case the underlying storage cannot save the Introduction */ - public function save(Entity\Introduction $introduction): Entity\Introduction + public function save(IntroductionEntity $introduction): IntroductionEntity { try { $fields = $this->convertToTableRow($introduction); diff --git a/src/Contact/LocalRelationship/Repository/LocalRelationship.php b/src/Contact/LocalRelationship/Repository/LocalRelationship.php index 2b9abc3dfc..f00002a066 100644 --- a/src/Contact/LocalRelationship/Repository/LocalRelationship.php +++ b/src/Contact/LocalRelationship/Repository/LocalRelationship.php @@ -7,59 +7,54 @@ namespace Friendica\Contact\LocalRelationship\Repository; -use Friendica\Contact\LocalRelationship\Entity; -use Friendica\Contact\LocalRelationship\Exception; -use Friendica\Contact\LocalRelationship\Factory; +use Exception; +use Friendica\BaseRepository; +use Friendica\Contact\LocalRelationship\Entity\LocalRelationship as LocalRelationshipEntity; +use Friendica\Contact\LocalRelationship\Exception\LocalRelationshipPersistenceException; +use Friendica\Contact\LocalRelationship\Factory\LocalRelationship as LocalRelationshipFactory; use Friendica\Database\Database; -use Friendica\Network\HTTPException; +use Friendica\Network\HTTPException\NotFoundException; use Psr\Log\LoggerInterface; -class LocalRelationship extends \Friendica\BaseRepository +class LocalRelationship extends BaseRepository { protected static $table_name = 'user-contact'; - /** @var Factory\LocalRelationship */ + /** @var LocalRelationshipFactory */ protected $factory; - public function __construct(Database $database, LoggerInterface $logger, Factory\LocalRelationship $factory) + public function __construct(Database $database, LoggerInterface $logger, LocalRelationshipFactory $factory) { parent::__construct($database, $logger, $factory); } /** - * @param int $uid - * @param int $cid - * @return Entity\LocalRelationship - * @throws HTTPException\NotFoundException + * @throws NotFoundException */ - public function selectForUserContact(int $uid, int $cid): Entity\LocalRelationship + public function selectForUserContact(int $uid, int $cid): LocalRelationshipEntity { - return $this->_selectOne(['uid' => $uid, 'cid' => $cid]); + $fields = $this->_selectFirstRowAsArray( ['uid' => $uid, 'cid' => $cid]); + + return $this->factory->createFromTableRow($fields); } /** * Returns the existing local relationship between a user and a public contact or a default * relationship if it doesn't. * - * @param int $uid - * @param int $cid - * @return Entity\LocalRelationship - * @throws HTTPException\NotFoundException + * @throws NotFoundException */ - public function getForUserContact(int $uid, int $cid): Entity\LocalRelationship + public function getForUserContact(int $uid, int $cid): LocalRelationshipEntity { try { return $this->selectForUserContact($uid, $cid); - } catch (HTTPException\NotFoundException $e) { + } catch (NotFoundException $e) { return $this->factory->createFromTableRow(['uid' => $uid, 'cid' => $cid]); } } /** - * @param int $uid - * @param int $cid - * @return bool - * @throws \Exception + * @throws Exception */ public function existsForUserContact(int $uid, int $cid): bool { @@ -68,12 +63,8 @@ class LocalRelationship extends \Friendica\BaseRepository /** * Converts a given local relationship into a DB compatible row array - * - * @param Entity\LocalRelationship $localRelationship - * - * @return array */ - protected function convertToTableRow(Entity\LocalRelationship $localRelationship): array + protected function convertToTableRow(LocalRelationshipEntity $localRelationship): array { return [ 'uid' => $localRelationship->userId, @@ -97,13 +88,9 @@ class LocalRelationship extends \Friendica\BaseRepository } /** - * @param Entity\LocalRelationship $localRelationship - * - * @return Entity\LocalRelationship - * - * @throws Exception\LocalRelationshipPersistenceException In case the underlying storage cannot save the LocalRelationship + * @throws LocalRelationshipPersistenceException In case the underlying storage cannot save the LocalRelationship */ - public function save(Entity\LocalRelationship $localRelationship): Entity\LocalRelationship + public function save(LocalRelationshipEntity $localRelationship): LocalRelationshipEntity { try { $fields = $this->convertToTableRow($localRelationship); @@ -111,8 +98,8 @@ class LocalRelationship extends \Friendica\BaseRepository $this->db->insert(self::$table_name, $fields, Database::INSERT_UPDATE); return $localRelationship; - } catch (\Exception $exception) { - throw new Exception\LocalRelationshipPersistenceException(sprintf('Cannot insert/update the local relationship %d for user %d', $localRelationship->contactId, $localRelationship->userId), $exception); + } catch (Exception $exception) { + throw new LocalRelationshipPersistenceException(sprintf('Cannot insert/update the local relationship %d for user %d', $localRelationship->contactId, $localRelationship->userId), $exception); } } } diff --git a/src/Content/Conversation/Repository/UserDefinedChannel.php b/src/Content/Conversation/Repository/UserDefinedChannel.php index 229ef8e40c..65b29d0c94 100644 --- a/src/Content/Conversation/Repository/UserDefinedChannel.php +++ b/src/Content/Conversation/Repository/UserDefinedChannel.php @@ -7,10 +7,10 @@ namespace Friendica\Content\Conversation\Repository; -use Friendica\BaseCollection; +use Friendica\BaseRepository; use Friendica\Content\Conversation\Collection\UserDefinedChannels; -use Friendica\Content\Conversation\Entity; -use Friendica\Content\Conversation\Factory; +use Friendica\Content\Conversation\Entity\UserDefinedChannel as UserDefinedChannelEntity; +use Friendica\Content\Conversation\Factory\UserDefinedChannel as UserDefinedChannelFactory; use Friendica\Core\Config\Capability\IManageConfigValues; use Friendica\Database\Database; use Friendica\Database\DBA; @@ -21,13 +21,16 @@ use Friendica\Model\User; use Friendica\Util\DateTimeFormat; use Psr\Log\LoggerInterface; -class UserDefinedChannel extends \Friendica\BaseRepository +class UserDefinedChannel extends BaseRepository { protected static $table_name = 'channel'; + /** @var UserDefinedChannelFactory */ + protected $factory; + private IManageConfigValues $config; - public function __construct(Database $database, LoggerInterface $logger, Factory\UserDefinedChannel $factory, IManageConfigValues $config) + public function __construct(Database $database, LoggerInterface $logger, UserDefinedChannelFactory $factory, IManageConfigValues $config) { parent::__construct($database, $logger, $factory); @@ -40,7 +43,7 @@ class UserDefinedChannel extends \Friendica\BaseRepository * @return UserDefinedChannels * @throws \Exception */ - protected function _select(array $condition, array $params = []): BaseCollection + protected function _select(array $condition, array $params = []): UserDefinedChannels { $rows = $this->db->selectToArray(static::$table_name, [], $condition, $params); @@ -62,12 +65,13 @@ class UserDefinedChannel extends \Friendica\BaseRepository * * @param int $id The id of the user defined channel * @param int $uid The user that this channel belongs to. (Not part of the primary key) - * @return Entity\UserDefinedChannel * @throws \Friendica\Network\HTTPException\NotFoundException */ - public function selectById(int $id, int $uid): Entity\UserDefinedChannel + public function selectById(int $id, int $uid): UserDefinedChannelEntity { - return $this->_selectOne(['id' => $id, 'uid' => $uid]); + $fields = $this->_selectFirstRowAsArray( ['id' => $id, 'uid' => $uid]); + + return $this->factory->createFromTableRow($fields); } /** @@ -106,7 +110,7 @@ class UserDefinedChannel extends \Friendica\BaseRepository return $this->_select(['uid' => $uid]); } - public function save(Entity\UserDefinedChannel $Channel): Entity\UserDefinedChannel + public function save(UserDefinedChannelEntity $Channel): UserDefinedChannelEntity { $fields = [ 'label' => $Channel->label, @@ -210,7 +214,7 @@ class UserDefinedChannel extends \Friendica\BaseRepository $disposableFullTextSearch = new DisposableFullTextSearch($this->db, $searchtext); $filteredChannels = $this->select(['uid' => array_column($users, 'uid'), 'publish' => true, 'valid' => true])->filter( - function (Entity\UserDefinedChannel $channel) use ($owner_id, $reshare_id, $language, $tags, $media_type, $disposableFullTextSearch, $searchtext) { + function (UserDefinedChannelEntity $channel) use ($owner_id, $reshare_id, $language, $tags, $media_type, $disposableFullTextSearch, $searchtext) { static $uids = []; // Filter out channels from already picked users diff --git a/src/Content/Post/Entity/PostMedia.php b/src/Content/Post/Entity/PostMedia.php index 4b4268b750..59d1ec9c57 100644 --- a/src/Content/Post/Entity/PostMedia.php +++ b/src/Content/Post/Entity/PostMedia.php @@ -13,7 +13,6 @@ use Friendica\Util\Images; use Friendica\Util\Proxy; use Psr\Http\Message\UriInterface; - /** * @property-read int $id * @property-read int $uriId @@ -210,7 +209,7 @@ class PostMedia extends BaseEntity * * @param \GuzzleHttp\Psr7\Uri $preview * @param string $size - * @return $this + * @return self */ public function withPreview(\GuzzleHttp\Psr7\Uri $preview, string $size = ''): self { diff --git a/src/Content/Post/Factory/PostMedia.php b/src/Content/Post/Factory/PostMedia.php index 0dbfeb4896..1ebedda72e 100644 --- a/src/Content/Post/Factory/PostMedia.php +++ b/src/Content/Post/Factory/PostMedia.php @@ -9,8 +9,9 @@ namespace Friendica\Content\Post\Factory; use Friendica\BaseFactory; use Friendica\Capabilities\ICanCreateFromTableRow; -use Friendica\Content\Post\Entity; -use Friendica\Network; +use Friendica\Content\Post\Entity\PostMedia as PostMediaEntity; +use Friendica\Network\Entity\MimeType as MimeTypeEntity; +use Friendica\Network\Factory\MimeType as MimeTypeFactory; use Friendica\Util\Network as UtilNetwork; use GuzzleHttp\Psr7\Uri; use Psr\Log\LoggerInterface; @@ -18,10 +19,10 @@ use stdClass; class PostMedia extends BaseFactory implements ICanCreateFromTableRow { - /** @var Network\Factory\MimeType */ + /** @var MimeTypeFactory */ private $mimeTypeFactory; - public function __construct(Network\Factory\MimeType $mimeTypeFactory, LoggerInterface $logger) + public function __construct(MimeTypeFactory $mimeTypeFactory, LoggerInterface $logger) { parent::__construct($logger); @@ -31,9 +32,9 @@ class PostMedia extends BaseFactory implements ICanCreateFromTableRow /** * @inheritDoc */ - public function createFromTableRow(array $row) + public function createFromTableRow(array $row): PostMediaEntity { - return new Entity\PostMedia( + return new PostMediaEntity( $row['uri-id'], UtilNetwork::createUriFromString($row['url']), $row['type'], @@ -58,13 +59,13 @@ class PostMedia extends BaseFactory implements ICanCreateFromTableRow ); } - public function createFromBlueskyImageEmbed(int $uriId, stdClass $image): Entity\PostMedia + public function createFromBlueskyImageEmbed(int $uriId, stdClass $image): PostMediaEntity { - return new Entity\PostMedia( + return new PostMediaEntity( $uriId, new Uri($image->fullsize), - Entity\PostMedia::TYPE_IMAGE, - new Network\Entity\MimeType('unkn', 'unkn'), + PostMediaEntity::TYPE_IMAGE, + new MimeTypeEntity('unkn', 'unkn'), null, null, null, @@ -77,13 +78,13 @@ class PostMedia extends BaseFactory implements ICanCreateFromTableRow } - public function createFromBlueskyExternalEmbed(int $uriId, stdClass $external): Entity\PostMedia + public function createFromBlueskyExternalEmbed(int $uriId, stdClass $external): PostMediaEntity { - return new Entity\PostMedia( + return new PostMediaEntity( $uriId, new Uri($external->uri), - Entity\PostMedia::TYPE_HTML, - new Network\Entity\MimeType('text', 'html'), + PostMediaEntity::TYPE_HTML, + new MimeTypeEntity('text', 'html'), null, null, null, diff --git a/src/Content/Post/Repository/PostMedia.php b/src/Content/Post/Repository/PostMedia.php index 778591c1ab..f02d93c665 100644 --- a/src/Content/Post/Repository/PostMedia.php +++ b/src/Content/Post/Repository/PostMedia.php @@ -7,11 +7,10 @@ namespace Friendica\Content\Post\Repository; -use Friendica\BaseCollection; use Friendica\BaseRepository; -use Friendica\Content\Post\Collection; -use Friendica\Content\Post\Entity; -use Friendica\Content\Post\Factory; +use Friendica\Content\Post\Collection\PostMedias as PostMediasCollection; +use Friendica\Content\Post\Entity\PostMedia as PostMediaEntity; +use Friendica\Content\Post\Factory\PostMedia as PostMediaFactory; use Friendica\Database\Database; use Friendica\Model\Post; use Friendica\Util\Strings; @@ -21,16 +20,19 @@ class PostMedia extends BaseRepository { protected static $table_name = 'post-media'; - public function __construct(Database $database, LoggerInterface $logger, Factory\PostMedia $factory) + /** @var PostMediaFactory */ + protected $factory; + + public function __construct(Database $database, LoggerInterface $logger, PostMediaFactory $factory) { parent::__construct($database, $logger, $factory); } - protected function _select(array $condition, array $params = []): BaseCollection + protected function _select(array $condition, array $params = []): PostMediasCollection { $rows = $this->db->selectToArray(static::$table_name, [], $condition, $params); - $Entities = new Collection\PostMedias(); + $Entities = new PostMediasCollection(); foreach ($rows as $fields) { try { $Entities[] = $this->factory->createFromTableRow($fields); @@ -42,17 +44,19 @@ class PostMedia extends BaseRepository return $Entities; } - public function selectOneById(int $postMediaId): Entity\PostMedia + public function selectOneById(int $postMediaId): PostMediaEntity { - return $this->_selectOne(['id' => $postMediaId]); + $fields = $this->_selectFirstRowAsArray( ['id' => $postMediaId]); + + return $this->factory->createFromTableRow($fields); } - public function selectByUriId(int $uriId): Collection\PostMedias + public function selectByUriId(int $uriId): PostMediasCollection { return $this->_select(["`uri-id` = ? AND `type` != ?", $uriId, Post\Media::UNKNOWN]); } - public function save(Entity\PostMedia $PostMedia): Entity\PostMedia + public function save(PostMediaEntity $PostMedia): PostMediaEntity { $fields = [ 'uri-id' => $PostMedia->uriId, @@ -97,14 +101,14 @@ class PostMedia extends BaseRepository * @param int $uri_id URI id * @param array $links list of links that shouldn't be added * @param bool $has_media - * @return Collection\PostMedias[] Three collections in "visual", "link" and "additional" keys + * @return PostMediasCollection[] Three collections in "visual", "link" and "additional" keys */ public function splitAttachments(int $uri_id, array $links = [], bool $has_media = true): array { $attachments = [ - 'visual' => new Collection\PostMedias(), - 'link' => new Collection\PostMedias(), - 'additional' => new Collection\PostMedias(), + 'visual' => new PostMediasCollection(), + 'link' => new PostMediasCollection(), + 'additional' => new PostMediasCollection(), ]; if (!$has_media) { @@ -137,7 +141,7 @@ class PostMedia extends BaseRepository // Currently these two types are ignored here. // Posts are added differently and contacts are not displayed as attachments. - if (in_array($PostMedia->type, [Entity\PostMedia::TYPE_ACCOUNT, Entity\PostMedia::TYPE_ACTIVITY])) { + if (in_array($PostMedia->type, [PostMediaEntity::TYPE_ACCOUNT, PostMediaEntity::TYPE_ACTIVITY])) { continue; } @@ -148,17 +152,17 @@ class PostMedia extends BaseRepository //$PostMedia->filetype = $filetype; //$PostMedia->subtype = $subtype; - if ($PostMedia->type == Entity\PostMedia::TYPE_HTML || ($PostMedia->mimetype->type == 'text' && $PostMedia->mimetype->subtype == 'html')) { + if ($PostMedia->type == PostMediaEntity::TYPE_HTML || ($PostMedia->mimetype->type == 'text' && $PostMedia->mimetype->subtype == 'html')) { $attachments['link'][] = $PostMedia; continue; } if ( - in_array($PostMedia->type, [Entity\PostMedia::TYPE_AUDIO, Entity\PostMedia::TYPE_IMAGE, Entity\PostMedia::TYPE_HLS]) || + in_array($PostMedia->type, [PostMediaEntity::TYPE_AUDIO, PostMediaEntity::TYPE_IMAGE, PostMediaEntity::TYPE_HLS]) || in_array($PostMedia->mimetype->type, ['audio', 'image']) ) { $attachments['visual'][] = $PostMedia; - } elseif (($PostMedia->type == Entity\PostMedia::TYPE_VIDEO) || ($PostMedia->mimetype->type == 'video')) { + } elseif (($PostMedia->type == PostMediaEntity::TYPE_VIDEO) || ($PostMedia->mimetype->type == 'video')) { if (!empty($PostMedia->height)) { // Peertube videos are delivered in many different resolutions. We pick a moderate one. // Since only Peertube provides a "height" parameter, this wouldn't be executed diff --git a/src/Core/Worker/Repository/Process.php b/src/Core/Worker/Repository/Process.php index 146854234e..ee4d46a9f4 100644 --- a/src/Core/Worker/Repository/Process.php +++ b/src/Core/Worker/Repository/Process.php @@ -8,11 +8,11 @@ namespace Friendica\Core\Worker\Repository; use Friendica\BaseRepository; +use Friendica\Core\Worker\Entity\Process as ProcessEntity; use Friendica\Core\Worker\Exception\ProcessPersistenceException; +use Friendica\Core\Worker\Factory\Process as ProcessFactory; use Friendica\Database\Database; use Friendica\Util\DateTimeFormat; -use Friendica\Core\Worker\Factory; -use Friendica\Core\Worker\Entity; use Psr\Log\LoggerInterface; /** @@ -24,13 +24,13 @@ class Process extends BaseRepository protected static $table_name = 'process'; - /** @var Factory\Process */ + /** @var ProcessFactory */ protected $factory; /** @var string */ private $currentHost; - public function __construct(Database $database, LoggerInterface $logger, Factory\Process $factory, array $server) + public function __construct(Database $database, LoggerInterface $logger, ProcessFactory $factory, array $server) { parent::__construct($database, $logger, $factory); @@ -39,13 +39,8 @@ class Process extends BaseRepository /** * Starts and Returns the process for a given PID at the current host - * - * @param int $pid - * @param string $command - * - * @return Entity\Process */ - public function create(int $pid, string $command): Entity\Process + public function create(int $pid, string $command): ProcessEntity { // Cleanup inactive process $this->deleteInactive(); @@ -64,7 +59,9 @@ class Process extends BaseRepository } } - $result = $this->_selectOne(['pid' => $pid, 'hostname' => $this->currentHost]); + $fields = $this->_selectFirstRowAsArray( ['pid' => $pid, 'hostname' => $this->currentHost]); + + $result = $this->factory->createFromTableRow($fields); $this->db->commit(); @@ -74,7 +71,7 @@ class Process extends BaseRepository } } - public function delete(Entity\Process $process) + public function delete(ProcessEntity $process) { try { if (!$this->db->delete(static::$table_name, [ From e1eb6fff839fcfbb2f6cf74d5e2dc22cec7d1af4 Mon Sep 17 00:00:00 2001 From: Art4 Date: Thu, 13 Mar 2025 09:18:53 +0000 Subject: [PATCH 31/46] Deprecate BaseRepository::_selectOne() set BaseRepository::_selectFirstRowAsArray() as final --- src/BaseRepository.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/BaseRepository.php b/src/BaseRepository.php index ead4bf73bf..bf495a6a5d 100644 --- a/src/BaseRepository.php +++ b/src/BaseRepository.php @@ -136,7 +136,7 @@ abstract class BaseRepository * * @return array The resulted fields as array */ - protected function _selectFirstRowAsArray(array $condition, array $params = []): array + final protected function _selectFirstRowAsArray(array $condition, array $params = []): array { $fields = $this->db->selectFirst(static::$table_name, [], $condition, $params); @@ -154,6 +154,8 @@ abstract class BaseRepository */ protected function _selectOne(array $condition, array $params = []): BaseEntity { + @trigger_error('`' . __METHOD__ . '()` is deprecated since 2025.05 and will be removed after 5 months, use `\Friendica\BaseRepository::_selectFirstRowAsArray()` instead.', E_USER_DEPRECATED); + $fields = $this->_selectFirstRowAsArray( $condition, $params); return $this->factory->createFromTableRow($fields); From 7e66b35b4626fa84f12dfd4a63dd416d37b9177e Mon Sep 17 00:00:00 2001 From: Art4 Date: Thu, 13 Mar 2025 11:39:02 +0000 Subject: [PATCH 32/46] Fix 10 PHPStan errors --- src/Core/Storage/Type/Database.php | 2 +- src/Core/System.php | 8 +++----- src/Core/Update.php | 4 ++-- src/Core/Worker.php | 7 ++++--- 4 files changed, 10 insertions(+), 11 deletions(-) diff --git a/src/Core/Storage/Type/Database.php b/src/Core/Storage/Type/Database.php index 39b84528e5..6ed8527533 100644 --- a/src/Core/Storage/Type/Database.php +++ b/src/Core/Storage/Type/Database.php @@ -80,7 +80,7 @@ class Database implements ICanWriteToStorage throw new StorageException(sprintf('Database storage failed to update %s', $reference), 500, new Exception($this->dba->errorMessage(), $this->dba->errorNo())); } - return $this->dba->lastInsertId(); + return (string) $this->dba->lastInsertId(); } } diff --git a/src/Core/System.php b/src/Core/System.php index df494bec5d..d7367e871c 100644 --- a/src/Core/System.php +++ b/src/Core/System.php @@ -452,19 +452,17 @@ class System /** * Returns the current Load of the System - * - * @return integer */ - public static function currentLoad() + public static function currentLoad(): float { if (!function_exists('sys_getloadavg')) { - return false; + return (float) 0; } $load_arr = sys_getloadavg(); if (!is_array($load_arr)) { - return false; + return (float) 0; } return round(max($load_arr[0], $load_arr[1]), 2); diff --git a/src/Core/Update.php b/src/Core/Update.php index 7aeefc3793..dc68f280cc 100644 --- a/src/Core/Update.php +++ b/src/Core/Update.php @@ -217,7 +217,7 @@ class Update ->set('system', 'maintenance', false) ->delete('system', 'maintenance_reason') ->commit(); - return $r; + return 'Pre update failed'; } else { DI::logger()->notice('Pre update executed.', ['version' => $version]); } @@ -262,7 +262,7 @@ class Update ->set('system', 'maintenance', false) ->delete('system', 'maintenance_reason') ->commit(); - return $r; + return 'Post update failed'; } else { DI::config()->set('system', 'build', $version); DI::logger()->notice('Post update executed.', ['version' => $version]); diff --git a/src/Core/Worker.php b/src/Core/Worker.php index 995239cde9..75a457f38e 100644 --- a/src/Core/Worker.php +++ b/src/Core/Worker.php @@ -271,12 +271,13 @@ class Worker * * @param integer $priority The priority that should be checked * - * @return integer Is there a process running with that priority? + * @return bool Is there a process running with that priority? * @throws \Exception */ - private static function processWithPriorityActive(int $priority): int + private static function processWithPriorityActive(int $priority): bool { $condition = ["`priority` <= ? AND `pid` != 0 AND NOT `done`", $priority]; + return DBA::exists('workerqueue', $condition); } @@ -955,7 +956,7 @@ class Worker /** * Returns the priority of the next workerqueue job * - * @return string|bool priority or FALSE on failure + * @return int|false priority or FALSE on failure * @throws \Exception */ private static function nextPriority() From 441846cfbdce0b368486f7d782c8ececb52b14c6 Mon Sep 17 00:00:00 2001 From: Art4 Date: Thu, 13 Mar 2025 11:50:15 +0000 Subject: [PATCH 33/46] Fix return type or UserSession::getUserIDForVisitorContactID() --- src/Core/Session/Model/UserSession.php | 4 ++-- src/Object/Post.php | 2 +- tests/src/Core/Session/UserSessionTest.php | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Core/Session/Model/UserSession.php b/src/Core/Session/Model/UserSession.php index cc3db7f806..70370371ff 100644 --- a/src/Core/Session/Model/UserSession.php +++ b/src/Core/Session/Model/UserSession.php @@ -101,7 +101,7 @@ class UserSession implements IHandleUserSessions public function getUserIDForVisitorContactID(int $cid): int { if (empty($this->session->get('remote'))) { - return false; + return 0; } return array_search($cid, $this->session->get('remote')); @@ -142,7 +142,7 @@ class UserSession implements IHandleUserSessions { return !$this->session->get('authenticated', false); } - + /** {@inheritDoc} */ public function setVisitorsContacts(string $my_url) { diff --git a/src/Object/Post.php b/src/Object/Post.php index 4dd5cdea30..7c19a99842 100644 --- a/src/Object/Post.php +++ b/src/Object/Post.php @@ -71,7 +71,7 @@ class Post $this->setTemplate('wall'); $this->toplevel = $this->getId() == $this->getDataValue('parent'); - if (!empty(DI::userSession()->getUserIDForVisitorContactID($this->getDataValue('contact-id')))) { + if (DI::userSession()->getUserIDForVisitorContactID($this->getDataValue('contact-id')) !== 0) { $this->visiting = true; } diff --git a/tests/src/Core/Session/UserSessionTest.php b/tests/src/Core/Session/UserSessionTest.php index 64c7d8b950..cecae1d90c 100644 --- a/tests/src/Core/Session/UserSessionTest.php +++ b/tests/src/Core/Session/UserSessionTest.php @@ -152,13 +152,13 @@ class UserSessionTest extends MockedTestCase 'data' => [ 'remote' => ['3' => '21'], ], - 'expected' => false, + 'expected' => 0, ], 'empty' => [ 'cid' => 21, 'data' => [ ], - 'expected' => false, + 'expected' => 0, ], ]; } @@ -167,7 +167,7 @@ class UserSessionTest extends MockedTestCase public function testGetUserIdForVisitorContactID(int $cid, array $data, $expected) { $userSession = new UserSession(new ArraySession($data)); - $this->assertEquals($expected, $userSession->getUserIDForVisitorContactID($cid)); + $this->assertSame($expected, $userSession->getUserIDForVisitorContactID($cid)); } public function dataAuthenticated() From a63babc658fe7a609474fb9328419c3a2e380f76 Mon Sep 17 00:00:00 2001 From: Art4 Date: Thu, 13 Mar 2025 12:20:43 +0000 Subject: [PATCH 34/46] Fix 6 PHPStan errors --- src/Core/Logger/Type/StreamLogger.php | 8 ++---- src/Core/Logger/Type/SyslogLogger.php | 28 ++++++++----------- src/Core/PConfig/Repository/PConfig.php | 2 +- .../Logger/SyslogLoggerFactoryWrapper.php | 10 +++---- tests/src/Core/Logger/SyslogLoggerWrapper.php | 2 +- 5 files changed, 21 insertions(+), 29 deletions(-) diff --git a/src/Core/Logger/Type/StreamLogger.php b/src/Core/Logger/Type/StreamLogger.php index 81af7e4474..03dfe69b6d 100644 --- a/src/Core/Logger/Type/StreamLogger.php +++ b/src/Core/Logger/Type/StreamLogger.php @@ -22,21 +22,19 @@ class StreamLogger extends AbstractLogger /** * The minimum loglevel at which this logger will be triggered - * @var string */ - private $logLevel; + private int $logLevel; /** * The stream, where the current logger is writing into - * @var resource + * @var resource|null */ private $stream; /** * The current process ID - * @var int */ - private $pid; + private int $pid; /** * Translates LogLevel log levels to integer values diff --git a/src/Core/Logger/Type/SyslogLogger.php b/src/Core/Logger/Type/SyslogLogger.php index 8f24af053c..8b5f34634f 100644 --- a/src/Core/Logger/Type/SyslogLogger.php +++ b/src/Core/Logger/Type/SyslogLogger.php @@ -29,7 +29,7 @@ class SyslogLogger extends AbstractLogger /** * Translates LogLevel log levels to syslog log priorities. - * @var array + * @var array */ public const logLevels = [ LogLevel::DEBUG => LOG_DEBUG, @@ -60,39 +60,33 @@ class SyslogLogger extends AbstractLogger /** * Indicates what logging options will be used when generating a log message * @see http://php.net/manual/en/function.openlog.php#refsect1-function.openlog-parameters - * - * @var int */ - private $logOpts; + private int $logOpts; /** * Used to specify what type of program is logging the message * @see http://php.net/manual/en/function.openlog.php#refsect1-function.openlog-parameters - * - * @var int */ - private $logFacility; + private int $logFacility; /** * The minimum loglevel at which this logger will be triggered - * @var int */ - private $logLevel; + private int $logLevel; /** * A error message of the current operation - * @var string */ - private $errorMessage; + private string $errorMessage; /** * {@inheritdoc} * - * @param string $logLevel The minimum loglevel at which this logger will be triggered - * @param string $logOptions - * @param string $logFacility + * @param int $logLevel The minimum loglevel at which this logger will be triggered + * @param int $logOptions + * @param int $logFacility */ - public function __construct(string $channel, IHaveCallIntrospections $introspection, string $logLevel, string $logOptions, string $logFacility) + public function __construct(string $channel, IHaveCallIntrospections $introspection, int $logLevel, int $logOptions, int $logFacility) { parent::__construct($channel, $introspection); @@ -166,7 +160,7 @@ class SyslogLogger extends AbstractLogger restore_error_handler(); if (!$opened) { - throw new LoggerException(sprintf('Can\'t open syslog for ident "%s" and facility "%s": ' . $this->errorMessage, $this->channel, $this->logFacility)); + throw new LoggerException(sprintf('Can\'t open syslog for ident "%s" and facility "%s": ' . $this->errorMessage, $this->channel, (string) $this->logFacility)); } $this->syslogWrapper($priority, $message); @@ -215,7 +209,7 @@ class SyslogLogger extends AbstractLogger restore_error_handler(); if (!$written) { - throw new LoggerException(sprintf('Can\'t write into syslog for ident "%s" and facility "%s": ' . $this->errorMessage, $this->channel, $this->logFacility)); + throw new LoggerException(sprintf('Can\'t write into syslog for ident "%s" and facility "%s": ' . $this->errorMessage, $this->channel, (string) $this->logFacility)); } } } diff --git a/src/Core/PConfig/Repository/PConfig.php b/src/Core/PConfig/Repository/PConfig.php index d3b68b8ce1..af59e23fc3 100644 --- a/src/Core/PConfig/Repository/PConfig.php +++ b/src/Core/PConfig/Repository/PConfig.php @@ -37,7 +37,7 @@ class PConfig */ public function isConnected(): bool { - return $this->db->isConnected() & !$this->mode->isInstall(); + return $this->db->isConnected() && !$this->mode->isInstall(); } /** diff --git a/tests/src/Core/Logger/SyslogLoggerFactoryWrapper.php b/tests/src/Core/Logger/SyslogLoggerFactoryWrapper.php index 10b19d1991..6bc30bc439 100644 --- a/tests/src/Core/Logger/SyslogLoggerFactoryWrapper.php +++ b/tests/src/Core/Logger/SyslogLoggerFactoryWrapper.php @@ -17,16 +17,16 @@ class SyslogLoggerFactoryWrapper extends SyslogLogger { public function create(IManageConfigValues $config): LoggerInterface { - $logOpts = $config->get('system', 'syslog_flags') ?? SyslogLoggerClass::DEFAULT_FLAGS; - $logFacility = $config->get('system', 'syslog_facility') ?? SyslogLoggerClass::DEFAULT_FACILITY; + $logOpts = (int) $config->get('system', 'syslog_flags') ?? SyslogLoggerClass::DEFAULT_FLAGS; + $logFacility = (int) $config->get('system', 'syslog_facility') ?? SyslogLoggerClass::DEFAULT_FACILITY; $loglevel = SyslogLogger::mapLegacyConfigDebugLevel($config->get('system', 'loglevel')); - if (array_key_exists($loglevel, SyslogLoggerClass::logLevels)) { - $loglevel = SyslogLoggerClass::logLevels[$loglevel]; - } else { + if (!array_key_exists($loglevel, SyslogLoggerClass::logLevels)) { throw new LogLevelException(sprintf('The level "%s" is not valid.', $loglevel)); } + $loglevel = SyslogLoggerClass::logLevels[$loglevel]; + return new SyslogLoggerWrapper($this->channel, $this->introspection, $loglevel, $logOpts, $logFacility); } } diff --git a/tests/src/Core/Logger/SyslogLoggerWrapper.php b/tests/src/Core/Logger/SyslogLoggerWrapper.php index e0e360a50f..df2944c4c5 100644 --- a/tests/src/Core/Logger/SyslogLoggerWrapper.php +++ b/tests/src/Core/Logger/SyslogLoggerWrapper.php @@ -17,7 +17,7 @@ class SyslogLoggerWrapper extends SyslogLogger { private $content; - public function __construct(string $channel, IHaveCallIntrospections $introspection, string $logLevel, string $logOptions, string $logFacility) + public function __construct(string $channel, IHaveCallIntrospections $introspection, int $logLevel, int $logOptions, int $logFacility) { parent::__construct($channel, $introspection, $logLevel, $logOptions, $logFacility); From 2dfd7c83cf27cd80fef6c00384f075e4e2f90b56 Mon Sep 17 00:00:00 2001 From: Art4 Date: Thu, 13 Mar 2025 12:26:16 +0000 Subject: [PATCH 35/46] ignore PHPStan error in deprecated code --- src/Core/Config/Util/ConfigFileManager.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Core/Config/Util/ConfigFileManager.php b/src/Core/Config/Util/ConfigFileManager.php index d76e3e53cd..96c416e4de 100644 --- a/src/Core/Config/Util/ConfigFileManager.php +++ b/src/Core/Config/Util/ConfigFileManager.php @@ -257,6 +257,7 @@ class ConfigFileManager // map the legacy configuration structure to the current structure foreach ($htConfigCategories as $htConfigCategory) { + /** @phpstan-ignore-next-line $a->config could be modified after `include $fullName` */ if (is_array($a->config[$htConfigCategory])) { $keys = array_keys($a->config[$htConfigCategory]); From bb6a4a3acd1125ba52a0d38a2d96925b61b1a159 Mon Sep 17 00:00:00 2001 From: Art4 Date: Thu, 13 Mar 2025 12:37:30 +0000 Subject: [PATCH 36/46] fix 14 PHPStan errors in console --- src/Console/Contact.php | 14 ++++++++------ src/Console/User.php | 20 ++++++++++---------- src/Content/PageInfo.php | 1 + 3 files changed, 19 insertions(+), 16 deletions(-) diff --git a/src/Console/Contact.php b/src/Console/Contact.php index 8173054826..d54979c11b 100644 --- a/src/Console/Contact.php +++ b/src/Console/Contact.php @@ -56,7 +56,7 @@ HELP; return $help; } - public function __construct(Mode $appMode, array $argv = null) + public function __construct(Mode $appMode, ?array $argv = null) { parent::__construct($argv); @@ -84,13 +84,13 @@ HELP; switch ($command) { case 'add': - return $this->addContact(); + return ($this->addContact()) ? 0 : 1; case 'remove': - return $this->removeContact(); + return ($this->removeContact()) ? 0 : 1; case 'search': - return $this->searchContact(); + return ($this->searchContact()) ? 0 : 1; case 'terminate': - return $this->terminateContact(); + return ($this->terminateContact()) ? 0 : 1; default: throw new \Asika\SimpleConsole\CommandArgsException('Wrong command.'); } @@ -206,7 +206,7 @@ HELP; /** * Marks a contact for removal */ - private function removeContact() + private function removeContact(): bool { $cid = $this->getArgument(1); if (empty($cid)) { @@ -218,6 +218,8 @@ HELP; } ContactModel::remove($cid); + + return true; } /** diff --git a/src/Console/User.php b/src/Console/User.php index 89c217694d..5a8f62cc8c 100644 --- a/src/Console/User.php +++ b/src/Console/User.php @@ -106,21 +106,21 @@ HELP; case 'password': return $this->password(); case 'add': - return $this->addUser(); + return ($this->addUser()) ? 0 : 1; case 'allow': - return $this->pendingUser(true); + return ($this->pendingUser(true)) ? 0 : 1; case 'deny': - return $this->pendingUser(false); + return ($this->pendingUser(false)) ? 0 : 1; case 'block': - return $this->blockUser(true); + return ($this->blockUser(true)) ? 0 : 1; case 'unblock': - return $this->blockUser(false); + return ($this->blockUser(false)) ? 0 : 1; case 'delete': - return $this->deleteUser(); + return ($this->deleteUser()) ? 0 : 1; case 'list': - return $this->listUser(); + return ($this->listUser()) ? 0 : 1; case 'search': - return $this->searchUser(); + return ($this->searchUser()) ? 0 : 1; case 'config': return ($this->configUser()) ? 0 : 1; default: @@ -178,7 +178,7 @@ HELP; * * @throws \Exception */ - private function password() + private function password(): int { $user = $this->getUserByNick(1); @@ -212,7 +212,7 @@ HELP; * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \ImagickException */ - private function addUser() + private function addUser(): bool { $name = $this->getArgument(1); $nick = $this->getArgument(2); diff --git a/src/Content/PageInfo.php b/src/Content/PageInfo.php index 4d2a1180d3..a53c36b68c 100644 --- a/src/Content/PageInfo.php +++ b/src/Content/PageInfo.php @@ -92,6 +92,7 @@ class PageInfo { $eventDispatcher = DI::eventDispatcher(); + /** @var array */ $data = $eventDispatcher->dispatch( new ArrayFilterEvent(ArrayFilterEvent::PAGE_INFO, $data), )->getArray(); From b999472ddb6e2196f482c34d9c4e209620832bbc Mon Sep 17 00:00:00 2001 From: Art4 Date: Thu, 13 Mar 2025 12:49:09 +0000 Subject: [PATCH 37/46] Fix possible false return type in PHP 7.4 --- src/Console/PoToPhp.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Console/PoToPhp.php b/src/Console/PoToPhp.php index ec5c050e70..a99cd6e806 100644 --- a/src/Console/PoToPhp.php +++ b/src/Console/PoToPhp.php @@ -175,11 +175,11 @@ HELP; * @param string $string * @param array|string $node */ - private static function parse(string $string, &$node = []) + private static function parse(string $string, &$node) { // Removes extra outward parentheses if (strpos($string, '(') === 0 && strrpos($string, ')') === strlen($string) - 1) { - $string = substr($string, 1, -1); + $string = (string) substr($string, 1, -1); } $q = strpos($string, '?'); From 0427812269b0c671b9f89a93a69bec43ecf3777f Mon Sep 17 00:00:00 2001 From: Art4 Date: Thu, 13 Mar 2025 12:54:00 +0000 Subject: [PATCH 38/46] Run phpstan in addons with level 3 --- .phpstan-addons.neon | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.phpstan-addons.neon b/.phpstan-addons.neon index 801db2ab6a..c4864d468d 100644 --- a/.phpstan-addons.neon +++ b/.phpstan-addons.neon @@ -3,7 +3,7 @@ # SPDX-License-Identifier: CC0-1.0 parameters: - level: 2 + level: 3 paths: - addon/ From cd00a8950f568ed653177cd4d68949fea8d9f9fb Mon Sep 17 00:00:00 2001 From: Artur Weigandt Date: Thu, 13 Mar 2025 15:59:56 +0100 Subject: [PATCH 39/46] Update src/Contact/FriendSuggest/Repository/FriendSuggest.php Co-authored-by: Hypolite Petovan --- src/Contact/FriendSuggest/Repository/FriendSuggest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Contact/FriendSuggest/Repository/FriendSuggest.php b/src/Contact/FriendSuggest/Repository/FriendSuggest.php index a9f4610439..833421c7f6 100644 --- a/src/Contact/FriendSuggest/Repository/FriendSuggest.php +++ b/src/Contact/FriendSuggest/Repository/FriendSuggest.php @@ -49,7 +49,7 @@ class FriendSuggest extends BaseRepository */ private function selectOne(array $condition, array $params = []): FriendSuggestEntity { - $fields = $this->_selectFirstRowAsArray( $condition, $params); + $fields = $this->_selectFirstRowAsArray($condition, $params); return $this->factory->createFromTableRow($fields); } From bdfc87ab0d097d75b0f3009089360be2c1559d63 Mon Sep 17 00:00:00 2001 From: Artur Weigandt Date: Thu, 13 Mar 2025 16:00:05 +0100 Subject: [PATCH 40/46] Update src/Contact/LocalRelationship/Repository/LocalRelationship.php Co-authored-by: Hypolite Petovan --- src/Contact/LocalRelationship/Repository/LocalRelationship.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Contact/LocalRelationship/Repository/LocalRelationship.php b/src/Contact/LocalRelationship/Repository/LocalRelationship.php index f00002a066..d1a87d5569 100644 --- a/src/Contact/LocalRelationship/Repository/LocalRelationship.php +++ b/src/Contact/LocalRelationship/Repository/LocalRelationship.php @@ -33,7 +33,7 @@ class LocalRelationship extends BaseRepository */ public function selectForUserContact(int $uid, int $cid): LocalRelationshipEntity { - $fields = $this->_selectFirstRowAsArray( ['uid' => $uid, 'cid' => $cid]); + $fields = $this->_selectFirstRowAsArray(['uid' => $uid, 'cid' => $cid]); return $this->factory->createFromTableRow($fields); } From 71bef03316288eab757bd27203c305f438520288 Mon Sep 17 00:00:00 2001 From: Artur Weigandt Date: Thu, 13 Mar 2025 16:00:17 +0100 Subject: [PATCH 41/46] Update src/Content/Conversation/Repository/UserDefinedChannel.php Co-authored-by: Hypolite Petovan --- src/Content/Conversation/Repository/UserDefinedChannel.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Content/Conversation/Repository/UserDefinedChannel.php b/src/Content/Conversation/Repository/UserDefinedChannel.php index 65b29d0c94..b9eecbf53c 100644 --- a/src/Content/Conversation/Repository/UserDefinedChannel.php +++ b/src/Content/Conversation/Repository/UserDefinedChannel.php @@ -69,7 +69,7 @@ class UserDefinedChannel extends BaseRepository */ public function selectById(int $id, int $uid): UserDefinedChannelEntity { - $fields = $this->_selectFirstRowAsArray( ['id' => $id, 'uid' => $uid]); + $fields = $this->_selectFirstRowAsArray(['id' => $id, 'uid' => $uid]); return $this->factory->createFromTableRow($fields); } From 2c87e7e102f2a383967a065108db3682b7462332 Mon Sep 17 00:00:00 2001 From: Artur Weigandt Date: Thu, 13 Mar 2025 16:00:25 +0100 Subject: [PATCH 42/46] Update src/Content/Post/Repository/PostMedia.php Co-authored-by: Hypolite Petovan --- src/Content/Post/Repository/PostMedia.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Content/Post/Repository/PostMedia.php b/src/Content/Post/Repository/PostMedia.php index f02d93c665..9d6b09cb5f 100644 --- a/src/Content/Post/Repository/PostMedia.php +++ b/src/Content/Post/Repository/PostMedia.php @@ -46,7 +46,7 @@ class PostMedia extends BaseRepository public function selectOneById(int $postMediaId): PostMediaEntity { - $fields = $this->_selectFirstRowAsArray( ['id' => $postMediaId]); + $fields = $this->_selectFirstRowAsArray(['id' => $postMediaId]); return $this->factory->createFromTableRow($fields); } From b632b1d84e275b4061f09c0a38df0056ab5732cf Mon Sep 17 00:00:00 2001 From: Artur Weigandt Date: Thu, 13 Mar 2025 16:00:34 +0100 Subject: [PATCH 43/46] Update src/Core/Worker/Repository/Process.php Co-authored-by: Hypolite Petovan --- src/Core/Worker/Repository/Process.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Core/Worker/Repository/Process.php b/src/Core/Worker/Repository/Process.php index ee4d46a9f4..ece8dc9db2 100644 --- a/src/Core/Worker/Repository/Process.php +++ b/src/Core/Worker/Repository/Process.php @@ -59,7 +59,7 @@ class Process extends BaseRepository } } - $fields = $this->_selectFirstRowAsArray( ['pid' => $pid, 'hostname' => $this->currentHost]); + $fields = $this->_selectFirstRowAsArray(['pid' => $pid, 'hostname' => $this->currentHost]); $result = $this->factory->createFromTableRow($fields); From 8ba652818f169a4391c193f9dde31c3c0dddb61e Mon Sep 17 00:00:00 2001 From: Art4 Date: Fri, 14 Mar 2025 07:50:24 +0000 Subject: [PATCH 44/46] let ATProtocol Processor::fetchUriId() return int --- src/Protocol/ATProtocol/Processor.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Protocol/ATProtocol/Processor.php b/src/Protocol/ATProtocol/Processor.php index ba838817a9..da11cbb479 100755 --- a/src/Protocol/ATProtocol/Processor.php +++ b/src/Protocol/ATProtocol/Processor.php @@ -279,7 +279,7 @@ class Processor $uri = $this->getUri($post); if ($uri_id = $this->fetchUriId($uri, $uid)) { - return (int) $uri_id; + return $uri_id; } if (empty($post->record)) { @@ -322,7 +322,7 @@ class Processor $this->logger->warning('Fetched post was not inserted', ['guid' => $item['guid'], 'uri' => $item['uri']]); } - return (int) $this->fetchUriId($uri, $uid); + return $this->fetchUriId($uri, $uid); } private function getHeaderFromJetstream(stdClass $data, int $uid, int $protocol = Conversation::PARCEL_JETSTREAM): array @@ -848,19 +848,19 @@ class Processor return $class; } - public function fetchUriId(string $uri, int $uid): string + public function fetchUriId(string $uri, int $uid): int { $reply = Post::selectFirst(['uri-id'], ['uri' => $uri, 'uid' => [$uid, 0]]); if (!empty($reply['uri-id'])) { $this->logger->debug('Post exists', ['uri' => $uri]); - return $reply['uri-id']; + return (int) $reply['uri-id']; } $reply = Post::selectFirst(['uri-id'], ['extid' => $uri, 'uid' => [$uid, 0]]); if (!empty($reply['uri-id'])) { $this->logger->debug('Post with extid exists', ['uri' => $uri]); - return $reply['uri-id']; + return (int) $reply['uri-id']; } - return '0'; + return 0; } private function getPostUids(string $uri, bool $with_public_user): array From 674b6c55def262df89fb21959003e91507a0d95c Mon Sep 17 00:00:00 2001 From: Art4 Date: Mon, 17 Mar 2025 07:38:53 +0000 Subject: [PATCH 45/46] Fix code style --- src/Console/PoToPhp.php | 10 ++--- .../Introduction/Repository/Introduction.php | 5 ++- .../Repository/UserDefinedChannel.php | 6 +-- src/Content/Post/Entity/PostMedia.php | 7 ++-- src/Content/Post/Repository/PostMedia.php | 2 +- src/Core/Hook.php | 2 +- src/Database/Database.php | 34 ++++++++-------- src/Factory/Api/Mastodon/Attachment.php | 2 +- src/Factory/Api/Twitter/Status.php | 4 +- src/Module/Filer/RemoveTag.php | 2 +- .../Notifications/Repository/Notification.php | 14 +++---- .../ValueObject/Introduction.php | 40 +++++++++---------- .../HTTPClient/Response/CurlResult.php | 6 +-- src/Object/Api/Friendica/Notification.php | 6 +-- src/Object/Api/Mastodon/Field.php | 2 +- .../Diaspora/Repository/DiasporaContact.php | 4 +- .../Repository/PermissionSet.php | 4 +- src/Security/Security.php | 18 +++------ 18 files changed, 81 insertions(+), 87 deletions(-) diff --git a/src/Console/PoToPhp.php b/src/Console/PoToPhp.php index a99cd6e806..480da23c46 100644 --- a/src/Console/PoToPhp.php +++ b/src/Console/PoToPhp.php @@ -134,7 +134,7 @@ HELP; ); $fnname = 'string_plural_select_' . $lang; - $out = 'if(! function_exists("' . $fnname . '")) {' . "\n"; + $out = 'if(! function_exists("' . $fnname . '")) {' . "\n"; $out .= 'function ' . $fnname . '($n){' . "\n"; $out .= ' $n = intval($n);' . "\n"; $out .= ' ' . $return . "\n"; @@ -192,13 +192,13 @@ HELP; if ($q === false || $s < $q) { list($then, $else) = explode(':', $string, 2); - $node['then'] = $then; - $parsedElse = []; + $node['then'] = $then; + $parsedElse = []; self::parse($else, $parsedElse); $node['else'] = $parsedElse; } else { list($if, $thenelse) = explode('?', $string, 2); - $node['if'] = $if; + $node['if'] = $if; self::parse($thenelse, $node); } } @@ -214,7 +214,7 @@ HELP; private static function render($tree): string { if (is_array($tree)) { - $if = trim($tree['if']); + $if = trim($tree['if']); $then = trim($tree['then']); $else = self::render($tree['else']); diff --git a/src/Contact/Introduction/Repository/Introduction.php b/src/Contact/Introduction/Repository/Introduction.php index dec2f2a246..a624017a2a 100644 --- a/src/Contact/Introduction/Repository/Introduction.php +++ b/src/Contact/Introduction/Repository/Introduction.php @@ -83,7 +83,10 @@ class Introduction extends BaseRepository $BaseCollection = parent::_selectByBoundaries( ['`uid` = ? AND NOT `ignore`',$uid], ['order' => ['id' => 'DESC']], - $min_id, $max_id, $limit); + $min_id, + $max_id, + $limit + ); } catch (\Exception $e) { throw new IntroductionPersistenceException(sprintf('Cannot select Introductions for used %d', $uid), $e); } diff --git a/src/Content/Conversation/Repository/UserDefinedChannel.php b/src/Content/Conversation/Repository/UserDefinedChannel.php index b9eecbf53c..b256e34e56 100644 --- a/src/Content/Conversation/Repository/UserDefinedChannel.php +++ b/src/Content/Conversation/Repository/UserDefinedChannel.php @@ -169,14 +169,14 @@ class UserDefinedChannel extends BaseRepository $uids = array_column($users, 'uid'); $usercondition = ['uid' => $uids]; - $condition = DBA::mergeConditions($usercondition, ["`languages` != ? AND `include-tags` = ? AND `full-text-search` = ? AND `circle` = ?", '', '', '', 0]); + $condition = DBA::mergeConditions($usercondition, ["`languages` != ? AND `include-tags` = ? AND `full-text-search` = ? AND `circle` = ?", '', '', '', 0]); foreach ($this->select($condition) as $channel) { if (!empty($channel->languages) && in_array($language, $channel->languages)) { return true; } } - $search = ''; + $search = ''; $condition = DBA::mergeConditions($usercondition, ["`full-text-search` != ? AND `circle` = ? AND `valid`", '', 0]); foreach ($this->select($condition) as $channel) { $search .= '(' . $channel->fullTextSearch . ') '; @@ -201,7 +201,7 @@ class UserDefinedChannel extends BaseRepository { $condition = $this->getUserCondition(); $condition = DBA::mergeConditions($condition, ["`account-type` IN (?, ?) AND `uid` != ?", User::ACCOUNT_TYPE_RELAY, User::ACCOUNT_TYPE_COMMUNITY, 0]); - $users = $this->db->selectToArray('user', ['uid'], $condition); + $users = $this->db->selectToArray('user', ['uid'], $condition); if (empty($users)) { return []; } diff --git a/src/Content/Post/Entity/PostMedia.php b/src/Content/Post/Entity/PostMedia.php index 59d1ec9c57..b06e258710 100644 --- a/src/Content/Post/Entity/PostMedia.php +++ b/src/Content/Post/Entity/PostMedia.php @@ -121,8 +121,7 @@ class PostMedia extends BaseEntity ?UriInterface $publisherImage = null, ?string $blurhash = null, int $id = null - ) - { + ) { $this->uriId = $uriId; $this->url = $url; $this->type = $type; @@ -223,8 +222,8 @@ class PostMedia extends BaseEntity if ($newWidth && $newHeight && $size) { $dimensionts = Images::getScalingDimensions($newWidth, $newHeight, Proxy::getPixelsFromSize($size)); - $newWidth = $dimensionts['width']; - $newHeight = $dimensionts['height']; + $newWidth = $dimensionts['width']; + $newHeight = $dimensionts['height']; } return new self( diff --git a/src/Content/Post/Repository/PostMedia.php b/src/Content/Post/Repository/PostMedia.php index 9d6b09cb5f..d28d15bca7 100644 --- a/src/Content/Post/Repository/PostMedia.php +++ b/src/Content/Post/Repository/PostMedia.php @@ -167,7 +167,7 @@ class PostMedia extends BaseRepository // Peertube videos are delivered in many different resolutions. We pick a moderate one. // Since only Peertube provides a "height" parameter, this wouldn't be executed // when someone for example on Mastodon was sharing multiple videos in a single post. - $heights[$PostMedia->height] = (string)$PostMedia->url; + $heights[$PostMedia->height] = (string)$PostMedia->url; $video[(string) $PostMedia->url] = $PostMedia; } else { $attachments['visual'][] = $PostMedia; diff --git a/src/Core/Hook.php b/src/Core/Hook.php index 8c9f3ba910..555b6b5d9f 100644 --- a/src/Core/Hook.php +++ b/src/Core/Hook.php @@ -40,7 +40,7 @@ class Hook public static function loadHooks() { self::$hooks = []; - $stmt = DBA::select('hook', ['hook', 'file', 'function'], [], ['order' => ['priority' => 'desc', 'file']]); + $stmt = DBA::select('hook', ['hook', 'file', 'function'], [], ['order' => ['priority' => 'desc', 'file']]); while ($hook = DBA::fetch($stmt)) { self::add($hook['hook'], $hook['file'], $hook['function']); diff --git a/src/Database/Database.php b/src/Database/Database.php index 6f42756302..88aa636fd3 100644 --- a/src/Database/Database.php +++ b/src/Database/Database.php @@ -62,15 +62,15 @@ class Database protected $server_info = ''; /** @var PDO|mysqli|null */ protected $connection; - protected $driver = ''; + protected $driver = ''; protected $pdo_emulate_prepares = false; - private $error = ''; - private $errorno = 0; - private $affected_rows = 0; - protected $in_transaction = false; - protected $in_retrial = false; - protected $testmode = false; - private $relation = []; + private $error = ''; + private $errorno = 0; + private $affected_rows = 0; + protected $in_transaction = false; + protected $in_retrial = false; + protected $testmode = false; + private $relation = []; /** @var DbaDefinition */ protected $dbaDefinition; /** @var ViewDefinition */ @@ -86,7 +86,7 @@ class Database $this->viewDefinition = $viewDefinition; // Use dummy values - necessary for the first factory call of the logger itself - $this->logger = new NullLogger(); + $this->logger = new NullLogger(); $this->profiler = new Profiler($config); $this->connect(); @@ -630,7 +630,7 @@ class Database } elseif (is_string($args[$param])) { $param_types .= 's'; } elseif (is_object($args[$param]) && method_exists($args[$param], '__toString')) { - $param_types .= 's'; + $param_types .= 's'; $args[$param] = (string)$args[$param]; } else { $param_types .= 'b'; @@ -677,9 +677,9 @@ class Database } $this->logger->error('DB Error', [ - 'code' => $errorno, - 'error' => $error, - 'params' => $this->replaceParameters($sql, $args), + 'code' => $errorno, + 'error' => $error, + 'params' => $this->replaceParameters($sql, $args), ]); // On a lost connection we try to reconnect - but only once. @@ -784,9 +784,9 @@ class Database } $this->logger->error('DB Error', [ - 'code' => $errorno, - 'error' => $error, - 'params' => $this->replaceParameters($sql, $params), + 'code' => $errorno, + 'error' => $error, + 'params' => $this->replaceParameters($sql, $params), ]); // On a lost connection we simply quit. @@ -1335,7 +1335,7 @@ class Database return true; } - $fields = $this->castFields($table, $fields); + $fields = $this->castFields($table, $fields); $direct_fields = []; foreach ($fields as $key => $value) { diff --git a/src/Factory/Api/Mastodon/Attachment.php b/src/Factory/Api/Mastodon/Attachment.php index bd16b61b38..65eeec22eb 100644 --- a/src/Factory/Api/Mastodon/Attachment.php +++ b/src/Factory/Api/Mastodon/Attachment.php @@ -65,7 +65,7 @@ class Attachment extends BaseFactory * @return \Friendica\Object\Api\Mastodon\Attachment * @throws InternalServerErrorException */ - private function createFromMediaArray(array $attachment): \Friendica\Object\Api\Mastodon\Attachment + private function createFromMediaArray(array $attachment): \Friendica\Object\Api\Mastodon\Attachment { $filetype = !empty($attachment['mimetype']) ? strtolower(substr($attachment['mimetype'], 0, strpos($attachment['mimetype'], '/'))) : ''; diff --git a/src/Factory/Api/Twitter/Status.php b/src/Factory/Api/Twitter/Status.php index b77ee801f7..7d235cc870 100644 --- a/src/Factory/Api/Twitter/Status.php +++ b/src/Factory/Api/Twitter/Status.php @@ -111,7 +111,7 @@ class Status extends BaseFactory */ private function createFromArray(array $item, int $uid, bool $include_entities): \Friendica\Object\Api\Twitter\Status { - $item = Post\Media::addHTMLAttachmentToItem($item); + $item = Post\Media::addHTMLAttachmentToItem($item); $author = $this->twitterUser->createFromContactId($item['author-id'], $uid, true); if (!empty($item['causer-id']) && ($item['post-reason'] == Item::PR_ANNOUNCEMENT)) { @@ -203,6 +203,6 @@ class Status extends BaseFactory $entities = []; } - return new \Friendica\Object\Api\Twitter\Status($text, $statusnetHtml, $friendicaHtml, $item, $author, $owner, $retweeted, $quoted, $geo, $friendica_activities, $entities, $attachments, $friendica_comments, $liked); + return new \Friendica\Object\Api\Twitter\Status($text, $statusnetHtml, $friendicaHtml, $item, $author, $owner, $retweeted, $quoted, $geo, $friendica_activities, $entities, $attachments, $friendica_comments, $liked); } } diff --git a/src/Module/Filer/RemoveTag.php b/src/Module/Filer/RemoveTag.php index 28666c8a44..eb20efe0bb 100644 --- a/src/Module/Filer/RemoveTag.php +++ b/src/Module/Filer/RemoveTag.php @@ -71,7 +71,7 @@ class RemoveTag extends BaseModule $item_id = $this->parameters['id'] ?? 0; $term = trim($request['term'] ?? ''); - $cat = trim($request['cat'] ?? ''); + $cat = trim($request['cat'] ?? ''); if (!empty($cat)) { $type = Post\Category::CATEGORY; diff --git a/src/Navigation/Notifications/Repository/Notification.php b/src/Navigation/Notifications/Repository/Notification.php index 49703bc1f9..85c8895135 100644 --- a/src/Navigation/Notifications/Repository/Notification.php +++ b/src/Navigation/Notifications/Repository/Notification.php @@ -127,23 +127,23 @@ class Notification extends BaseRepository $values = [$uid]; $type_condition = ''; - $notify_type = $this->pconfig->get($uid, 'system', 'notify_type'); + $notify_type = $this->pconfig->get($uid, 'system', 'notify_type'); if (!is_null($notify_type)) { $type_condition = 'AND `type` & ? != 0'; - $values[] = $notify_type | UserNotification::TYPE_SHARED | UserNotification::TYPE_FOLLOW; + $values[] = $notify_type | UserNotification::TYPE_SHARED | UserNotification::TYPE_FOLLOW; } $like_condition = ''; if (!$this->pconfig->get($uid, 'system', 'notify_like')) { $like_condition = 'AND NOT `vid` IN (?, ?)'; - $values[] = Verb::getID(Activity::LIKE); - $values[] = Verb::getID(Activity::DISLIKE); + $values[] = Verb::getID(Activity::LIKE); + $values[] = Verb::getID(Activity::DISLIKE); } $announce_condition = ''; if (!$this->pconfig->get($uid, 'system', 'notify_announce')) { $announce_condition = 'AND vid != ?'; - $values[] = Verb::getID(Activity::ANNOUNCE); + $values[] = Verb::getID(Activity::ANNOUNCE); } $rows = $this->db->p(" @@ -253,12 +253,12 @@ class Notification extends BaseRepository public function deleteForItem(int $itemUriId): bool { $conditionTarget = [ - 'vid' => Verb::getID(Activity::POST), + 'vid' => Verb::getID(Activity::POST), 'target-uri-id' => $itemUriId, ]; $conditionParent = [ - 'vid' => Verb::getID(Activity::POST), + 'vid' => Verb::getID(Activity::POST), 'parent-uri-id' => $itemUriId, ]; diff --git a/src/Navigation/Notifications/ValueObject/Introduction.php b/src/Navigation/Notifications/ValueObject/Introduction.php index 6e2c24d340..36e490d0be 100644 --- a/src/Navigation/Notifications/ValueObject/Introduction.php +++ b/src/Navigation/Notifications/ValueObject/Introduction.php @@ -63,30 +63,30 @@ class Introduction implements \JsonSerializable public function __construct(array $data = []) { - $this->label = $data['label'] ?? ''; - $this->type = $data['str_type'] ?? ''; - $this->intro_id = $data['intro_id'] ?? -1; - $this->madeBy = $data['madeBy'] ?? ''; - $this->madeByUrl = $data['madeByUrl'] ?? ''; - $this->madeByZrl = $data['madeByZrl'] ?? ''; - $this->madeByAddr = $data['madeByAddr'] ?? ''; - $this->contactId = $data['contactId'] ?? -1; - $this->photo = $data['photo'] ?? ''; - $this->name = $data['name'] ?? ''; - $this->url = $data['url'] ?? ''; - $this->zrl = $data['zrl'] ?? ''; - $this->hidden = $data['hidden'] ?? false; + $this->label = $data['label'] ?? ''; + $this->type = $data['str_type'] ?? ''; + $this->intro_id = $data['intro_id'] ?? -1; + $this->madeBy = $data['madeBy'] ?? ''; + $this->madeByUrl = $data['madeByUrl'] ?? ''; + $this->madeByZrl = $data['madeByZrl'] ?? ''; + $this->madeByAddr = $data['madeByAddr'] ?? ''; + $this->contactId = $data['contactId'] ?? -1; + $this->photo = $data['photo'] ?? ''; + $this->name = $data['name'] ?? ''; + $this->url = $data['url'] ?? ''; + $this->zrl = $data['zrl'] ?? ''; + $this->hidden = $data['hidden'] ?? false; $this->postNewFriend = $data['postNewFriend'] ?? ''; - $this->knowYou = $data['knowYou'] ?? false; - $this->note = $data['note'] ?? ''; - $this->request = $data['request'] ?? ''; + $this->knowYou = $data['knowYou'] ?? false; + $this->note = $data['note'] ?? ''; + $this->request = $data['request'] ?? ''; $this->dfrnId = -1; - $this->addr = $data['addr'] ?? ''; - $this->network = $data['network'] ?? ''; - $this->uid = $data['uid'] ?? -1; + $this->addr = $data['addr'] ?? ''; + $this->network = $data['network'] ?? ''; + $this->uid = $data['uid'] ?? -1; $this->keywords = $data['keywords'] ?? ''; $this->location = $data['location'] ?? ''; - $this->about = $data['about'] ?? ''; + $this->about = $data['about'] ?? ''; } public function getLabel(): string diff --git a/src/Network/HTTPClient/Response/CurlResult.php b/src/Network/HTTPClient/Response/CurlResult.php index 30b8be3830..a38de01336 100644 --- a/src/Network/HTTPClient/Response/CurlResult.php +++ b/src/Network/HTTPClient/Response/CurlResult.php @@ -225,11 +225,11 @@ class CurlResult implements ICanHandleHttpResponses } } - $this->redirectUrl = (string)Uri::fromParts((array)$redirect_parts); - $this->isRedirectUrl = true; + $this->redirectUrl = (string)Uri::fromParts((array)$redirect_parts); + $this->isRedirectUrl = true; $this->redirectIsPermanent = $this->returnCode == 301 || $this->returnCode == 308; } else { - $this->isRedirectUrl = false; + $this->isRedirectUrl = false; $this->redirectIsPermanent = false; } } diff --git a/src/Object/Api/Friendica/Notification.php b/src/Object/Api/Friendica/Notification.php index f83cd9cc2c..2a49ea770c 100644 --- a/src/Object/Api/Friendica/Notification.php +++ b/src/Object/Api/Friendica/Notification.php @@ -84,15 +84,15 @@ class Notification extends BaseDataTransferObject $this->date_rel = Temporal::getRelativeDate($this->date); try { - $this->msg_html = BBCode::convertForUriId($notify->uriId, $this->msg, BBCode::EXTERNAL); + $this->msg_html = BBCode::convertForUriId($notify->uriId, $this->msg, BBCode::EXTERNAL); } catch (\Exception $e) { - $this->msg_html = ''; + $this->msg_html = ''; } try { $this->msg_plain = explode("\n", trim(HTML::toPlaintext($this->msg_html, 0)))[0]; } catch (\Exception $e) { - $this->msg_plain = ''; + $this->msg_plain = ''; } } } diff --git a/src/Object/Api/Mastodon/Field.php b/src/Object/Api/Mastodon/Field.php index 846aac4d0f..092f33b361 100644 --- a/src/Object/Api/Mastodon/Field.php +++ b/src/Object/Api/Mastodon/Field.php @@ -25,7 +25,7 @@ class Field extends BaseDataTransferObject public function __construct(string $name, string $value) { - $this->name = $name; + $this->name = $name; $this->value = $value; // Link verification unsupported $this->verified_at = null; diff --git a/src/Protocol/Diaspora/Repository/DiasporaContact.php b/src/Protocol/Diaspora/Repository/DiasporaContact.php index 6d92b066f8..5cf05b8aa0 100644 --- a/src/Protocol/Diaspora/Repository/DiasporaContact.php +++ b/src/Protocol/Diaspora/Repository/DiasporaContact.php @@ -245,8 +245,8 @@ class DiasporaContact extends BaseRepository $uriId, new DateTime($contact['created'] ?? 'now', new DateTimeZone('UTC')), $interacting_count ?? 0, - $interacted_count ?? 0, - $post_count ?? 0 + $interacted_count ?? 0, + $post_count ?? 0 ); $DiasporaContact = $this->save($DiasporaContact); diff --git a/src/Security/PermissionSet/Repository/PermissionSet.php b/src/Security/PermissionSet/Repository/PermissionSet.php index c77baf0f2e..42b6219e9c 100644 --- a/src/Security/PermissionSet/Repository/PermissionSet.php +++ b/src/Security/PermissionSet/Repository/PermissionSet.php @@ -119,8 +119,8 @@ class PermissionSet extends BaseRepository $circle_ids = []; if (!empty($user_contact_str) && $this->db->exists('contact', [ - 'id' => $cid, - 'uid' => $uid, + 'id' => $cid, + 'uid' => $uid, 'blocked' => false ])) { $circle_ids = Circle::getIdsByContactId($cid); diff --git a/src/Security/Security.php b/src/Security/Security.php index 9056596f27..f04af42061 100644 --- a/src/Security/Security.php +++ b/src/Security/Security.php @@ -79,33 +79,25 @@ class Security */ public static function getPermissionsSQLByUserId(int $owner_id, bool $accessible = false) { - $local_user = DI::userSession()->getLocalUserId(); + $local_user = DI::userSession()->getLocalUserId(); $remote_contact = DI::userSession()->getRemoteContactID($owner_id); - $acc_sql = ''; + $acc_sql = ''; if ($accessible) { $acc_sql = ' OR `accessible`'; } - /* - * Construct permissions - * - * default permissions - anonymous user - */ + // Construct permissions: default permissions - anonymous user $sql = " AND (allow_cid = '' AND allow_gid = '' AND deny_cid = '' AND deny_gid = ''" . $acc_sql . ") "; - /* - * Profile owner - everything is visible - */ if ($local_user && $local_user == $owner_id) { + // Profile owner - everything is visible $sql = ''; - /* - * Authenticated visitor. Load the circles the visitor belongs to. - */ } elseif ($remote_contact) { + // Authenticated visitor. Load the circles the visitor belongs to. $circleIds = '<<>>'; // should be impossible to match foreach (Circle::getIdsByContactId($remote_contact) as $circleId) { From ed5de437be7aa2172e8b392889e133684b6f37c1 Mon Sep 17 00:00:00 2001 From: Art4 Date: Fri, 9 May 2025 06:40:49 +0000 Subject: [PATCH 46/46] Fix PHPStan errors --- src/Core/Logger/Factory/SyslogLoggerFactory.php | 6 +++--- src/Module/Photo.php | 6 ++++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/Core/Logger/Factory/SyslogLoggerFactory.php b/src/Core/Logger/Factory/SyslogLoggerFactory.php index 24a884a5f9..e71eb219f9 100644 --- a/src/Core/Logger/Factory/SyslogLoggerFactory.php +++ b/src/Core/Logger/Factory/SyslogLoggerFactory.php @@ -48,8 +48,8 @@ final class SyslogLoggerFactory implements LoggerFactory */ public function createLogger(string $logLevel, string $logChannel): LoggerInterface { - $logOpts = (string) $this->config->get('system', 'syslog_flags') ?? SyslogLogger::DEFAULT_FLAGS; - $logFacility = (string) $this->config->get('system', 'syslog_facility') ?? SyslogLogger::DEFAULT_FACILITY; + $logOpts = (int) $this->config->get('system', 'syslog_flags') ?? SyslogLogger::DEFAULT_FLAGS; + $logFacility = (int) $this->config->get('system', 'syslog_facility') ?? SyslogLogger::DEFAULT_FACILITY; if (!array_key_exists($logLevel, SyslogLogger::logLevels)) { throw new LogLevelException(sprintf('The log level "%s" is not supported by "%s".', $logLevel, SyslogLogger::class)); @@ -58,7 +58,7 @@ final class SyslogLoggerFactory implements LoggerFactory return new SyslogLogger( $logChannel, $this->introspection, - (string) SyslogLogger::logLevels[$logLevel], + SyslogLogger::logLevels[$logLevel], $logOpts, $logFacility ); diff --git a/src/Module/Photo.php b/src/Module/Photo.php index 8faef5aa6d..ddd7b1994d 100644 --- a/src/Module/Photo.php +++ b/src/Module/Photo.php @@ -308,7 +308,9 @@ class Photo extends BaseApi // For local users directly use the photo record that is marked as the profile if (DI::baseUrl()->isLocalUrl($contact['url'])) { - $contact = Contact::selectFirst($fields, ['nurl' => $contact['nurl'], 'self' => true]); + $nurl = $contact['nurl']; + $contact = Contact::selectFirst($fields, ['nurl' => $nurl, 'self' => true]); + if (!empty($contact)) { if ($customsize <= Proxy::PIXEL_MICRO) { $scale = 6; @@ -324,7 +326,7 @@ class Photo extends BaseApi $this->logger->notice('Profile photo was not loaded', ['scale' => $scale, 'uid' => $contact['uid']]); } } else { - $this->logger->notice('Local Contact was not found', ['url' => $contact['nurl']]); + $this->logger->notice('Local Contact was not found', ['url' => $nurl]); } }