ali-translator/url-template

Helping on work with template url, example: "{country}.example.com/{language}/{city}"

v0.3.0 2024-12-15 10:14 UTC

This package is auto-updated.

Last update: 2025-04-15 11:08:37 UTC


README

Helps work with URLs using their "base" template.
For example, the base structure of your project URL is "gb.example.com/en/london/". In this example, your template URL has the following parameters: "country," "language," and "city."
Let's create a template for this example: "{country}.example.com/{language}/{city}"

Installation

$ composer require ali-translator/url-template

Code examle:

use ALI\UrlTemplate\UrlTemplateConfig;
use ALI\UrlTemplate\UrlTemplateResolver;

$urlTemplateConfig = new UrlTemplateConfig(
    '{country}.example.com',
    '{language}/{city}/',
    // Regular expressions matching the parameters
    [
        'country' => ['uk','ua','pl'],
        'language' => '[a-z]{2}', // be careful with some free regular expressions
        'city' => ['kiev','berlin','paris','london'],
    ],
    // If you have some default parameters that may be empty in url, set them here
    [
        'city' => 'berlin',
        'language' => 'en',
    ],
    // "Hide default URL parameters?".
    // Can be an array if you want to hide only some parameters.
    true
);
$urlTemplateResolver = new UrlTemplateResolver($urlTemplateConfig);

$url = 'https://gb.example.com/de/london/';

// Parse existing URL
$parsedUrlTemplate = $urlTemplateResolver->parseCompiledUrl($url);
var_dump($parsedUrlTemplate->getFullParameters());

// Change some parameter on existing URL
$parsedUrlTemplate->setParameter('country','pl');
$urlWithAnotherCountry = $urlTemplateResolver->compileUrl($parsedUrlTemplate);
var_dump($urlWithAnotherCountry);

// Get clear url(without template parameters) for application routing
$simplifiedUrl = $urlTemplateResolver->getSimplifiedUrl($parsedUrlTemplate);
var_dump($simplifiedUrl); // -> "https://example.com"

// Generate full url from simplified url(which application returns)
$parsedUrlTemplate = $urlTemplateResolver->generateParsedUrlTemplate('https://example.com/some-category/item?sale=1',[
    'country' => 'uk',
    'city' => 'london',
     // 'language' => 'en', // Default values may be skipped
]);
$compiledUrl = $urlTemplateResolver->compileUrl($parsedUrlTemplate);
var_dump($compiledUrl); // -> "https://uk.example.com/london/some-category/item?sale=1"

// As you may see, the default language value "en" is omitted in the URL.
// If you want it included in the URL, you must set "false" for the last parameter "isHideDefaultParameters" in the constructor of `UrlTemplateConfig`. 

Warning: be careful with some free regular expressions, as for language '[a-z]{2}', will be better '(en|de|ua)'

Optionality default values

You may set optionality default value of parameter. For this you must set callable argument for default value.
You optionality parameter must be depending only from required argument.

Example of use:

use ALI\UrlTemplate\UrlTemplateConfig;

$urlTemplateConfig = new UrlTemplateConfig(
    '{country}.test.com',
    '/{language}/',
    [
        'country' => ['tr','gb'],
        'language' => ['en','tr','de'],
    ],
    [
        'language' => function ($requiredParameters) {
            $languagesByCountries = ['tr'=>'tr','gb'=>'en'];
            
            return $languagesByCountries[$requiredParameters['country']] ?? 
                throw new Exception('Invalid country alias');
        },
    ],
    true
);

Parameter Decorators

Sometimes you need to apply decorations to your parameters in a URL.
For example, if you want the following path template to be "/{country}-{language}/" and decide to hide the default language.
In this case, without decorators, you would get the following compiled URL: "/country-/".
The excessive character "-" looks unappealing.
You can use decorators to solve this problem.
A decorator is a class that implements the ParameterDecoratorInterface.

Example of use:

use ALI\UrlTemplate\ParameterDecorators\WrapperParameterDecorator;
use ALI\UrlTemplate\UrlTemplateConfig;

$urlTemplateConfig = new UrlTemplateConfig(
    null,
    '/{country}{language}/',
    [
        'country' => ['ua', 'pl'],
        'language' => ['ua', 'en', 'de'],
    ],
    [
        'city' => 'berlin',
        'language' => 'en',
    ],
    true,
    [
        'language' => new WrapperParameterDecorator('-'),
    ]
);

For the decorator to work correctly, use an array of requirements with available values, instead of a regular expression.

Validate ParsedTemplate object

use \ALI\UrlTemplate\UrlTemplateResolver\ParsedUrlTemplateValidator;
use \ALI\UrlTemplate\ParsedUrlTemplate;

/** @var ParsedUrlTemplate $parsedUrlTemplate */

$urlTemplateValidator = new ParsedUrlTemplateValidator();
$errors = $urlTemplateValidator->validateParameters($parsedUrlTemplate);
// $errors : [key -> (string)'error description']

Additional features

  • You can use templates where multiple parameters are placed in one "URL namespace," such as the host "{country}-{language}-{currency}.test.com" and the path "/{country}-{language}/".
    • If you need to compile only the "host URL" or "path URL," you can use:
    $urlTemplateResolver->compileUrl($parsedUrl, $urlTemplateResolver::COMPILE_TYPE_HOST);
  • If you need to skip only some default parameters in the URL, you can pass an array of parameter names to the $hideDefaultParametersFromUrl parameter of the UrlTemplateConfig class.
  • If you have an optional parameter that depends on another parameter, and this other parameter is in a different part of the URL (e.g., the optional parameter is in the "path URL part" and depends on a parameter in the "host URL part"), there may be an issue when processing a relative URL without the host.
    To handle this scenario, pass a value to the function that determines the optional parameter:
    ...
    [
      'language' => function ($requiredParametersValues) use ($currentCountryAlias) {
          $countryAlias = $requiredParametersValues['country'] ?? $currentCountryAlias;
    ...
  • To create a new UrlTemplateConfig based on an existing one:
    /** @var $urlTemplateConfig ALI\UrlTemplate\UrlTemplateConfig */
    $urlTemplateConfigData = $urlTemplateConfig->generateUrlTemplateConfigData();
    // Modify some config data
    $urlTemplateConfigData->setDefaultUrlSchema('https');
    // Create a new UrlTemplateConfig
    $newUrlTemplateConfig = $urlTemplateConfigData->generateUrlTemplateConfig();
  • By default, the system allows the use of all subdomains for a given domain template.
    For example, if we have a template {city}.test.com, it will correctly handle the domain www.lviv.test.com.
    However, if we need the system to restrict handling of subdomains, we can specify in UrlTemplateConfig that subdomains should not be supported:
    $urlTemplateConfig->setIsAllowedSubdomains(false);

Tests

Included in the package is a docker-compose file, with an environment for testing.

docker-compose up -d
docker-compose exec php bash
composer install
./vendor/bin/phpunit