diff --git a/.phpstan.neon b/.phpstan.neon index 201d6acb39..fb731728b8 100644 --- a/.phpstan.neon +++ b/.phpstan.neon @@ -2,9 +2,6 @@ # # SPDX-License-Identifier: CC0-1.0 -includes: - - vendor/phpstan/phpstan-strict-rules/rules.neon - parameters: level: 3 @@ -26,10 +23,6 @@ parameters: dynamicConstantNames: - DB_UPDATE_VERSION - # See all rules at https://github.com/phpstan/phpstan-strict-rules/blob/2.0.x/rules.neon - strictRules: - allRules: false - ignoreErrors: - # Ignore missing GdImage class in PHP <= 7.4 @@ -45,17 +38,3 @@ parameters: # Ignore missing IMAP\Connection class in PHP <= 8.0 message: '(^Parameter .+ has invalid type IMAP\\Connection\.$)' path: src - - - - # #Fixme: Ignore type mismatch of BaseRepository::$factory in child classes - message: '#^PHPDoc type Friendica\\.+ of property Friendica\\.+\:\:\$factory is not the same as PHPDoc type Friendica\\Capabilities\\ICanCreateFromTableRow of overridden property Friendica\\BaseRepository\:\:\$factory\.$#' - identifier: property.phpDocType - count: 13 - path: src - - - - # #Fixme: Ignore type mismatch of BaseModule::$response in BaseApi module - message: '#^PHPDoc type Friendica\\Module\\Api\\ApiResponse of property Friendica\\Module\\BaseApi\:\:\$response is not the same as PHPDoc type Friendica\\Capabilities\\ICanCreateResponses of overridden property Friendica\\BaseModule\:\:\$response\.$#' - identifier: property.phpDocType - count: 1 - path: src/Module/BaseApi.php diff --git a/composer.json b/composer.json index fc26674ca7..9973336590 100644 --- a/composer.json +++ b/composer.json @@ -157,7 +157,6 @@ "php-mock/php-mock-phpunit": "^2.10", "phpmd/phpmd": "^2.15", "phpstan/phpstan": "^2.0", - "phpstan/phpstan-strict-rules": "^2.0", "phpunit/phpunit": "^9" }, "scripts": { diff --git a/composer.lock b/composer.lock index ab66a33d05..fb9fadddbd 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "e93a8ac7e31cf3e5e0ca76134e5ffa0b", + "content-hash": "897b878d6db24b9a6437bd9f971478be", "packages": [ { "name": "asika/simple-console", @@ -5849,54 +5849,6 @@ ], "time": "2024-11-11T15:43:04+00:00" }, - { - "name": "phpstan/phpstan-strict-rules", - "version": "2.0.0", - "source": { - "type": "git", - "url": "https://github.com/phpstan/phpstan-strict-rules.git", - "reference": "a4a6a08bd4a461e516b9c3b8fdbf0f1883b34158" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan-strict-rules/zipball/a4a6a08bd4a461e516b9c3b8fdbf0f1883b34158", - "reference": "a4a6a08bd4a461e516b9c3b8fdbf0f1883b34158", - "shasum": "" - }, - "require": { - "php": "^7.4 || ^8.0", - "phpstan/phpstan": "^2.0" - }, - "require-dev": { - "php-parallel-lint/php-parallel-lint": "^1.2", - "phpstan/phpstan-deprecation-rules": "^2.0", - "phpstan/phpstan-phpunit": "^2.0", - "phpunit/phpunit": "^9.6" - }, - "type": "phpstan-extension", - "extra": { - "phpstan": { - "includes": [ - "rules.neon" - ] - } - }, - "autoload": { - "psr-4": { - "PHPStan\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "Extra strict and opinionated rules for PHPStan", - "support": { - "issues": "https://github.com/phpstan/phpstan-strict-rules/issues", - "source": "https://github.com/phpstan/phpstan-strict-rules/tree/2.0.0" - }, - "time": "2024-10-26T16:04:33+00:00" - }, { "name": "phpunit/php-code-coverage", "version": "9.2.31", diff --git a/src/App.php b/src/App.php index b10e474885..ffcbfd1544 100644 --- a/src/App.php +++ b/src/App.php @@ -18,6 +18,7 @@ use Friendica\Capabilities\ICanCreateResponses; use Friendica\Capabilities\ICanHandleRequests; use Friendica\Content\Nav; use Friendica\Core\Addon\AddonHelper; +use Friendica\Core\Addon\Capability\ICanLoadAddons; use Friendica\Core\Config\Factory\Config; use Friendica\Core\Container; use Friendica\Core\Hooks\HookEventBridge; @@ -277,15 +278,11 @@ class App private function setupContainerForAddons(): void { - /** @var AddonHelper $addonHelper */ - $addonHelper = $this->container->create(AddonHelper::class); + /** @var ICanLoadAddons $addonLoader */ + $addonLoader = $this->container->create(ICanLoadAddons::class); - $addonHelper->loadAddons(); - - foreach ($addonHelper->getEnabledAddons() as $addonId) { - foreach ($addonHelper->getAddonDependencyConfig($addonId) as $name => $rule) { - $this->container->addRule($name, $rule); - } + foreach ($addonLoader->getActiveAddonConfig('dependencies') as $name => $rule) { + $this->container->addRule($name, $rule); } } diff --git a/src/Console/Worker.php b/src/Console/Worker.php index 09ff5f6599..97b7160d03 100644 --- a/src/Console/Worker.php +++ b/src/Console/Worker.php @@ -92,7 +92,5 @@ HELP; CoreWorker::unclaimProcess($process); $this->processRepo->delete($process); - - return; } } diff --git a/src/Content/Pager.php b/src/Content/Pager.php index 1199ec758f..0cdf5c0e4a 100644 --- a/src/Content/Pager.php +++ b/src/Content/Pager.php @@ -157,10 +157,10 @@ class Pager 'text' => $this->l10n->t('newer'), 'class' => 'previous' . ($this->getPage() == 1 ? ' disabled' : '') ], - 'next' => [ + 'next' => [ 'url' => Strings::ensureQueryParameter($this->baseQueryString . '&page=' . ($this->getPage() + 1)), 'text' => $this->l10n->t('older'), - 'class' => 'next' . ($displayedItemCount < $this->getItemsPerPage() ? ' disabled' : '') + 'class' => 'next' . ($displayedItemCount < $this->getItemsPerPage() ? ' disabled' : '') ] ]; @@ -208,15 +208,15 @@ class Pager 'class' => $this->getPage() == 1 ? 'disabled' : '' ]; - $numpages = (int) ceil($totalItemCount / $this->getItemsPerPage()); + $numpages = $totalItemCount / $this->getItemsPerPage(); $numstart = 1; - $numstop = $numpages; + $numstop = $numpages; // Limit the number of displayed page number buttons. if ($numpages > 8) { - $numstart = ($this->getPage() > 4) ? ($this->getPage() - 4) : 1; - $numstop = ($this->getPage() > ($numpages - 7)) ? $numpages : ($numstart + 8); + $numstart = (($this->getPage() > 4) ? ($this->getPage() - 4) : 1); + $numstop = (($this->getPage() > ($numpages - 7)) ? $numpages : ($numstart + 8)); } $pages = []; @@ -237,9 +237,25 @@ class Pager } } + if (($totalItemCount % $this->getItemsPerPage()) != 0) { + if ($i == $this->getPage()) { + $pages[$i] = [ + 'url' => '#', + 'text' => $i, + 'class' => 'current active' + ]; + } else { + $pages[$i] = [ + 'url' => Strings::ensureQueryParameter($this->baseQueryString . '&page=' . $i), + 'text' => $i, + 'class' => 'n' + ]; + } + } + $data['pages'] = $pages; - $lastpage = (($numpages > intval($numpages)) ? intval($numpages) + 1 : $numpages); + $lastpage = (($numpages > intval($numpages)) ? intval($numpages)+1 : $numpages); $data['next'] = [ 'url' => Strings::ensureQueryParameter($this->baseQueryString . '&page=' . ($this->getPage() + 1)), diff --git a/src/Content/Text/HTML.php b/src/Content/Text/HTML.php index 701125dd27..72c61f38cc 100644 --- a/src/Content/Text/HTML.php +++ b/src/Content/Text/HTML.php @@ -55,7 +55,7 @@ class HTML $xpath = new DOMXPath($doc); - /** @var \DOMNodeList<\DOMNode>|false $list */ + /** @var \DOMNode[] $list */ $list = $xpath->query("//" . $tag); foreach ($list as $node) { $attr = []; @@ -1018,7 +1018,7 @@ class HTML */ public static function checkRelMeLink(DOMDocument $doc, UriInterface $meUrl): bool { - $xpath = new \DOMXPath($doc); + $xpath = new \DOMXpath($doc); // This expression checks that "me" is among the space-delimited values of the "rel" attribute. // And that the href attribute contains exactly the provided URL diff --git a/src/Core/Addon/AddonHelper.php b/src/Core/Addon/AddonHelper.php index 0f4205696f..500bf66f1d 100644 --- a/src/Core/Addon/AddonHelper.php +++ b/src/Core/Addon/AddonHelper.php @@ -9,8 +9,6 @@ declare(strict_types=1); namespace Friendica\Core\Addon; -use Friendica\Core\Addon\Exception\AddonInvalidConfigFileException; - /** * Some functions to handle addons */ @@ -68,17 +66,6 @@ interface AddonHelper */ public function getAddonInfo(string $addonId): AddonInfo; - /** - * Returns a dependency config array for a given addon - * - * This will load a potential config-file from the static directory, like `addon/{addonId}/static/dependencies.config.php` - * - * @throws AddonInvalidConfigFileException If the config file doesn't return an array - * - * @return array the config as array or empty array if no config file was found - */ - public function getAddonDependencyConfig(string $addonId): array; - /** * Checks if the provided addon is enabled */ diff --git a/src/Core/Addon/AddonManagerHelper.php b/src/Core/Addon/AddonManagerHelper.php index 0825e67b13..9c888f55da 100644 --- a/src/Core/Addon/AddonManagerHelper.php +++ b/src/Core/Addon/AddonManagerHelper.php @@ -9,7 +9,6 @@ declare(strict_types=1); namespace Friendica\Core\Addon; -use Friendica\Core\Addon\Exception\AddonInvalidConfigFileException; use Friendica\Core\Addon\Exception\InvalidAddonException; use Friendica\Core\Cache\Capability\ICanCache; use Friendica\Core\Config\Capability\IManageConfigValues; @@ -271,34 +270,6 @@ final class AddonManagerHelper implements AddonHelper return AddonInfo::fromString($addonId, $matches[0]); } - /** - * Returns a dependency config array for a given addon - * - * This will load a potential config-file from the static directory, like `addon/{addonId}/static/dependencies.config.php` - * - * @throws AddonInvalidConfigFileException If the config file doesn't return an array - * - * @return array the config as array or empty array if no config file was found - */ - public function getAddonDependencyConfig(string $addonId): array - { - $addonId = Strings::sanitizeFilePathItem(trim($addonId)); - - $configFile = $this->getAddonPath() . '/' . $addonId . '/static/dependencies.config.php'; - - if (!file_exists($configFile)) { - return []; - } - - $config = include($configFile); - - if (!is_array($config)) { - throw new AddonInvalidConfigFileException('Error loading config file ' . $configFile); - } - - return $config; - } - /** * Checks if the provided addon is enabled */ diff --git a/src/Core/Addon/Capability/ICanLoadAddons.php b/src/Core/Addon/Capability/ICanLoadAddons.php index 63978462d3..993c431497 100644 --- a/src/Core/Addon/Capability/ICanLoadAddons.php +++ b/src/Core/Addon/Capability/ICanLoadAddons.php @@ -9,16 +9,12 @@ namespace Friendica\Core\Addon\Capability; /** * Interface for loading Addons specific content - * - * @deprecated 2025.02 Use implementation of `\Friendica\Core\Addon\AddonHelper` instead. */ interface ICanLoadAddons { /** * Returns a merged config array of all active addons for a given config-name * - * @deprecated 2025.02 Use `\Friendica\Core\Addon\AddonHelper::getAddonDependencyConfig()` instead. - * * @param string $configName The config-name (config-file at the static directory, like 'hooks' => '{addon}/static/hooks.config.php) * * @return array the merged array diff --git a/src/Core/Addon/Model/AddonLoader.php b/src/Core/Addon/Model/AddonLoader.php index b56ba3eed8..a608a66e3d 100644 --- a/src/Core/Addon/Model/AddonLoader.php +++ b/src/Core/Addon/Model/AddonLoader.php @@ -14,9 +14,6 @@ use Friendica\Core\Logger\Factory\LoggerFactory; use Friendica\Util\Strings; use Psr\Log\LoggerInterface; -/** - * @deprecated 2025.02 Use implementation of `\Friendica\Core\Addon\AddonHelper` instead. - */ class AddonLoader implements ICanLoadAddons { const STATIC_PATH = 'static'; @@ -27,19 +24,13 @@ class AddonLoader implements ICanLoadAddons public function __construct(string $basePath, IManageConfigValues $config) { - @trigger_error('Class `' . __CLASS__ . '` is deprecated since 2025.02 and will be removed after 5 months, use implementation of `Friendica\Core\Addon\AddonHelper` instead.', E_USER_DEPRECATED); - $this->basePath = $basePath; $this->config = $config; } - /** - * @deprecated 2025.02 Use `\Friendica\Core\Addon\AddonHelper::getAddonDependencyConfig()` instead. - */ + /** {@inheritDoc} */ public function getActiveAddonConfig(string $configName): array { - @trigger_error('Class `' . __CLASS__ . '` is deprecated since 2025.02 and will be removed after 5 months, use `\Friendica\Core\Addon\AddonHelper::getAddonDependencyConfig()` instead.', E_USER_DEPRECATED); - $addons = array_keys(array_filter($this->config->get('addons') ?? [])); $returnConfig = []; diff --git a/src/Core/Hooks/Util/StrategiesFileManager.php b/src/Core/Hooks/Util/StrategiesFileManager.php index c56a13ee6a..a876dc832c 100644 --- a/src/Core/Hooks/Util/StrategiesFileManager.php +++ b/src/Core/Hooks/Util/StrategiesFileManager.php @@ -7,13 +7,9 @@ namespace Friendica\Core\Hooks\Util; -use Friendica\Core\Addon\Exception\AddonInvalidConfigFileException; -use Friendica\Core\Config\Capability\IManageConfigValues; +use Friendica\Core\Addon\Capability\ICanLoadAddons; use Friendica\Core\Hooks\Capability\ICanRegisterStrategies; use Friendica\Core\Hooks\Exceptions\HookConfigException; -use Friendica\Core\Logger\Factory\LoggerFactory; -use Friendica\Util\Strings; -use Psr\Log\LoggerInterface; /** * Manage all strategies.config.php files @@ -28,15 +24,17 @@ class StrategiesFileManager const STATIC_DIR = 'static'; const CONFIG_NAME = 'strategies'; - private IManageConfigValues $configuration; - protected array $config = []; + /** @var ICanLoadAddons */ + protected $addonLoader; + /** @var array */ + protected $config = []; /** @var string */ protected $basePath; - public function __construct(string $basePath, IManageConfigValues $configuration) + public function __construct(string $basePath, ICanLoadAddons $addonLoader) { - $this->basePath = $basePath; - $this->configuration = $configuration; + $this->basePath = $basePath; + $this->addonLoader = $addonLoader; } /** @@ -86,50 +84,6 @@ class StrategiesFileManager /** * @deprecated 2025.02 Providing strategies via addons is deprecated and will be removed in 5 months. */ - $this->config = array_merge_recursive($config, $this->getActiveAddonConfig()); - } - - private function getActiveAddonConfig(): array - { - $addons = array_keys(array_filter($this->configuration->get('addons') ?? [])); - $returnConfig = []; - - foreach ($addons as $addon) { - $addonName = Strings::sanitizeFilePathItem(trim($addon)); - - $configFile = $this->basePath . '/addon/' . $addonName . '/' . static::STATIC_DIR . '/strategies.config.php'; - - if (!file_exists($configFile)) { - // Addon unmodified, skipping - continue; - } - - $config = include $configFile; - - if (!is_array($config)) { - throw new AddonInvalidConfigFileException('Error loading config file ' . $configFile); - } - - foreach ($config as $classname => $rule) { - if ($classname === LoggerInterface::class) { - @trigger_error(sprintf( - 'Providing a strategy for `%s` is deprecated since 2025.02 and will stop working in 5 months, please provide an implementation for `%s` via `dependency.config.php` and remove the `strategies.config.php` file in the `%s` addon.', - $classname, - LoggerFactory::class, - $addonName, - ), \E_USER_DEPRECATED); - } else { - @trigger_error(sprintf( - 'Providing strategies for `%s` via addons is deprecated since 2025.02 and will stop working in 5 months, please stop using this and remove the `strategies.config.php` file in the `%s` addon.', - $classname, - $addonName, - ), \E_USER_DEPRECATED); - } - } - - $returnConfig = array_merge_recursive($returnConfig, $config); - } - - return $returnConfig; + $this->config = array_merge_recursive($config, $this->addonLoader->getActiveAddonConfig(static::CONFIG_NAME)); } } diff --git a/src/Core/Lock/Type/AbstractLock.php b/src/Core/Lock/Type/AbstractLock.php index 6854be267c..9d8b5849b2 100644 --- a/src/Core/Lock/Type/AbstractLock.php +++ b/src/Core/Lock/Type/AbstractLock.php @@ -28,7 +28,7 @@ abstract class AbstractLock implements ICanLock */ protected function hasAcquiredLock(string $key): bool { - return isset($this->acquiredLocks[$key]) && $this->acquiredLocks[$key] === true; + return isset($this->acquireLock[$key]) && $this->acquiredLocks[$key] === true; } /** diff --git a/src/Core/Session/Handler/Cache.php b/src/Core/Session/Handler/Cache.php index 65b87872a7..7629d9a164 100644 --- a/src/Core/Session/Handler/Cache.php +++ b/src/Core/Session/Handler/Cache.php @@ -99,11 +99,8 @@ class Cache extends AbstractSessionHandler } #[\ReturnTypeWillChange] - /** - * @return int|false - */ - public function gc($max_lifetime) + public function gc($max_lifetime): bool { - return 0; // Cache does not support garbage collection, so we return 0 to indicate no action taken + return true; } } diff --git a/src/Core/Session/Handler/Database.php b/src/Core/Session/Handler/Database.php index d8146139a1..3ef64294b9 100644 --- a/src/Core/Session/Handler/Database.php +++ b/src/Core/Session/Handler/Database.php @@ -124,23 +124,13 @@ class Database extends AbstractSessionHandler } #[\ReturnTypeWillChange] - /** - * @return int|false - */ - public function gc($max_lifetime) + public function gc($max_lifetime): bool { try { - $result = $this->dba->delete('session', ["`expire` < ?", time()]); + return $this->dba->delete('session', ["`expire` < ?", time()]); } catch (\Exception $exception) { $this->logger->warning('Cannot use garbage collector.', ['exception' => $exception]); return false; } - - if ($result !== false) { - // TODO: DBA::delete() returns true, but we need to return the number of deleted rows as interger - $result = 0; - } - - return $result; } } diff --git a/src/Core/Worker.php b/src/Core/Worker.php index fd2ab5c242..fd33278502 100644 --- a/src/Core/Worker.php +++ b/src/Core/Worker.php @@ -521,7 +521,7 @@ class Worker } if ($sleeping) { - DI::logger()->info('Cooldown ended.', ['max-load' => $load_cooldown, 'max-processes' => $processes_cooldown, 'load' => $load ?? [], 'called-by' => System::callstack(1)]); + DI::logger()->info('Cooldown ended.', ['max-load' => $load_cooldown, 'max-processes' => $processes_cooldown, 'load' => $load, 'called-by' => System::callstack(1)]); } } diff --git a/src/Database/PostUpdate.php b/src/Database/PostUpdate.php index 031c2fec1d..6aebda8096 100644 --- a/src/Database/PostUpdate.php +++ b/src/Database/PostUpdate.php @@ -193,7 +193,7 @@ class PostUpdate Contact::removeDuplicates($contact['nurl'], $contact['uid']); } - DBA::close($contacts); + DBA::close($contact); DI::keyValue()->set('post_update_version', 1322); DI::logger()->info('Done'); diff --git a/src/Module/Search/Index.php b/src/Module/Search/Index.php index e6e9f39a31..8d395ba880 100644 --- a/src/Module/Search/Index.php +++ b/src/Module/Search/Index.php @@ -136,9 +136,7 @@ class Index extends BaseSearch // Tags don't look like an URL and the fulltext search does only work with natural words if (parse_url($search, PHP_URL_SCHEME) && parse_url($search, PHP_URL_HOST)) { $this->logger->info('Skipping tag and fulltext search since the search looks like a URL.', ['q' => $search]); - $o .= Renderer::replaceMacros(Renderer::getMarkupTemplate('section_title.tpl'), [ - '$title' => DI::l10n()->t('No results.') - ]); + DI::sysmsg()->addNotice(DI::l10n()->t('No results.')); return $o; } @@ -188,9 +186,7 @@ class Index extends BaseSearch if (empty($items)) { if (empty($last_uriid)) { - $o .= Renderer::replaceMacros(Renderer::getMarkupTemplate('section_title.tpl'), [ - '$title' => DI::l10n()->t('No results.') - ]); + DI::sysmsg()->addNotice(DI::l10n()->t('No results.')); } return $o; } diff --git a/src/Module/Settings/Display.php b/src/Module/Settings/Display.php index f4173e82c0..97c163cea6 100644 --- a/src/Module/Settings/Display.php +++ b/src/Module/Settings/Display.php @@ -234,11 +234,11 @@ class Display extends BaseSettings $update_content = $this->pConfig->get($uid, 'system', 'update_content') ?? false; $enable_smile = !$this->pConfig->get($uid, 'system', 'no_smilies', false); - $infinite_scroll = $this->pConfig->get($uid, 'system', 'infinite_scroll', true); + $infinite_scroll = $this->pConfig->get($uid, 'system', 'infinite_scroll', false); $enable_smart_threading = !$this->pConfig->get($uid, 'system', 'no_smart_threading', false); $enable_dislike = !$this->pConfig->get($uid, 'system', 'hide_dislike', false); $display_resharer = $this->pConfig->get($uid, 'system', 'display_resharer', false); - $stay_local = $this->pConfig->get($uid, 'system', 'stay_local', true); + $stay_local = $this->pConfig->get($uid, 'system', 'stay_local', false); $show_page_drop = $this->pConfig->get($uid, 'system', 'show_page_drop', true); $display_eventlist = $this->pConfig->get($uid, 'system', 'display_eventlist', true); diff --git a/src/Network/Probe.php b/src/Network/Probe.php index 92ee97b816..471f6e313a 100644 --- a/src/Network/Probe.php +++ b/src/Network/Probe.php @@ -8,7 +8,7 @@ namespace Friendica\Network; use DOMDocument; -use DOMXPath; +use DomXPath; use Exception; use Friendica\Content\Text\HTML; use Friendica\Core\Hook; @@ -1273,7 +1273,7 @@ class Probe return []; } - $xpath = new DOMXPath($doc); + $xpath = new DomXPath($doc); $vcards = $xpath->query("//div[contains(concat(' ', @class, ' '), ' vcard ')]"); if (!is_object($vcards)) { diff --git a/src/Object/Image.php b/src/Object/Image.php index 56c6f9f325..0aad761341 100644 --- a/src/Object/Image.php +++ b/src/Object/Image.php @@ -48,8 +48,8 @@ class Image public function __construct(string $data, string $type = '', string $filename = '', bool $imagick = true) { $this->filename = $filename; - $type = Images::addMimeTypeByDataIfInvalid($type, $data); - $type = Images::addMimeTypeByExtensionIfInvalid($type, $filename); + $type = Images::addMimeTypeByDataIfInvalid($type, $data); + $type = Images::addMimeTypeByExtensionIfInvalid($type, $filename); if (Images::isSupportedMimeType($type)) { $this->originType = $this->outputType = Images::getImageTypeByMimeType($type); @@ -108,7 +108,7 @@ class Image private function isAnimatedWebP(string $data) { $header_format = 'A4Riff/I1Filesize/A4Webp/A4Vp/A74Chunk'; - $header = @unpack($header_format, $data); + $header = @unpack($header_format, $data); if (!isset($header['Riff']) || strtoupper($header['Riff']) !== 'RIFF') { return false; @@ -348,7 +348,7 @@ class Image return false; } - $width = $this->getWidth(); + $width = $this->getWidth(); $height = $this->getHeight(); $scale = Images::getScalingDimensions($width, $height, $max); @@ -363,11 +363,12 @@ class Image * Rotates image * * @param integer $degrees degrees to rotate image + * @return mixed */ - public function rotate(int $degrees): void + public function rotate(int $degrees) { if (!$this->isValid()) { - return; + return false; } if ($this->isImagick()) { @@ -392,11 +393,12 @@ class Image * * @param boolean $horiz optional, default true * @param boolean $vert optional, default false + * @return mixed */ - public function flip(bool $horiz = true, bool $vert = false): void + public function flip(bool $horiz = true, bool $vert = false) { if (!$this->isValid()) { - return; + return false; } if ($this->isImagick()) { @@ -412,8 +414,8 @@ class Image return; } - $w = imagesx($this->image); - $h = imagesy($this->image); + $w = imagesx($this->image); + $h = imagesy($this->image); $flipped = imagecreate($w, $h); if ($horiz) { for ($x = 0; $x < $w; $x++) { @@ -521,7 +523,7 @@ class Image return false; } - $width = $this->getWidth(); + $width = $this->getWidth(); $height = $this->getHeight(); if ((!$width) || (!$height)) { @@ -530,22 +532,22 @@ class Image if ($width < $min && $height < $min) { if ($width > $height) { - $dest_width = $min; + $dest_width = $min; $dest_height = intval(($height * $min) / $width); } else { - $dest_width = intval(($width * $min) / $height); + $dest_width = intval(($width * $min) / $height); $dest_height = $min; } } else { if ($width < $min) { - $dest_width = $min; + $dest_width = $min; $dest_height = intval(($height * $min) / $width); } else { if ($height < $min) { - $dest_width = intval(($width * $min) / $height); + $dest_width = intval(($width * $min) / $height); $dest_height = $min; } else { - $dest_width = $width; + $dest_width = $width; $dest_height = $height; } } @@ -620,7 +622,7 @@ class Image imagedestroy($this->image); } - $this->image = $dest; + $this->image = $dest; $this->width = imagesx($this->image); $this->height = imagesy($this->image); } @@ -797,9 +799,9 @@ class Image } $row[] = [$colors['r'], $colors['g'], $colors['b']]; } else { - $index = imagecolorat($image->image, $x, $y); + $index = imagecolorat($image->image, $x, $y); $colors = @imagecolorsforindex($image->image, $index); - $row[] = [$colors['red'], $colors['green'], $colors['blue']]; + $row[] = [$colors['red'], $colors['green'], $colors['blue']]; } } $pixels[] = $row; @@ -828,7 +830,7 @@ class Image if ($this->isImagick()) { $this->image = new Imagick(); - $draw = new ImagickDraw(); + $draw = new ImagickDraw(); $this->image->newImage($scaled['width'], $scaled['height'], '', 'png'); } else { $this->image = imagecreatetruecolor($scaled['width'], $scaled['height']); @@ -836,7 +838,7 @@ class Image for ($y = 0; $y < $scaled['height']; ++$y) { for ($x = 0; $x < $scaled['width']; ++$x) { - list($r, $g, $b) = $pixels[$y][$x]; + [$r, $g, $b] = $pixels[$y][$x]; if ($draw !== null) { $draw->setFillColor("rgb($r, $g, $b)"); $draw->point($x, $y); diff --git a/src/Util/HTTPSignature.php b/src/Util/HTTPSignature.php index c5a182f98e..a779a59a86 100644 --- a/src/Util/HTTPSignature.php +++ b/src/Util/HTTPSignature.php @@ -592,7 +592,7 @@ class HTTPSignature return []; } - $sig_block = self::parseSigheader($http_headers['HTTP_SIGNATURE']); + $sig_block = self::parseSigHeader($http_headers['HTTP_SIGNATURE']); if (empty($sig_block['keyId'])) { DI::logger()->debug('No keyId', ['sig_block' => $sig_block]); @@ -652,7 +652,7 @@ class HTTPSignature } } - $sig_block = self::parseSigheader($http_headers['HTTP_SIGNATURE']); + $sig_block = self::parseSigHeader($http_headers['HTTP_SIGNATURE']); // Add fields from the signature block to the header. See issue 8845 if (!empty($sig_block['created']) && empty($headers['(created)'])) { diff --git a/static/dependencies.config.php b/static/dependencies.config.php index 1ce02a2411..04e2dd2aee 100644 --- a/static/dependencies.config.php +++ b/static/dependencies.config.php @@ -39,6 +39,7 @@ return (function(string $basepath, array $getVars, array $serverVars, array $coo 'instanceOf' => \Friendica\Core\Addon\Model\AddonLoader::class, 'constructParams' => [ $basepath, + [Dice::INSTANCE => Dice::SELF], ], ], \Friendica\Core\Addon\AddonHelper::class => [ diff --git a/tests/Unit/Core/Addon/AddonManagerHelperTest.php b/tests/Unit/Core/Addon/AddonManagerHelperTest.php index a63c605538..882082ceb0 100644 --- a/tests/Unit/Core/Addon/AddonManagerHelperTest.php +++ b/tests/Unit/Core/Addon/AddonManagerHelperTest.php @@ -12,7 +12,6 @@ namespace Friendica\Test\Unit\Core\Addon; use Exception; use Friendica\Core\Addon\AddonInfo; use Friendica\Core\Addon\AddonManagerHelper; -use Friendica\Core\Addon\Exception\AddonInvalidConfigFileException; use Friendica\Core\Addon\Exception\InvalidAddonException; use Friendica\Core\Cache\Capability\ICanCache; use Friendica\Core\Config\Capability\IManageConfigValues; @@ -82,76 +81,6 @@ class AddonManagerHelperTest extends TestCase $addonManagerHelper->getAddonInfo('helloaddon'); } - public function testGetAddonDependencyConfigReturnsArray(): void - { - $root = vfsStream::setup(__FUNCTION__ . '_addons', 0777, [ - 'helloaddon' => [ - 'static' => [ - 'dependencies.config.php' => << 'bar', - ]; - PHP, - ], - ] - ]); - - $addonManagerHelper = new AddonManagerHelper( - $root->url(), - $this->createStub(Database::class), - $this->createStub(IManageConfigValues::class), - $this->createStub(ICanCache::class), - $this->createStub(LoggerInterface::class), - $this->createStub(Profiler::class) - ); - - $this->assertSame(['foo' => 'bar'], $addonManagerHelper->getAddonDependencyConfig('helloaddon')); - } - - public function testGetAddonDependencyConfigWithoutConfigFileReturnsEmptyArray(): void - { - $root = vfsStream::setup(__FUNCTION__ . '_addons', 0777, [ - 'helloaddon' => [] - ]); - - $addonManagerHelper = new AddonManagerHelper( - $root->url(), - $this->createStub(Database::class), - $this->createStub(IManageConfigValues::class), - $this->createStub(ICanCache::class), - $this->createStub(LoggerInterface::class), - $this->createStub(Profiler::class) - ); - - $this->assertSame([], $addonManagerHelper->getAddonDependencyConfig('helloaddon')); - } - - public function testGetAddonDependencyConfigWithoutReturningAnArrayThrowsException(): void - { - $root = vfsStream::setup(__FUNCTION__ . '_addons', 0777, [ - 'helloaddon' => [ - 'static' => [ - 'dependencies.config.php' => 'url(), - $this->createStub(Database::class), - $this->createStub(IManageConfigValues::class), - $this->createStub(ICanCache::class), - $this->createStub(LoggerInterface::class), - $this->createStub(Profiler::class) - ); - - $this->expectException(AddonInvalidConfigFileException::class); - $this->expectExceptionMessageMatches('#Error loading config file .+/helloaddon/static/dependencies\.config\.php#'); - - $addonManagerHelper->getAddonDependencyConfig('helloaddon'); - } - public function testEnabledAddons(): void { $config = $this->createStub(IManageConfigValues::class); diff --git a/tests/src/Core/Hooks/Util/StrategiesFileManagerTest.php b/tests/src/Core/Hooks/Util/StrategiesFileManagerTest.php index 7adcfc0a97..633b636701 100644 --- a/tests/src/Core/Hooks/Util/StrategiesFileManagerTest.php +++ b/tests/src/Core/Hooks/Util/StrategiesFileManagerTest.php @@ -7,7 +7,7 @@ namespace Friendica\Test\src\Core\Hooks\Util; -use Friendica\Core\Config\Capability\IManageConfigValues; +use Friendica\Core\Addon\Capability\ICanLoadAddons; use Friendica\Core\Hooks\Capability\ICanRegisterStrategies; use Friendica\Core\Hooks\Exceptions\HookConfigException; use Friendica\Core\Hooks\Util\StrategiesFileManager; @@ -33,61 +33,49 @@ class StrategiesFileManagerTest extends MockedTestCase return [ 'normal' => [ 'content' => << [ - \Psr\Log\NullLogger::class => [''], - ], - ]; - EOF, - 'addonContent' => << [ + \Psr\Log\NullLogger::class => [''], + ], +]; +EOF, + 'addonsArray' => [], 'assertStrategies' => [ [LoggerInterface::class, NullLogger::class, ''], ], ], 'normalWithString' => [ 'content' => << [ - \Psr\Log\NullLogger::class => '', - ], - ]; - EOF, - 'addonContent' => << [ + \Psr\Log\NullLogger::class => '', + ], +]; +EOF, + 'addonsArray' => [], 'assertStrategies' => [ [LoggerInterface::class, NullLogger::class, ''], ], ], 'withAddons' => [ 'content' => << [ - \Psr\Log\NullLogger::class => [''], - ], - ]; - EOF, - 'addonContent' => << [ - \Psr\Log\NullLogger::class => ['null'], - ], - ]; - EOF, +return [ + \Psr\Log\LoggerInterface::class => [ + \Psr\Log\NullLogger::class => [''], + ], +]; +EOF, + 'addonsArray' => [ + \Psr\Log\LoggerInterface::class => [ + \Psr\Log\NullLogger::class => ['null'], + ], + ], 'assertStrategies' => [ [LoggerInterface::class, NullLogger::class, ''], [LoggerInterface::class, NullLogger::class, 'null'], @@ -95,23 +83,19 @@ class StrategiesFileManagerTest extends MockedTestCase ], 'withAddonsWithString' => [ 'content' => << [ - \Psr\Log\NullLogger::class => [''], - ], - ]; - EOF, - 'addonContent' => << [ - \Psr\Log\NullLogger::class => ['null'], - ], - ]; - EOF, +return [ + \Psr\Log\LoggerInterface::class => [ + \Psr\Log\NullLogger::class => [''], + ], +]; +EOF, + 'addonsArray' => [ + \Psr\Log\LoggerInterface::class => [ + \Psr\Log\NullLogger::class => 'null', + ], + ], 'assertStrategies' => [ [LoggerInterface::class, NullLogger::class, ''], [LoggerInterface::class, NullLogger::class, 'null'], @@ -120,23 +104,19 @@ class StrategiesFileManagerTest extends MockedTestCase // This should work because unique name convention is part of the instance manager logic, not of the file-infrastructure layer 'withAddonsDoubleNamed' => [ 'content' => << [ - \Psr\Log\NullLogger::class => [''], - ], - ]; - EOF, - 'addonContent' => << [ - \Psr\Log\NullLogger::class => [''], - ], - ]; - EOF, +return [ + \Psr\Log\LoggerInterface::class => [ + \Psr\Log\NullLogger::class => [''], + ], +]; +EOF, + 'addonsArray' => [ + \Psr\Log\LoggerInterface::class => [ + \Psr\Log\NullLogger::class => [''], + ], + ], 'assertStrategies' => [ [LoggerInterface::class, NullLogger::class, ''], [LoggerInterface::class, NullLogger::class, ''], @@ -148,20 +128,16 @@ class StrategiesFileManagerTest extends MockedTestCase /** * @dataProvider dataHooks */ - public function testSetupHooks(string $content, string $addonContent, array $assertStrategies) + public function testSetupHooks(string $content, array $addonsArray, array $assertStrategies) { vfsStream::newFile(StrategiesFileManager::STATIC_DIR . '/' . StrategiesFileManager::CONFIG_NAME . '.config.php') ->withContent($content) ->at($this->root); - vfsStream::newFile('addon/testaddon/' . StrategiesFileManager::STATIC_DIR . '/' . StrategiesFileManager::CONFIG_NAME . '.config.php') - ->withContent($addonContent) - ->at($this->root); + $addonLoader = \Mockery::mock(ICanLoadAddons::class); + $addonLoader->shouldReceive('getActiveAddonConfig')->andReturn($addonsArray)->once(); - $config = \Mockery::mock(IManageConfigValues::class); - $config->shouldReceive('get')->andReturn(['testaddon' => ['admin' => false]])->once(); - - $hookFileManager = new StrategiesFileManager($this->root->url(), $config); + $hookFileManager = new StrategiesFileManager($this->root->url(), $addonLoader); $instanceManager = \Mockery::mock(ICanRegisterStrategies::class); foreach ($assertStrategies as $assertStrategy) { @@ -179,15 +155,13 @@ class StrategiesFileManagerTest extends MockedTestCase */ public function testMissingStrategiesFile() { - $config = \Mockery::mock(IManageConfigValues::class); + $addonLoader = \Mockery::mock(ICanLoadAddons::class); $instanceManager = \Mockery::mock(ICanRegisterStrategies::class); - $hookFileManager = new StrategiesFileManager($this->root->url(), $config); + $hookFileManager = new StrategiesFileManager($this->root->url(), $addonLoader); self::expectException(HookConfigException::class); - self::expectExceptionMessage(sprintf( - 'config file %s does not exist.', - $this->root->url() . '/' . StrategiesFileManager::STATIC_DIR . '/' . StrategiesFileManager::CONFIG_NAME . '.config.php' - )); + self::expectExceptionMessage(sprintf('config file %s does not exist.', + $this->root->url() . '/' . StrategiesFileManager::STATIC_DIR . '/' . StrategiesFileManager::CONFIG_NAME . '.config.php')); $hookFileManager->loadConfig(); } @@ -197,19 +171,17 @@ class StrategiesFileManagerTest extends MockedTestCase */ public function testWrongStrategiesFile() { - $config = \Mockery::mock(IManageConfigValues::class); + $addonLoader = \Mockery::mock(ICanLoadAddons::class); $instanceManager = \Mockery::mock(ICanRegisterStrategies::class); - $hookFileManager = new StrategiesFileManager($this->root->url(), $config); + $hookFileManager = new StrategiesFileManager($this->root->url(), $addonLoader); vfsStream::newFile(StrategiesFileManager::STATIC_DIR . '/' . StrategiesFileManager::CONFIG_NAME . '.config.php') ->withContent("at($this->root); self::expectException(HookConfigException::class); - self::expectExceptionMessage(sprintf( - 'Error loading config file %s.', - $this->root->url() . '/' . StrategiesFileManager::STATIC_DIR . '/' . StrategiesFileManager::CONFIG_NAME . '.config.php' - )); + self::expectExceptionMessage(sprintf('Error loading config file %s.', + $this->root->url() . '/' . StrategiesFileManager::STATIC_DIR . '/' . StrategiesFileManager::CONFIG_NAME . '.config.php')); $hookFileManager->loadConfig(); } diff --git a/view/global.css b/view/global.css index 86e8ccc933..0215e6d4df 100644 --- a/view/global.css +++ b/view/global.css @@ -806,7 +806,6 @@ summary.wall-item-summary { /* Margin to create space between the icon and the text */ .notif-image { margin-right: 10px; -} /* Styles to ensure the text wraps properly after 70 characters */ .notif-text { @@ -814,16 +813,3 @@ summary.wall-item-summary { max-width: 70ch; overflow-wrap: break-word; } - -/* Add alt tag indicators to the relevant images */ -a:has(img.has-alt-description)::after { - background: lightgray; - border-radius: 4px; - color: black; - content: "ALT"; - font-weight: bold; - padding: 3px 8px; - position: absolute; - bottom: 10px; - right: 10px; -} diff --git a/view/lang/C/messages.po b/view/lang/C/messages.po index 3988254f0a..4aa51dc1cd 100644 --- a/view/lang/C/messages.po +++ b/view/lang/C/messages.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: 2025.02-dev\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2025-06-21 13:03+0200\n" +"POT-Creation-Date: 2025-06-14 15:06+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -646,7 +646,7 @@ msgstr "" msgid "Map" msgstr "" -#: src/App.php:454 +#: src/App.php:451 msgid "Apologies but the website is unavailable at the moment." msgstr "" @@ -2227,11 +2227,11 @@ msgstr "" msgid "prev" msgstr "" -#: src/Content/Pager.php:246 src/Module/Calendar/Show.php:122 +#: src/Content/Pager.php:262 src/Module/Calendar/Show.php:122 msgid "next" msgstr "" -#: src/Content/Pager.php:251 +#: src/Content/Pager.php:267 msgid "last" msgstr "" @@ -6108,7 +6108,7 @@ msgstr "" msgid "Search your contacts" msgstr "" -#: src/Module/Contact.php:441 src/Module/Search/Index.php:206 +#: src/Module/Contact.php:441 src/Module/Search/Index.php:202 #, php-format msgid "Results for: %s" msgstr "" @@ -6698,8 +6698,8 @@ msgid "Unable to unfollow this contact, please contact your administrator" msgstr "" #: src/Module/Conversation/Channel.php:125 -#: src/Module/Conversation/Community.php:114 src/Module/Search/Index.php:140 -#: src/Module/Search/Index.php:192 +#: src/Module/Conversation/Community.php:114 src/Module/Search/Index.php:139 +#: src/Module/Search/Index.php:189 msgid "No results." msgstr "" @@ -8901,7 +8901,7 @@ msgstr "" msgid "Only one search per minute is permitted for not logged in users." msgstr "" -#: src/Module/Search/Index.php:204 +#: src/Module/Search/Index.php:200 #, php-format msgid "Items tagged with: %s" msgstr "" diff --git a/view/theme/frio/js/theme.js b/view/theme/frio/js/theme.js index d11f953127..ad59a3f633 100644 --- a/view/theme/frio/js/theme.js +++ b/view/theme/frio/js/theme.js @@ -174,8 +174,9 @@ $(document).ready(function () { // temporary workaround to avoid 'undefined' being displayed (issue #9789) // https://github.com/friendica/friendica/issues/9789 + // TODO: find a way to localize this string if (typeof searchText === "undefined") { - searchText = ""; + searchText = "No results"; } // insert the plain text in a

heading and give it a class var newText = '

' + searchText + "

"; diff --git a/view/theme/frio/templates/nav.tpl b/view/theme/frio/templates/nav.tpl index 843a2cf00d..37edb7118a 100644 --- a/view/theme/frio/templates/nav.tpl +++ b/view/theme/frio/templates/nav.tpl @@ -164,7 +164,7 @@