Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,23 @@ All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com), and this project adheres to [Semantic Versioning](https://semver.org).

## [5.1.7] - 2026-09-21
### Added
* *Nothing*

### Changed
* *Nothing*

### Deprecated
* *Nothing*

### Removed
* *Nothing*

### Fixed
* [#2658](https://github.com/shlinkio/shlink/issues/2658) Fix redis connections left open sometimes.


## [5.1.6] - 2026-09-06
### Added
* *Nothing*
Expand Down
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
"pagerfanta/core": "^3.8",
"ramsey/uuid": "^4.9",
"shlinkio/doctrine-specification": "^2.3",
"shlinkio/shlink-common": "^9.0.1",
"shlinkio/shlink-common": "^9.0.2",
"shlinkio/shlink-config": "^4.1.0",
"shlinkio/shlink-event-dispatcher": "^4.4.0",
"shlinkio/shlink-importer": "^5.8",
Expand Down
100 changes: 2 additions & 98 deletions mago-analyze-baseline.toml
Original file line number Diff line number Diff line change
Expand Up @@ -450,54 +450,6 @@ code = "less-specific-nested-argument-type"
message = 'Argument type mismatch for argument #1 of `Symfony\Component\Process\Process::__construct`: expected `array<array-key, string>`, but provided type `array<array-key, mixed>` is less specific.'
count = 1

[[issues]]
file = "module/CLI/src/Util/ProcessRunner.php"
code = "mixed-argument"
message = "Invalid argument type for argument #1 of `spl_object_hash`: expected `object`, but found `mixed`."
count = 2

[[issues]]
file = "module/CLI/src/Util/ProcessRunner.php"
code = "mixed-argument"
message = 'Invalid argument type for argument #2 of `Symfony\Component\Console\Helper\ProcessHelper::wrapCallback`: expected `Symfony\Component\Process\Process`, but found `mixed`.'
count = 1

[[issues]]
file = "module/CLI/src/Util/ProcessRunner.php"
code = "mixed-argument"
message = "Invalid argument type for argument #2 of `sprintf`: expected `Stringable|null|scalar`, but found `mixed`."
count = 1

[[issues]]
file = "module/CLI/src/Util/ProcessRunner.php"
code = "mixed-argument"
message = 'Invalid argument type for argument #3 of `Symfony\Component\Console\Helper\DebugFormatterHelper::stop`: expected `bool`, but found `mixed`.'
count = 1

[[issues]]
file = "module/CLI/src/Util/ProcessRunner.php"
code = "mixed-argument"
message = "Invalid argument type for argument #3 of `str_replace`: expected `array<array-key, string>|string`, but found `mixed`."
count = 1

[[issues]]
file = "module/CLI/src/Util/ProcessRunner.php"
code = "mixed-assignment"
message = "Assigning `mixed` type to a variable may lead to unexpected behavior."
count = 1

[[issues]]
file = "module/CLI/src/Util/ProcessRunner.php"
code = "mixed-method-access"
message = "Attempting to access a method on a non-object type (`mixed`)."
count = 5

[[issues]]
file = "module/CLI/src/Util/ProcessRunner.php"
code = "possibly-invalid-argument"
message = 'Possible argument type mismatch for argument #2 of `Symfony\Component\Console\Helper\DebugFormatterHelper::start`: expected `string`, but possibly received `array<array-key, string>|string`.'
count = 1

[[issues]]
file = "module/CLI/src/Util/ShlinkTable.php"
code = "mixed-assignment"
Expand Down Expand Up @@ -642,12 +594,6 @@ code = "mixed-argument"
message = "Invalid argument type for argument #6 of `sprintf`: expected `Stringable|null|scalar`, but found `mixed`."
count = 1

[[issues]]
file = "module/Core/functions/functions.php"
code = "mixed-array-access"
message = "Unsafe array access on type `nonnull`."
count = 1

[[issues]]
file = "module/Core/functions/functions.php"
code = "mixed-array-assignment"
Expand Down Expand Up @@ -723,7 +669,7 @@ count = 1
[[issues]]
file = "module/Core/functions/functions.php"
code = "possibly-null-argument"
message = "Argument #3 of function `preg_replace` is possibly `null`, but parameter type `array<array-key, string>|string` does not accept it."
message = "Argument #3 of function `preg_replace` is possibly `null`, but parameter type `array<('K.preg_replace() extends array-key), string>|string` does not accept it."
count = 1

[[issues]]
Expand Down Expand Up @@ -1098,17 +1044,11 @@ code = "mixed-array-access"
message = "Unsafe array access on type `mixed`."
count = 1

[[issues]]
file = "module/Core/src/Config/PostProcessor/ShortUrlMethodsProcessor.php"
code = "mixed-array-assignment"
message = "Unsafe array assignment on type `nonnull`."
count = 1

[[issues]]
file = "module/Core/src/Config/PostProcessor/ShortUrlMethodsProcessor.php"
code = "mixed-assignment"
message = "Assigning `mixed` type to a variable may lead to unexpected behavior."
count = 2
count = 1

[[issues]]
file = "module/Core/src/Config/PostProcessor/ShortUrlMethodsProcessor.php"
Expand Down Expand Up @@ -1452,12 +1392,6 @@ code = "possibly-null-argument"
message = 'Argument #2 of method `Happyr\DoctrineSpecification\Repository\EntitySpecificationRepositoryTrait::applySpecification` is possibly `null`, but parameter type `Happyr\DoctrineSpecification\Filter\Filter|Happyr\DoctrineSpecification\Query\QueryModifier` does not accept it.'
count = 1

[[issues]]
file = "module/Core/src/ShortUrl/Repository/ShortUrlListRepository.php"
code = "possibly-null-property-access"
message = "Attempting to access a property on a possibly `null` value."
count = 2

[[issues]]
file = "module/Core/src/ShortUrl/Repository/ShortUrlRepository.php"
code = "mixed-assignment"
Expand Down Expand Up @@ -1764,12 +1698,6 @@ code = "mixed-method-access"
message = "Attempting to access a method on a non-object type (`mixed`)."
count = 1

[[issues]]
file = "module/Core/src/Visit/Repository/VisitIterationRepository.php"
code = "possibly-null-property-access"
message = "Attempting to access a property on a possibly `null` value."
count = 2

[[issues]]
file = "module/Core/src/Visit/Repository/VisitRepository.php"
code = "array-to-string-conversion"
Expand Down Expand Up @@ -1806,12 +1734,6 @@ code = "less-specific-nested-return-statement"
message = '''Returned type `array<array-key, mixed>` is less specific than the declared return type `array<array-key, Shlinkio\Shlink\Core\Visit\Entity\Visit>` for function `Shlinkio\Shlink\Core\Visit\Repository\VisitRepository::findVisitsByTag` due to nested 'mixed'.'''
count = 1

[[issues]]
file = "module/Core/src/Visit/Repository/VisitRepository.php"
code = "mixed-argument"
message = 'Invalid argument type for argument #1 of `Doctrine\DBAL\Connection::quote`: expected `string`, but found `mixed`.'
count = 2

[[issues]]
file = "module/Core/src/Visit/Repository/VisitRepository.php"
code = "mixed-return-statement"
Expand All @@ -1824,24 +1746,12 @@ code = "mixed-return-statement"
message = 'Could not infer a precise return type for function `Shlinkio\Shlink\Core\Visit\Repository\VisitRepository::resolveVisitsWithNativeQuery`. Saw type `mixed`.'
count = 1

[[issues]]
file = "module/Core/src/Visit/Repository/VisitRepository.php"
code = "possible-method-access-on-null"
message = "Attempting to call a method on `null`."
count = 2

[[issues]]
file = "module/Core/src/Visit/Repository/VisitRepository.php"
code = "possibly-null-argument"
message = 'Argument #2 of method `Happyr\DoctrineSpecification\Repository\EntitySpecificationRepositoryTrait::applySpecification` is possibly `null`, but parameter type `Happyr\DoctrineSpecification\Filter\Filter|Happyr\DoctrineSpecification\Query\QueryModifier` does not accept it.'
count = 3

[[issues]]
file = "module/Core/src/Visit/Repository/VisitRepository.php"
code = "possibly-null-property-access"
message = "Attempting to access a property on a possibly `null` value."
count = 2

[[issues]]
file = "module/Core/src/Visit/RequestTracker.php"
code = "mixed-assignment"
Expand Down Expand Up @@ -2118,12 +2028,6 @@ code = "less-specific-argument"
message = 'Argument type mismatch for argument #1 of `ShlinkioTest\Shlink\Core\RedirectRule\Entity\ShortUrlRedirectRuleTest::createRule`: expected `Doctrine\Common\Collections\ArrayCollection<int, Shlinkio\Shlink\Core\RedirectRule\Entity\RedirectCondition>`, but provided type `Doctrine\Common\Collections\ArrayCollection<array-key, mixed>` is less specific.'
count = 1

[[issues]]
file = "module/Core/test/ShortUrl/Entity/ShortUrlTest.php"
code = "possibly-invalid-argument"
message = 'Possible argument type mismatch for argument #1 of `PHPUnit\Framework\Assert::assertStringStartsWith`: expected `non-empty-string`, but possibly received `string`.'
count = 1

[[issues]]
file = "module/Core/test/ShortUrl/Helper/ShortCodeUniquenessHelperTest.php"
code = "redundant-comparison"
Expand Down
3 changes: 3 additions & 0 deletions module/CLI/src/Util/PhpProcessRunner.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ public function __construct(private ProcessRunnerInterface $wrappedProcessRunner
$this->phpBinary = $phpFinder->find(includeArgs: false) ?: 'php';
}

/**
* @inheritDoc
*/
public function run(OutputInterface $output, array $cmd): void
{
$this->wrappedProcessRunner->run($output, [$this->phpBinary, ...$cmd]);
Expand Down
16 changes: 13 additions & 3 deletions module/CLI/src/Util/ProcessRunner.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,23 +11,30 @@
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Process\Process;

use function spl_object_hash;
use function spl_object_id;
use function sprintf;
use function str_replace;

class ProcessRunner implements ProcessRunnerInterface
{
private const int TIMEOUT = 1_200; // 20 minutes

/** @var Closure(string[] $cmd): Process */
private Closure $createProcess;

/**
* @param null|(callable(string[] $cmd): Process) $createProcess
*/
public function __construct(private readonly ProcessHelper $helper, callable|null $createProcess = null)
{
$this->createProcess = $createProcess !== null
? $createProcess(...)
: static fn (array $cmd) => new Process($cmd, timeout: self::TIMEOUT);
}

/**
* @inheritDoc
*/
public function run(OutputInterface $output, array $cmd): void
{
if ($output instanceof ConsoleOutputInterface) {
Expand All @@ -40,7 +47,10 @@ public function run(OutputInterface $output, array $cmd): void

if ($output->isVeryVerbose()) {
$output->write(
$formatter->start(spl_object_hash($process), str_replace('<', '\\<', $process->getCommandLine())),
$formatter->start(
(string) spl_object_id($process),
str_replace('<', '\\<', $process->getCommandLine()),
),
);
}

Expand All @@ -54,7 +64,7 @@ public function run(OutputInterface $output, array $cmd): void
'%s Command did not run successfully',
$process->getExitCode(),
);
$output->write($formatter->stop(spl_object_hash($process), $message, $process->isSuccessful()));
$output->write($formatter->stop((string) spl_object_id($process), $message, $process->isSuccessful()));
}
}
}
3 changes: 3 additions & 0 deletions module/CLI/src/Util/ProcessRunnerInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,8 @@

interface ProcessRunnerInterface
{
/**
* @param string[] $cmd
*/
public function run(OutputInterface $output, array $cmd): void;
}
Original file line number Diff line number Diff line change
Expand Up @@ -117,10 +117,12 @@ private function tryToResolveTitle(ResponseInterface $response, string $contentT
}

return (
$this->encodeToUtf8WithMbString($titleInOriginalEncoding, $pageCharset) ?? $this->encodeToUtf8WithIconv(
$this->encodeToUtf8WithMbString($titleInOriginalEncoding, $pageCharset)
?? $this->encodeToUtf8WithIconv(
$titleInOriginalEncoding,
$pageCharset,
) ?? $titleInOriginalEncoding
)
?? $titleInOriginalEncoding
);
}

Expand Down
13 changes: 7 additions & 6 deletions module/Core/src/ShortUrl/Persistence/ShortUrlsCountFiltering.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,13 @@ public function __construct(
public readonly TagsMode $excludeTagsMode = TagsMode::ANY,
string|null $apiKeyName = null,
) {
$this->searchIncludesDefaultDomain = !empty($searchTerm)
&& !empty($defaultDomain)
&& str_contains(
strtolower($defaultDomain),
strtolower($searchTerm),
);
$this->searchIncludesDefaultDomain =
!empty($searchTerm)
&& !empty($defaultDomain)
&& str_contains(
strtolower($defaultDomain),
strtolower($searchTerm),
);

// Filtering by API key name is only allowed if the API key used in the request is an admin one, or it matches
// the API key name
Expand Down
Loading