src/UriResolver.php
public static function relativize(UriInterface $base, UriInterface $target)
    {
        if ($target->getScheme() !== '' &&
            ($base->getScheme() !== $target->getScheme() || $target->getAuthority() === '' && $base->getAuthority() !== '')
        ) {
            return $target;
        }

        if (Uri::isRelativePathReference($target)) {
            // As the target is already highly relative we return it as-is. It would be possible to resolve
            // the target with `$target = self::resolve($base, $target);` and then try make it more relative
            // by removing a duplicate query. But let's not do that automatically.
            return $target;
        }

        if ($target->getAuthority() !== '' && $base->getAuthority() !== $target->getAuthority()) {
            return $target->withScheme('');
        }

        // We must remove the path before removing the authority because if the path starts with two slashes, the URI
        // would turn invalid. And we also cannot set a relative path before removing the authority, as that is also
        // invalid.
        $emptyPathUri = $target->withScheme('')->withPath('')->withUserInfo('')->withPort(null)->withHost('');

        if ($base->getPath() !== $target->getPath()) {
            return $emptyPathUri->withPath(self::getRelativePath($base, $target));
        }

        if ($base->getQuery() === $target->getQuery()) {
            // Only the target fragment is left. And it must be returned even if base and target fragment are the same.
            return $emptyPathUri->withQuery('');
        }

        // If the base URI has a query but the target has none, we cannot return an empty path reference as it would
        // inherit the base query component when resolving.
        if ($target->getQuery() === '') {
            $segments = explode('/', $target->getPath());
            $lastSegment = end($segments);

            return $emptyPathUri->withPath($lastSegment === '' ? './' : $lastSegment);
        }

        return $emptyPathUri;
    }
public static function relativize(UriInterface $base, UriInterface $target)
    {
        if ($target->getScheme() !== '' &&
            ($base->getScheme() !== $target->getScheme() || $target->getAuthority() === '' && $base->getAuthority() !== '')
        ) {
            return $target;
        }

        if (Uri::isRelativePathReference($target)) {
            // As the target is already highly relative we return it as-is. It would be possible to resolve
            // the target with `$target = self::resolve($base, $target);` and then try make it more relative
            // by removing a duplicate query. But let's not do that automatically.
            return $target;
        }

        if ($target->getAuthority() !== '' && $base->getAuthority() !== $target->getAuthority()) {
            return $target->withScheme('');
        }

        // We must remove the path before removing the authority because if the path starts with two slashes, the URI
        // would turn invalid. And we also cannot set a relative path before removing the authority, as that is also
        // invalid.
        $emptyPathUri = $target->withScheme('')->withPath('')->withUserInfo('')->withPort(null)->withHost('');

        if ($base->getPath() !== $target->getPath()) {
            return $emptyPathUri->withPath(self::getRelativePath($base, $target));
        }

        if ($base->getQuery() === $target->getQuery()) {
            // Only the target fragment is left. And it must be returned even if base and target fragment are the same.
            return $emptyPathUri->withQuery('');
        }

        // If the base URI has a query but the target has none, we cannot return an empty path reference as it would
        // inherit the base query component when resolving.
        if ($target->getQuery() === '') {
            $segments = explode('/', $target->getPath());
            $lastSegment = end($segments);

            return $emptyPathUri->withPath($lastSegment === '' ? './' : $lastSegment);
        }

        return $emptyPathUri;
    }
public static function relativize ( UriInterface $ base , UriInterface $ target ) { if ( $ target -> getScheme ( ) !== '' && ( $ base -> getScheme ( ) !== $ target -> getScheme ( ) || $ target -> getAuthority ( ) === '' && $ base -> getAuthority ( ) !== '' ) ) { return $ target ; } if ( Uri :: isRelativePathReference ( $ target ) ) { // As the target is already highly relative we return it as-is. It would be possible to resolve // the target with `$target = self::resolve($base, $target);` and then try make it more relative // by removing a duplicate query. But let's not do that automatically. return $ target ; } if ( $ target -> getAuthority ( ) !== '' && $ base -> getAuthority ( ) !== $ target -> getAuthority ( ) ) { return $ target -> withScheme ( '' ) ; } // We must remove the path before removing the authority because if the path starts with two slashes, the URI // would turn invalid. And we also cannot set a relative path before removing the authority, as that is also // invalid. $ emptyPathUri = $ target -> withScheme ( '' ) -> withPath ( '' ) -> withUserInfo ( '' ) -> withPort ( null ) -> withHost ( '' ) ; if ( $ base -> getPath ( ) !== $ target -> getPath ( ) ) { return $ emptyPathUri -> withPath ( self :: getRelativePath ( $ base , $ target ) ) ; } if ( $ base -> getQuery ( ) === $ target -> getQuery ( ) ) { // Only the target fragment is left. And it must be returned even if base and target fragment are the same. return $ emptyPathUri -> withQuery ( '' ) ; } // If the base URI has a query but the target has none, we cannot return an empty path reference as it would // inherit the base query component when resolving. if ( $ target -> getQuery ( ) === '' ) { $ segments = explode ( '/' , $ target -> getPath ( ) ) ; $ lastSegment = end ( $ segments ) ; return $ emptyPathUri -> withPath ( $ lastSegment === '' ? './' : $ lastSegment ) ; } return $ emptyPathUri ; }
Returns the target URI as a relative reference from the base URI.

This method is the counterpart to resolve():

(string) $target === (string) UriResolver::resolve($base, UriResolver::relativize($base, $target))

One use-case is to use the current request URI as base URI and then generate relative links in your documents
to reduce the document size or offer self-contained downloadable document archives.

$base = new Uri('http://example.com/a/b/');
echo UriResolver::relativize($base, new Uri('http://example.com/a/b/c'));  // prints 'c'.
echo UriResolver::relativize($base, new Uri('http://example.com/a/x/y'));  // prints '../x/y'.
echo UriResolver::relativize($base, new Uri('http://example.com/a/b/?q')); // prints '?q'.
echo UriResolver::relativize($base, new Uri('http://example.org/a/b/'));   // prints '//example.org/a/b/'.

This method also accepts a target that is already relative and will try to relativize it further. Only a
relative-path reference will be returned as-is.

echo UriResolver::relativize($base, new Uri('/a/b/c'));  // prints 'c' as well

@param UriInterface $base   Base URI
@param UriInterface $target Target URI

@return UriInterface The relative URI reference
Returns the target URI as a relative reference from the base URI .