diff --git a/src/Url/UrlTransformer.php b/src/Url/UrlTransformer.php new file mode 100644 index 0000000..99db928 --- /dev/null +++ b/src/Url/UrlTransformer.php @@ -0,0 +1,32 @@ +all() as $mapping ) { + $transformed = $this->replaceMapping( $transformed, $mapping ); + } + + return $transformed; + } + + private function replaceMapping( string $value, UrlMapping $mapping ): string { + $source = $mapping->sourceUrl(); + $destination = $mapping->destinationUrl(); + + $replacements = array( + $source => $destination, + str_replace( '&', '&', $source ) => str_replace( '&', '&', $destination ), + $this->toProtocolRelative( $source ) => $this->toProtocolRelative( $destination ), + ); + + return strtr( $value, $replacements ); + } + + private function toProtocolRelative( string $url ): string { + return preg_replace( '#^https?:#', '', $url ) ?? $url; + } +} diff --git a/tests/Unit/Url/UrlTransformerTest.php b/tests/Unit/Url/UrlTransformerTest.php new file mode 100644 index 0000000..1d3f71d --- /dev/null +++ b/tests/Unit/Url/UrlTransformerTest.php @@ -0,0 +1,84 @@ +transformString( 'Visit https://example.test/about for details.', $mappings ) + ); + } + + public function test_it_rewrites_html_attribute_urls(): void { + $transformer = new UrlTransformer(); + $mappings = new UrlMappingCollection( + array( + new UrlMapping( 'https://example.test', 'https://staging.example.test' ), + ) + ); + + self::assertSame( + '', + $transformer->transformString( + '', + $mappings + ) + ); + } + + public function test_it_rewrites_escaped_urls(): void { + $transformer = new UrlTransformer(); + $mappings = new UrlMappingCollection( + array( + new UrlMapping( 'https://example.test/path?a=1&b=2', 'https://staging.example.test/path?a=1&b=2' ), + ) + ); + + self::assertSame( + 'https://staging.example.test/path?a=1&b=2', + $transformer->transformString( 'https://example.test/path?a=1&b=2', $mappings ) + ); + } + + public function test_it_rewrites_protocol_relative_urls(): void { + $transformer = new UrlTransformer(); + $mappings = new UrlMappingCollection( + array( + new UrlMapping( 'https://example.test', 'https://staging.example.test' ), + ) + ); + + self::assertSame( + '//staging.example.test/uploads/file.pdf', + $transformer->transformString( '//example.test/uploads/file.pdf', $mappings ) + ); + } + + public function test_it_supports_multiple_mappings(): void { + $transformer = new UrlTransformer(); + $mappings = new UrlMappingCollection( + array( + new UrlMapping( 'https://example.test', 'https://staging.example.test' ), + new UrlMapping( 'https://cdn.example.test', 'https://cdn.staging.example.test' ), + ) + ); + + self::assertSame( + 'https://staging.example.test https://cdn.staging.example.test/image.jpg', + $transformer->transformString( 'https://example.test https://cdn.example.test/image.jpg', $mappings ) + ); + } +}