diff --git a/module/CLI/src/Command/Domain/DomainRedirectsCommand.php b/module/CLI/src/Command/Domain/DomainRedirectsCommand.php index 9a97e5fd..90cfd1f7 100644 --- a/module/CLI/src/Command/Domain/DomainRedirectsCommand.php +++ b/module/CLI/src/Command/Domain/DomainRedirectsCommand.php @@ -92,7 +92,7 @@ class DomainRedirectsCommand extends Command }; }; - $this->domainService->configureNotFoundRedirects($domainAuthority, new NotFoundRedirects( + $this->domainService->configureNotFoundRedirects($domainAuthority, NotFoundRedirects::withRedirects( $ask( 'URL to redirect to when a user hits this domain\'s base URL', $domain?->baseUrlRedirect(), diff --git a/module/CLI/test/Command/Domain/DomainRedirectsCommandTest.php b/module/CLI/test/Command/Domain/DomainRedirectsCommandTest.php index 1f8b93ab..9801930e 100644 --- a/module/CLI/test/Command/Domain/DomainRedirectsCommandTest.php +++ b/module/CLI/test/Command/Domain/DomainRedirectsCommandTest.php @@ -40,7 +40,7 @@ class DomainRedirectsCommandTest extends TestCase $findDomain = $this->domainService->findByAuthority($domainAuthority)->willReturn($domain); $configureRedirects = $this->domainService->configureNotFoundRedirects( $domainAuthority, - new NotFoundRedirects('foo.com', null, 'baz.com'), + NotFoundRedirects::withRedirects('foo.com', null, 'baz.com'), )->willReturn(Domain::withAuthority('')); $this->commandTester->setInputs(['foo.com', '', 'baz.com']); @@ -71,12 +71,12 @@ class DomainRedirectsCommandTest extends TestCase { $domainAuthority = 'example.com'; $domain = Domain::withAuthority($domainAuthority); - $domain->configureNotFoundRedirects(new NotFoundRedirects('foo.com', 'bar.com', 'baz.com')); + $domain->configureNotFoundRedirects(NotFoundRedirects::withRedirects('foo.com', 'bar.com', 'baz.com')); $findDomain = $this->domainService->findByAuthority($domainAuthority)->willReturn($domain); $configureRedirects = $this->domainService->configureNotFoundRedirects( $domainAuthority, - new NotFoundRedirects(null, 'edited.com', 'baz.com'), + NotFoundRedirects::withRedirects(null, 'edited.com', 'baz.com'), )->willReturn($domain); $this->commandTester->setInputs(['2', '1', 'edited.com', '0']); @@ -105,7 +105,7 @@ class DomainRedirectsCommandTest extends TestCase $findDomain = $this->domainService->findByAuthority($domainAuthority)->willReturn($domain); $configureRedirects = $this->domainService->configureNotFoundRedirects( $domainAuthority, - new NotFoundRedirects(), + NotFoundRedirects::withoutRedirects(), )->willReturn($domain); $this->commandTester->setInputs([$domainAuthority, '', '', '']); @@ -132,7 +132,7 @@ class DomainRedirectsCommandTest extends TestCase $findDomain = $this->domainService->findByAuthority($domainAuthority)->willReturn($domain); $configureRedirects = $this->domainService->configureNotFoundRedirects( $domainAuthority, - new NotFoundRedirects(), + NotFoundRedirects::withoutRedirects(), )->willReturn($domain); $this->commandTester->setInputs(['1', '', '', '']); @@ -162,7 +162,7 @@ class DomainRedirectsCommandTest extends TestCase $findDomain = $this->domainService->findByAuthority($domainAuthority)->willReturn($domain); $configureRedirects = $this->domainService->configureNotFoundRedirects( $domainAuthority, - new NotFoundRedirects(), + NotFoundRedirects::withoutRedirects(), )->willReturn($domain); $this->commandTester->setInputs(['2', $domainAuthority, '', '', '']); diff --git a/module/CLI/test/Command/Domain/ListDomainsCommandTest.php b/module/CLI/test/Command/Domain/ListDomainsCommandTest.php index 3f31f7e0..13e6d062 100644 --- a/module/CLI/test/Command/Domain/ListDomainsCommandTest.php +++ b/module/CLI/test/Command/Domain/ListDomainsCommandTest.php @@ -36,7 +36,7 @@ class ListDomainsCommandTest extends TestCase public function allDomainsAreProperlyPrinted(array $input, string $expectedOutput): void { $bazDomain = Domain::withAuthority('baz.com'); - $bazDomain->configureNotFoundRedirects(new NotFoundRedirects( + $bazDomain->configureNotFoundRedirects(NotFoundRedirects::withRedirects( null, 'https://foo.com/baz-domain/regular', 'https://foo.com/baz-domain/invalid', diff --git a/module/Core/src/Config/NotFoundRedirects.php b/module/Core/src/Config/NotFoundRedirects.php index bb8c578c..c00d35d0 100644 --- a/module/Core/src/Config/NotFoundRedirects.php +++ b/module/Core/src/Config/NotFoundRedirects.php @@ -8,13 +8,26 @@ use JsonSerializable; final class NotFoundRedirects implements JsonSerializable { - public function __construct( - private ?string $baseUrlRedirect = null, - private ?string $regular404Redirect = null, - private ?string $invalidShortUrlRedirect = null, + private function __construct( + private ?string $baseUrlRedirect, + private ?string $regular404Redirect, + private ?string $invalidShortUrlRedirect, ) { } + public static function withRedirects( + ?string $baseUrlRedirect = null, + ?string $regular404Redirect = null, + ?string $invalidShortUrlRedirect = null, + ): self { + return new self($baseUrlRedirect, $regular404Redirect, $invalidShortUrlRedirect); + } + + public static function withoutRedirects(): self + { + return new self(null, null, null); + } + public function baseUrlRedirect(): ?string { return $this->baseUrlRedirect; diff --git a/module/Core/src/Domain/Validation/DomainRedirectsInputFilter.php b/module/Core/src/Domain/Validation/DomainRedirectsInputFilter.php new file mode 100644 index 00000000..94c15217 --- /dev/null +++ b/module/Core/src/Domain/Validation/DomainRedirectsInputFilter.php @@ -0,0 +1,50 @@ +initializeInputs(); + $instance->setData($data); + + return $instance; + } + + private function initializeInputs(): void + { + $domain = $this->createInput(self::DOMAIN); + $domain->getValidatorChain()->attach(new Validator\NotEmpty([ + Validator\NotEmpty::OBJECT, + Validator\NotEmpty::SPACE, + Validator\NotEmpty::NULL, + Validator\NotEmpty::EMPTY_ARRAY, + Validator\NotEmpty::BOOLEAN, + ])); + $this->add($domain); + + $this->add($this->createInput(self::BASE_URL_REDIRECT, false)); + $this->add($this->createInput(self::REGULAR_404_REDIRECT, false)); + $this->add($this->createInput(self::INVALID_SHORT_URL_REDIRECT, false)); + } +} diff --git a/module/Core/test-db/Domain/Repository/DomainRepositoryTest.php b/module/Core/test-db/Domain/Repository/DomainRepositoryTest.php index f52ba54a..c58edfe6 100644 --- a/module/Core/test-db/Domain/Repository/DomainRepositoryTest.php +++ b/module/Core/test-db/Domain/Repository/DomainRepositoryTest.php @@ -45,7 +45,7 @@ class DomainRepositoryTest extends DatabaseTestCase $this->getEntityManager()->persist($detachedDomain); $detachedWithRedirects = Domain::withAuthority('detached-with-redirects.com'); - $detachedWithRedirects->configureNotFoundRedirects(new NotFoundRedirects('foo.com', 'bar.com')); + $detachedWithRedirects->configureNotFoundRedirects(NotFoundRedirects::withRedirects('foo.com', 'bar.com')); $this->getEntityManager()->persist($detachedWithRedirects); $this->getEntityManager()->flush(); @@ -101,7 +101,7 @@ class DomainRepositoryTest extends DatabaseTestCase $this->getEntityManager()->persist($detachedDomain); $detachedWithRedirects = Domain::withAuthority('detached-with-redirects.com'); - $detachedWithRedirects->configureNotFoundRedirects(new NotFoundRedirects('foo.com', 'bar.com')); + $detachedWithRedirects->configureNotFoundRedirects(NotFoundRedirects::withRedirects('foo.com', 'bar.com')); $this->getEntityManager()->persist($detachedWithRedirects); $this->getEntityManager()->flush(); diff --git a/module/Core/test/Domain/DomainServiceTest.php b/module/Core/test/Domain/DomainServiceTest.php index 060b24ab..812210dd 100644 --- a/module/Core/test/Domain/DomainServiceTest.php +++ b/module/Core/test/Domain/DomainServiceTest.php @@ -183,7 +183,7 @@ class DomainServiceTest extends TestCase $persist = $this->em->persist($foundDomain ?? Argument::type(Domain::class)); $flush = $this->em->flush(); - $result = $this->domainService->configureNotFoundRedirects($authority, new NotFoundRedirects( + $result = $this->domainService->configureNotFoundRedirects($authority, NotFoundRedirects::withRedirects( 'foo.com', 'bar.com', 'baz.com', diff --git a/module/Rest/src/Action/Domain/Request/DomainRedirectsRequest.php b/module/Rest/src/Action/Domain/Request/DomainRedirectsRequest.php index 8b9f69e5..e2b27e23 100644 --- a/module/Rest/src/Action/Domain/Request/DomainRedirectsRequest.php +++ b/module/Rest/src/Action/Domain/Request/DomainRedirectsRequest.php @@ -6,6 +6,8 @@ namespace Shlinkio\Shlink\Rest\Action\Domain\Request; use Shlinkio\Shlink\Core\Config\NotFoundRedirectConfigInterface; use Shlinkio\Shlink\Core\Config\NotFoundRedirects; +use Shlinkio\Shlink\Core\Domain\Validation\DomainRedirectsInputFilter; +use Shlinkio\Shlink\Core\Exception\ValidationException; use function array_key_exists; @@ -30,17 +32,33 @@ class DomainRedirectsRequest return $instance; } + /** + * @throws ValidationException + */ private function validateAndInit(array $payload): void { - // TODO Validate data - $this->baseUrlRedirectWasProvided = array_key_exists('baseUrlRedirect', $payload); - $this->regular404RedirectWasProvided = array_key_exists('regular404Redirect', $payload); - $this->invalidShortUrlRedirectWasProvided = array_key_exists('invalidShortUrlRedirect', $payload); + $inputFilter = DomainRedirectsInputFilter::withData($payload); + if (! $inputFilter->isValid()) { + throw ValidationException::fromInputFilter($inputFilter); + } - $this->authority = $payload['domain']; - $this->baseUrlRedirect = $payload['baseUrlRedirect'] ?? null; - $this->regular404Redirect = $payload['regular404Redirect'] ?? null; - $this->invalidShortUrlRedirect = $payload['invalidShortUrlRedirect'] ?? null; + $this->baseUrlRedirectWasProvided = array_key_exists( + DomainRedirectsInputFilter::BASE_URL_REDIRECT, + $payload, + ); + $this->regular404RedirectWasProvided = array_key_exists( + DomainRedirectsInputFilter::REGULAR_404_REDIRECT, + $payload, + ); + $this->invalidShortUrlRedirectWasProvided = array_key_exists( + DomainRedirectsInputFilter::INVALID_SHORT_URL_REDIRECT, + $payload, + ); + + $this->authority = $inputFilter->getValue(DomainRedirectsInputFilter::DOMAIN); + $this->baseUrlRedirect = $inputFilter->getValue(DomainRedirectsInputFilter::BASE_URL_REDIRECT); + $this->regular404Redirect = $inputFilter->getValue(DomainRedirectsInputFilter::REGULAR_404_REDIRECT); + $this->invalidShortUrlRedirect = $inputFilter->getValue(DomainRedirectsInputFilter::INVALID_SHORT_URL_REDIRECT); } public function authority(): string @@ -50,7 +68,7 @@ class DomainRedirectsRequest public function toNotFoundRedirects(?NotFoundRedirectConfigInterface $defaults = null): NotFoundRedirects { - return new NotFoundRedirects( + return NotFoundRedirects::withRedirects( $this->baseUrlRedirectWasProvided ? $this->baseUrlRedirect : $defaults?->baseUrlRedirect(), $this->regular404RedirectWasProvided ? $this->regular404Redirect : $defaults?->regular404Redirect(), $this->invalidShortUrlRedirectWasProvided diff --git a/module/Rest/test-api/Fixtures/DomainFixture.php b/module/Rest/test-api/Fixtures/DomainFixture.php index 31e68f21..619dfdc4 100644 --- a/module/Rest/test-api/Fixtures/DomainFixture.php +++ b/module/Rest/test-api/Fixtures/DomainFixture.php @@ -20,7 +20,7 @@ class DomainFixture extends AbstractFixture $manager->persist(Domain::withAuthority('this_domain_is_detached.com')); $detachedWithRedirects = Domain::withAuthority('detached-with-redirects.com'); - $detachedWithRedirects->configureNotFoundRedirects(new NotFoundRedirects('foo.com', 'bar.com')); + $detachedWithRedirects->configureNotFoundRedirects(NotFoundRedirects::withRedirects('foo.com', 'bar.com')); $manager->persist($detachedWithRedirects); $manager->flush();