mirror of
https://github.com/shlinkio/shlink.git
synced 2024-11-26 14:53:48 +03:00
Fix error when importing short URLs while using Postgres
This commit is contained in:
parent
3a43aa4d41
commit
1b14bb07b1
3 changed files with 27 additions and 11 deletions
|
@ -18,7 +18,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com), and this
|
||||||
* *Nothing*
|
* *Nothing*
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
* *Nothing*
|
* [#1947](https://github.com/shlinkio/shlink/issues/1947) Fix error when importing short URLs while using Postgres.
|
||||||
|
|
||||||
|
|
||||||
## [3.7.0] - 2023-11-25
|
## [3.7.0] - 2023-11-25
|
||||||
|
|
|
@ -12,9 +12,9 @@ use Shlinkio\Shlink\Importer\Model\ImportedShlinkVisit;
|
||||||
use function Shlinkio\Shlink\Core\normalizeDate;
|
use function Shlinkio\Shlink\Core\normalizeDate;
|
||||||
use function sprintf;
|
use function sprintf;
|
||||||
|
|
||||||
final class ShortUrlImporting
|
final readonly class ShortUrlImporting
|
||||||
{
|
{
|
||||||
private function __construct(private readonly ShortUrl $shortUrl, private readonly bool $isNew)
|
private function __construct(private ShortUrl $shortUrl, private bool $isNew)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -57,11 +57,18 @@ final class ShortUrlImporting
|
||||||
|
|
||||||
private function resolveShortUrl(EntityManagerInterface $em): ShortUrl
|
private function resolveShortUrl(EntityManagerInterface $em): ShortUrl
|
||||||
{
|
{
|
||||||
|
// If wrapped ShortUrl has no ID, avoid trying to query the EM, as it would fail in Postgres.
|
||||||
|
// See https://github.com/shlinkio/shlink/issues/1947
|
||||||
|
$id = $this->shortUrl->getId();
|
||||||
|
if (!$id) {
|
||||||
|
return $this->shortUrl;
|
||||||
|
}
|
||||||
|
|
||||||
// Instead of directly accessing wrapped ShortUrl entity, try to get it from the EM.
|
// Instead of directly accessing wrapped ShortUrl entity, try to get it from the EM.
|
||||||
// With this, we will get the same entity from memory if it is known by the EM, but if it was cleared, the EM
|
// With this, we will get the same entity from memory if it is known by the EM, but if it was cleared, the EM
|
||||||
// will fetch it again from the database, preventing errors at runtime.
|
// will fetch it again from the database, preventing errors at runtime.
|
||||||
// However, if the EM was not flushed yet, the entity will not be found by ID, but it is known by the EM.
|
// However, if the EM was not flushed yet, the entity will not be found by ID, but it is known by the EM.
|
||||||
// In that case, we fall back to wrapped ShortUrl entity directly.
|
// In that case, we fall back to wrapped ShortUrl entity directly.
|
||||||
return $em->find(ShortUrl::class, $this->shortUrl->getId()) ?? $this->shortUrl;
|
return $em->find(ShortUrl::class, $id) ?? $this->shortUrl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -232,15 +232,20 @@ class ImportedLinksProcessorTest extends TestCase
|
||||||
}
|
}
|
||||||
|
|
||||||
#[Test, DataProvider('provideFoundShortUrls')]
|
#[Test, DataProvider('provideFoundShortUrls')]
|
||||||
public function visitsArePersistedWithProperShortUrl(?ShortUrl $foundShortUrl): void
|
public function visitsArePersistedWithProperShortUrl(ShortUrl $originalShortUrl, ?ShortUrl $foundShortUrl): void
|
||||||
{
|
{
|
||||||
$originalShortUrl = ShortUrl::withLongUrl('https://foo');
|
|
||||||
|
|
||||||
$this->em->method('getRepository')->with(ShortUrl::class)->willReturn($this->repo);
|
$this->em->method('getRepository')->with(ShortUrl::class)->willReturn($this->repo);
|
||||||
$this->repo->expects($this->once())->method('findOneByImportedUrl')->willReturn($originalShortUrl);
|
$this->repo->expects($this->once())->method('findOneByImportedUrl')->willReturn($originalShortUrl);
|
||||||
$this->em->expects($this->exactly(2))->method('find')->willReturn($foundShortUrl);
|
if (!$originalShortUrl->getId()) {
|
||||||
|
$this->em->expects($this->never())->method('find');
|
||||||
|
} else {
|
||||||
|
$this->em->expects($this->exactly(2))->method('find')->willReturn($foundShortUrl);
|
||||||
|
}
|
||||||
$this->em->expects($this->once())->method('persist')->willReturnCallback(
|
$this->em->expects($this->once())->method('persist')->willReturnCallback(
|
||||||
static fn (Visit $visit) => Assert::assertSame($foundShortUrl ?? $originalShortUrl, $visit->getShortUrl()),
|
static fn (Visit $visit) => Assert::assertSame(
|
||||||
|
$foundShortUrl ?? $originalShortUrl,
|
||||||
|
$visit->getShortUrl(),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
$now = Chronos::now();
|
$now = Chronos::now();
|
||||||
|
@ -253,8 +258,12 @@ class ImportedLinksProcessorTest extends TestCase
|
||||||
|
|
||||||
public static function provideFoundShortUrls(): iterable
|
public static function provideFoundShortUrls(): iterable
|
||||||
{
|
{
|
||||||
yield [null];
|
yield 'not found new URL' => [ShortUrl::withLongUrl('https://foo')->setId('123'), null];
|
||||||
yield [ShortUrl::withLongUrl('https://bar')];
|
yield 'found new URL' => [
|
||||||
|
ShortUrl::withLongUrl('https://foo')->setId('123'),
|
||||||
|
ShortUrl::withLongUrl('https://bar'),
|
||||||
|
];
|
||||||
|
yield 'old URL without ID' => [$originalShortUrl = ShortUrl::withLongUrl('https://foo'), $originalShortUrl];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in a new issue