Initial commit.

This commit is contained in:
2025-11-24 21:33:55 +00:00
parent 14b7ade051
commit d6e9d316bc
8974 changed files with 1423277 additions and 0 deletions

View File

@@ -0,0 +1,21 @@
# Change log
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/)
and this project adheres to [Semantic Versioning](http://semver.org/).
## [[*next-version*]] - YYYY-MM-DD
## [0.2.0-alpha1] - 2021-05-03
### Removed
- Support for older PHP versions. Now requires at least PHP 7.1 (#2).
### Added
- Support for PHP 8.
### Changed
- Now using native `Stringable` rather than proprietary standard.
This requires pre-PHP-8 projects to use a polyfill.
## [0.1.0] - 2020-05-14
Initial version.

View File

@@ -0,0 +1,19 @@
Copyright (c) 2017 Dhii Team
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -0,0 +1,31 @@
version: '3.4'
services:
build:
build:
context: ./
dockerfile: docker/Dockerfile
target: build
args:
PHP_BUILD_VERSION: $PHP_BUILD_VERSION
BUILD_ROOT_PATH: $BUILD_ROOT_PATH
container_name: "${PROJECT_NAME}_build"
working_dir: ${BUILD_ROOT_PATH}
volumes:
- ${BASE_PATH}:${BUILD_ROOT_PATH}
test:
extra_hosts:
- "host.docker.internal:${HOST_IP_ADDRESS}"
build:
context: ./
dockerfile: docker/Dockerfile
target: test
args:
BUILD_ROOT_PATH: $BUILD_ROOT_PATH
PHP_BUILD_VERSION: $PHP_BUILD_VERSION
PHP_TEST_VERSION: $PHP_TEST_VERSION
container_name: "${PROJECT_NAME}_test"
working_dir: ${BUILD_ROOT_PATH}
volumes:
- ${BASE_PATH}:${BUILD_ROOT_PATH}

View File

@@ -0,0 +1,39 @@
ARG PHP_BUILD_VERSION
ARG PHP_TEST_VERSION
# Composer on correct PHP version
FROM php:${PHP_BUILD_VERSION}-cli as build
ARG BUILD_ROOT_PATH
RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini"
RUN apt-get update
RUN apt-get install -y zip unzip curl git
RUN php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
RUN php composer-setup.php --install-dir=/usr/bin --filename=composer
RUN php -r "unlink('composer-setup.php');"
WORKDIR ${BUILD_ROOT_PATH}
COPY . ./
FROM php:${PHP_TEST_VERSION}-cli as test
ARG BUILD_ROOT_PATH
RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini"
RUN pecl install xdebug-2.7.0
RUN docker-php-ext-install pcntl
RUN docker-php-ext-install posix
WORKDIR ${BUILD_ROOT_PATH}
COPY --from=build ${BUILD_ROOT_PATH} ${BUILD_ROOT_PATH}
# Install PHP dev dependencies
FROM build as vendor-dev
ARG BUILD_ROOT_PATH
WORKDIR ${BUILD_ROOT_PATH}
RUN composer install

View File

@@ -0,0 +1,21 @@
<?php
declare (strict_types=1);
namespace Dhii\Util\String;
use Stringable;
/**
* Something that is aware of a caption.
*/
interface CaptionAwareInterface
{
/**
* Retrieves the caption related to this instance.
*
* A caption is a human-readable string that provides a brief description for some element.
* It typically accompanies some illustration or screen fragment.
*
* @return string|Stringable
*/
public function getCaption();
}

View File

@@ -0,0 +1,21 @@
<?php
declare (strict_types=1);
namespace Dhii\Util\String;
use Stringable;
/**
* Something that is aware of a description.
*/
interface DescriptionAwareInterface
{
/**
* Retrieves the description related to this instance.
*
* A description is a human readable string that provides verbose explanation, additional information,
* instructions, and/or context.
*
* @return string|Stringable
*/
public function getDescription();
}

View File

@@ -0,0 +1,20 @@
<?php
declare (strict_types=1);
namespace Dhii\Util\String;
use Stringable;
/**
* Something that is aware of a label.
*/
interface LabelAwareInterface
{
/**
* Retrieves the label related to this instance.
*
* A label is a relatively short human readable string that can be used to identify or refer to this instance.
*
* @return string|Stringable
*/
public function getLabel();
}

View File

@@ -0,0 +1,21 @@
<?php
declare (strict_types=1);
namespace Dhii\Util\String;
use Stringable;
/**
* Something that is aware of a message.
*/
interface MessageAwareInterface
{
/**
* Retrieves the message related to this instance.
*
* A message is a human-readable string that provides information. It differs from a description in that it is more
* intrinsic to the instance. Example: exceptions, notifications, etc.
*
* @return string|Stringable
*/
public function getMessage();
}

View File

@@ -0,0 +1,20 @@
<?php
declare (strict_types=1);
namespace Dhii\Util\String;
use Stringable;
/**
* Something that is aware of a title.
*/
interface TitleAwareInterface
{
/**
* Retrieves the title related to this instance.
*
* A title is a human-readable string that serves as a heading for some content.
*
* @return string|Stringable
*/
public function getTitle();
}

View File

@@ -0,0 +1,15 @@
<?php
declare (strict_types=1);
namespace Dhii\Modular\Module\Exception;
use Dhii\Modular\Module\ModuleAwareInterface;
use Throwable;
/**
* Represents an exception that is thrown in relation to a module.
*
* @since 0.2
*/
interface ModuleExceptionInterface extends Throwable, ModuleAwareInterface
{
}

View File

@@ -0,0 +1,21 @@
<?php
declare (strict_types=1);
namespace Dhii\Modular\Module;
/**
* Something that can have a module instance retrieved.
*
* @since 0.2
*/
interface ModuleAwareInterface
{
/**
* Retrieves the module that is associated with this instance.
*
* @since 0.2
*
* @return ModuleInterface|null The module, if applicable; otherwise, null.
*/
public function getModule(): ?\Dhii\Modular\Module\ModuleInterface;
}

View File

@@ -0,0 +1,51 @@
<?php
declare (strict_types=1);
namespace Dhii\Modular\Module;
use Dhii\Modular\Module\Exception\ModuleExceptionInterface;
use Interop\Container\ServiceProviderInterface;
use WooCommerce\PayPalCommerce\Vendor\Psr\Container\ContainerInterface;
/**
* Something that represents an application module.
*
* @since 0.2
*/
interface ModuleInterface
{
/**
* Performs module-specific setup and provides a service provider.
*
* This method SHOULD be called at least once before {@link ModuleInterface::run()} may be invoked for a particular
* module instance. The returned service provider instance SHOULD be incorporated by the application into the
* container instance that is then given to this module's {@link ModuleInterface::run()} method.
*
* The application MAY also incorporate the service provider into the container instance given to other modules,
* but this is not required. As such, services factories in the returned service provider should not assume the
* existence of other module's services. Use proxy services together with {@link ContainerInterface::has()} for
* optionally integrating with other modules.
*
* @since 0.2
*
* @return ServiceProviderInterface A service provider instance for this module's services.
*
* @throws ModuleExceptionInterface If module setup failed and/or a service provider instance could not be returned.
*/
public function setup(): ServiceProviderInterface;
/**
* Runs the module.
*
* This method MUST be called after the module has been set up using {@link ModuleInterface::setup()}. A services
* container MUST be given to this method, and MUST incorporate the services from the service provider returned
* by the same module's {@link ModuleInterface::setup()} method. This container instance is not guaranteed to be
* the same instance given to other modules. As such, it is strongly advised to assume it is not, and to avoid
* referencing services from other modules.
*
* @since 0.2
*
* @param ContainerInterface $c A services container instance.
*
* @throws ModuleExceptionInterface If the module failed to run.
*/
public function run(ContainerInterface $c): void;
}

View File

@@ -0,0 +1,38 @@
<?php
declare (strict_types=1);
namespace Dhii\Package;
use Exception;
use Dhii\Package\Version\VersionInterface;
/**
* Represents a software package.
*/
interface PackageInterface
{
/**
* Retrieves the package name.
*
* @return string The unique package name.
* All lowercase alphanumeric characters, '.', '_', '-'. Also, a '/' is used to separate the vendor.
*
* @throws Exception If problem retrieving.
*/
public function getName(): string;
/**
* Retrieves the package version.
*
* @return VersionInterface The SemVer-compliant package version.
*
* @throws Exception If problem retrieving.
*/
public function getVersion(): VersionInterface;
/**
* Retrieves the path to the package base directory.
*
* @return string The absolute path to the base directory of the package.
*
* @throws Exception If problem retrieving.
*/
public function getBaseDir(): string;
}

View File

@@ -0,0 +1,12 @@
<?php
declare (strict_types=1);
namespace Dhii\Package\Version\Constraint\Exception;
use Dhii\Validation\Exception\ValidationFailedExceptionInterface;
/**
* Represents a case when a version does not match a constraint.
*/
interface ConstraintFailedExceptionInterface extends ValidationFailedExceptionInterface
{
}

View File

@@ -0,0 +1,24 @@
<?php
declare (strict_types=1);
namespace Dhii\Package\Version\Constraint;
use Dhii\Package\Version\Constraint\Exception\ConstraintFailedExceptionInterface;
use Dhii\Package\Version\VersionInterface;
use Dhii\Validation\ValidatorInterface;
use Exception;
/**
* Represents a version constraint.
*/
interface VersionConstraintInterface extends ValidatorInterface
{
/**
* Validates a package version.
*
* @param VersionInterface|mixed $version The version to validate.
*
* @throws ConstraintFailedExceptionInterface If version does not match this constraint.
* @throws Exception If problem validating.
*/
public function validate($version): void;
}

View File

@@ -0,0 +1,24 @@
<?php
declare (strict_types=1);
namespace Dhii\Package\Version;
use DomainException;
use Exception;
/**
* Represents a factory that can create a version from a version string.
*/
interface StringVersionFactoryInterface
{
/**
* Creates a new version from a version string.
*
* @param string $version The SemVer compatible version string.
*
* @return VersionInterface The new version.
*
* @throws DomainException If version string is malformed.
* @throws Exception If problem creating.
*/
public function createVersionFromString(string $version): \Dhii\Package\Version\VersionInterface;
}

View File

@@ -0,0 +1,56 @@
<?php
declare (strict_types=1);
namespace Dhii\Package\Version;
use Exception;
use Stringable;
/**
* Represents a SemVer-compliant version.
*/
interface VersionInterface extends Stringable
{
/**
* Retrieves the version's major number.
*
* @return int The major number.
*
* @throws Exception If problem retrieving.
*/
public function getMajor(): int;
/**
* Retrieves the version's minor number.
*
* @return int The minor number.
*
* @throws Exception If problem retrieving.
*/
public function getMinor(): int;
/**
* Retrieves the version's patch number.
*
* @return int The patch number.
*
* @throws Exception If problem retrieving.
*/
public function getPatch(): int;
/**
* Retrieves the version's pre-release identifier.
*
* @return string[] A list of identifiers.
* Each is a non-empty alphanumeric+hyphen string.
* If numeric, has no leading zeroes.
*
* @throws Exception If problem retrieving.
*/
public function getPreRelease(): array;
/**
* Retrieves the version's build metadata.
*
* @return string[] A series of identifiers.
* Each is a non-empty alphanumeric+hyphen string.
*
* @throws Exception If problem retrieving.
*/
public function getBuild(): array;
}

View File

@@ -0,0 +1,64 @@
# Change log
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/)
and this project adheres to [Semantic Versioning](http://semver.org/).
## [[*next-version*]] - YYYY-MM-DD
## [0.3.0-alpha3] - 2021-01-14
### Removed
- `ValidationExceptionInterface` was redundant, and burdened implementations.
- `ValidatorInterface#validate()` must now throw `RuntimeException` instead of `ValidationExceptionInterface`.
## [0.3.0-alpha2] - 2021-01-14
### Added
- `ValidatorInterface#validate()` now has explicit `void` return type.
### Changed
- Updated and added missing configs.
- Allowing PHP 8.
- Now _updating_ composer deps in CI, proving that this package is in fact installable on all target versions.
- Using newer Psalm.
### Removed
- No longer depends on Dhii `Stringable` interface. Instead, using Symfony Polyfill for testing.
This is recommended for use by consuming projects in cases when working PHP lower than 8.
## [0.3.0-alpha1] - 2020-05-14
### Removed
- `SpecAwareInterface`.
- `ValidatorFactoryInterface`.
- `SubjectAwareInterface`.
- `ValidatorAwareInterface`.
- `@since` tags everywhere.
- Support for PHP < 7.1.
### Changed
- `ValidationFailedExceptionInterface::getSubject()` is now `getValidationSubject().
## [0.2] - 2018-08-29
Stable release. No code changed.
## [0.2-alpha2] - 2018-03-07
### Added
- `ValidatorFactoryInterface`
### Changed
- Using newer version of `dhii/exception-interface`
### Removed
- `SpecValidatorInterface`
### Fixed
- Added missing import for `Traversable` in `SpecAwareInterface`
## [0.2-alpha1] - 2018-03-06
### Added
- `SpecValidatorInterface`.
- `SpecAwareInterface`.
- `SubjectAwareInterface`.
- `ValidatorAwareInterface`.
## [0.1] - 2017-03-09
Initial release, containing validator and exception interfaces.

View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2016-2017 Dhii
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -0,0 +1,33 @@
<?php
declare (strict_types=1);
namespace Dhii\Validation\Exception;
use Stringable;
use Exception;
use Throwable;
/**
* Something that can represent an exception which occurs if a validation
* fails.
*/
interface ValidationFailedExceptionInterface extends Throwable
{
/**
* Retrieves validation errors that are associated with this instance.
*
* @return string[]|Stringable[]|iterable A list of errors.
* Each error is something that can be treated as a string, and represents
* a description of why a validation subject is invalid.
*
* @throws Exception If problem retrieving.
*/
public function getValidationErrors(): iterable;
/**
* Returns the subject, the validation for which failed.
*
* @return mixed The subject that was being validated.
*
* @throws Exception If problem retrieving.
*/
public function getValidationSubject();
}

View File

@@ -0,0 +1,22 @@
<?php
declare (strict_types=1);
namespace Dhii\Validation;
use Dhii\Validation\Exception\ValidationFailedExceptionInterface;
use RuntimeException;
/**
* Something that can validate a value.
*/
interface ValidatorInterface
{
/**
* Validates a value.
*
* @param mixed $value The subject of validation.
*
* @throws RuntimeException If problem validating.
* @throws ValidationFailedExceptionInterface If validation failed. Must extend {@see RuntimeException}.
*/
public function validate($value): void;
}

View File

@@ -0,0 +1,97 @@
<?php
declare (strict_types=1);
namespace Dhii\Versions;
use Dhii\Package\Version\StringVersionFactoryInterface;
use Dhii\Package\Version\VersionInterface;
use DomainException;
use Exception;
use RangeException;
use RuntimeException;
use UnexpectedValueException;
/**
* @inheritDoc
*/
class StringVersionFactory implements StringVersionFactoryInterface
{
protected const SEP_PRERELEASE = '-';
protected const SEP_BUILD = '+';
/**
* @inheritDoc
*/
public function createVersionFromString(string $versionString): VersionInterface
{
try {
$components = $this->parseVersion($versionString);
$version = new \Dhii\Versions\Version($components['major'], $components['minor'], $components['patch'], $components['pre_release'], $components['build']);
} catch (RangeException $e) {
throw new DomainException(sprintf('Version string "%1$s" is malformed', $versionString), 0, $e);
}
return $version;
}
/**
* Parses a SemVer-compliant version string into components.
*
* @param string $version The version string.
*
* @return array{
* major: int,
* minor: int,
* patch: int,
* pre_release: string[],
* build: string[]
* }
*
* @throws DomainException If version string is malformed.
* @throws Exception If problem parsing.
*/
protected function parseVersion(string $version): array
{
$preReleaseSepPos = ($preReleaseSepPos = strpos($version, static::SEP_PRERELEASE)) !== \false ? $preReleaseSepPos : null;
$buildSepPos = ($buildSepPos = strpos($version, static::SEP_BUILD)) !== \false ? $buildSepPos : null;
if ($preReleaseSepPos === 0 || $buildSepPos === 0) {
throw new DomainException(sprintf('Pre-release or build information in version string "%1$s" must be preceded by at least one version number', $version));
}
$preRelease = '';
$build = '';
$numbers = $this->getSubstring($version, 0, $preReleaseSepPos ?? $buildSepPos);
if ($preReleaseSepPos) {
$preRelease = $this->getSubstring($version, $preReleaseSepPos + 1, $buildSepPos ? $buildSepPos - strlen($numbers) - 1 : $buildSepPos);
}
if ($buildSepPos) {
$build = $this->getSubstring($version, $buildSepPos + 1, null);
}
$numbers = strlen($numbers) ? explode('.', $numbers, 3) : [];
$preRelease = strlen($preRelease) ? explode('.', $preRelease) : [];
$build = strlen($build) ? explode('.', $build) : [];
$major = $numbers[0] ?? 0;
$minor = $numbers[1] ?? 0;
$patch = $numbers[2] ?? 0;
if (!is_numeric($major) || !is_numeric($minor) || !is_numeric($patch)) {
throw new DomainException(sprintf('Major, minor, and patch numbers in version string "%1$s" must be numeric', $version));
}
return ['major' => (int) $major, 'minor' => (int) $minor, 'patch' => (int) $patch, 'pre_release' => $preRelease, 'build' => $build];
}
/**
* Retrieves a string from withing a string.
*
* @see substr()
*
* @param string $string The string to get a substring from.
* @param int $start The index of the character from which to start the substring, inclusive.
* @param int|null $length The length of the substring, or `null` to get the remaining characters.
*
* @return string The substring.
*
* @throws RuntimeException If problem retrieving.
*/
protected function getSubstring(string $string, int $start, ?int $length): string
{
$substring = is_null($length) ? substr($string, $start) : substr($string, $start, $length);
if (!is_string($substring)) {
throw new UnexpectedValueException(sprintf('Could not extract a substring of a string "%1$d" chars long, starting from "%2$d" for "%3$d" chars', $string, $start, $length ?? 'null'));
}
return $substring;
}
}

View File

@@ -0,0 +1,205 @@
<?php
declare (strict_types=1);
namespace Dhii\Versions;
use Dhii\Package\Version\VersionInterface;
use DomainException;
use Exception;
use RangeException;
use RuntimeException;
use Stringable;
/**
* A value object containing information about a SemVer-compliant version.
*/
class Version implements VersionInterface
{
/**
* @var int
*/
protected $major;
/**
* @var int
*/
protected $minor;
/**
* @var int
*/
protected $patch;
/**
* @var string[]
*/
protected $preRelease;
/**
* @var string[]
*/
protected $build;
/**
* @param int $major The major version number. See {@see getMajor()}.
* @param int $minor The minor version number See {@see getMinor()}.
* @param int $patch The patch version number. See {@see getPatch()}.
* @param array<string|Stringable> $preRelease A list of pre-release identifiers. See {@see getPreRelease()}.
* @param array<string|Stringable> $build A list of build identifiers. See {@see getBuild()}.
*
* @throws RangeException If an identifier is malformed
* @throws Exception If problem creating.
*/
public function __construct(int $major, int $minor, int $patch, array $preRelease, array $build)
{
$this->major = $major;
$this->minor = $minor;
$this->patch = $patch;
$this->preRelease = $this->normalizePreRelease($preRelease);
$this->build = $this->normalizeBuild($build);
}
/**
* @inheritDoc
*/
public function getMajor(): int
{
return $this->major;
}
/**
* @inheritDoc
*/
public function getMinor(): int
{
return $this->minor;
}
/**
* @inheritDoc
*/
public function getPatch(): int
{
return $this->patch;
}
/**
* @inheritDoc
*/
public function getPreRelease(): array
{
return $this->preRelease;
}
/**
* @inheritDoc
*/
public function getBuild(): array
{
return $this->build;
}
/**
* Normalizes an identifier.
*
* @param string $identifier The identifier to normalize.
* Must be a non-empty alphanumeric+hyphen string.
*
* @return string An identifier with all disallowed characters removed.
*
* @throws DomainException If identifier is malformed
* @throws Exception If problem normalizing.
*/
protected function normalizeIdentifier(string $identifier): string
{
$origIdentifier = $identifier;
$identifier = $this->replace('![^\d\w-]!', '', $identifier);
if (!strlen($identifier)) {
throw new DomainException(sprintf('Identifier "%1$s" normalized to "%2$s" is empty', $origIdentifier, $identifier));
}
return $identifier;
}
/**
* Normalizes a series of pre-release identifiers.
*
* Will remove all illegal characters.
*
* @param iterable|array<string|Stringable> $preRelease The series of identifiers to normalize.
* Each is a non-empty alphanumeric+hyphen string.
* If numeric, leading zeroes are not allowed.
*
* @return string[] A series of normalized pre-release identifiers.
*
* @throws RangeException If could not normalize.
* @throws Exception If problem normalizing.
*/
protected function normalizePreRelease(iterable $preRelease): array
{
$normalized = [];
foreach ($preRelease as $idx => $identifier) {
$identifier = (string) $identifier;
try {
$identifier = $this->normalizeIdentifier($identifier);
} catch (DomainException $e) {
throw new RangeException(sprintf('Pre-release identifier #%1$d "%2$s" cannot be normalized', $idx, $identifier), 0, $e);
}
if (is_numeric($identifier)) {
$identifier = (string) intval($identifier);
}
$normalized[] = $identifier;
}
return $normalized;
}
/**
* Normalizes a series of build identifiers.
*
* Will remove all illegal characters.
*
* @param iterable|array<string|Stringable> $build The series of identifiers to normalize.
* Each is a non-empty alphanumeric+hyphen string.
*
* @return string[] A series of normalized build identifiers.
*
* @throws RangeException If could not normalize.
* @throws Exception If problem normalizing.
*/
protected function normalizeBuild(iterable $build): array
{
$normalized = [];
foreach ($build as $idx => $identifier) {
$identifier = (string) $identifier;
try {
$identifier = $this->normalizeIdentifier($identifier);
} catch (DomainException $e) {
throw new RangeException(sprintf('Build identifier #%1$d "%2$s" cannot be normalized', $idx, $identifier), 0, $e);
}
$normalized[] = $identifier;
}
return $normalized;
}
/**
* Replaces occurrences of $pattern in $subject.
*
* @param string $pattern The pattern to use for replacing.
* @param string $replacement The replacement.
* @param string $subject The subject.
*
* @return string The result of replacement.
*
* @throws Exception If problem replacing.
*/
protected function replace(string $pattern, string $replacement, string $subject): string
{
$result = preg_replace($pattern, $replacement, $subject);
if ($result === null) {
$code = preg_last_error();
$code = $code ? $code : 0;
$message = preg_last_error_msg();
$message = !empty($message) ? $message : 'Could not replace';
throw new RuntimeException($message, $code);
}
return $result;
}
/**
* @inheritDoc
*/
public function __toString()
{
$version = "{$this->major}.{$this->minor}.{$this->patch}";
if (count($this->preRelease)) {
$version .= '-' . implode('.', $this->preRelease);
}
if (count($this->build)) {
$version .= '+' . implode('.', $this->build);
}
return $version;
}
}