babaev-an a439c0d2c9 20250612
* Добавлено перечисление стадий в информации о версии VersionInfoStage.

* Добавлен новый класс, описывающий информацию о версии, VersionInfo (подробнее см. VersionInfo.md).
2025-06-12 16:09:03 +03:00

295 lines
13 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
namespace goodboyalex\php_components_pack\classes;
use goodboyalex\php_components_pack\enums\VersionInfoStage;
use goodboyalex\php_components_pack\extensions\StringExtension;
/**
* Класс, описывающий информацию о версии.
*
* @author Александр Бабаев
* @package php_components_pack
* @version 1.0
* @since 1.0.24
*/
final class VersionInfo
{
/**
* @var array $StagesNames Имена стадий сборки.
*/
public const array StagesNames = [
VersionInfoStage::PreAlpha->value => 'PreAlpha',
VersionInfoStage::Alpha->value => 'Alpha',
VersionInfoStage::Beta->value => 'Beta',
VersionInfoStage::ReleaseCandidate->value => 'rc',
VersionInfoStage::Stable->value => 'Stable'
];
/**
* @var string $DefaultTemplate Шаблон вывода по умолчанию.
*/
public const string DefaultTemplate = '#{Major}.#{Minor}.#{Release}.#{Build} #{Stage} #{StageNumber}';
/**
* @var int $Major Мажорная версия.
*/
private(set) int $Major = 0;
/**
* @var int $Minor Минорная версия.
*/
private(set) int $Minor = 0;
/**
* @var int $Release Номер релиза.
*/
private(set) int $Release = 0;
/**
* @var int $Build Номер сборки.
*/
private(set) int $Build = 0;
/**
* @var VersionInfoStage $Stage Стадия сборки.
*/
private(set) VersionInfoStage $Stage = VersionInfoStage::Undefined;
/**
* @var int $StageNumber Номер стадии сборки.
*/
private(set) int $StageNumber = 0;
/**
* Конструктор.
*
* @param int $Major Мажорная версия.
* @param int $Minor Минорная версия.
* @param int $Release Номер релиза.
* @param int $Build Номер сборки.
* @param VersionInfoStage $Stage Стадия сборки.
* @param int $StageNumber Номер стадии сборки.
*/
public function __construct (int $Major, int $Minor, int $Release, int $Build,
VersionInfoStage $Stage = VersionInfoStage::Undefined, int $StageNumber = 0)
{
$this->Major = $Major;
$this->Minor = $Minor;
$this->Release = $Release;
$this->Build = $Build;
$this->Stage = $Stage;
$this->StageNumber = $StageNumber;
}
/**
* Сравнивает две версии.
*
* @param VersionInfo $version1 Версия 1.
* @param VersionInfo $version2 Версия 2.
*
* @return int Возвращает 1, если версия 1 больше версии 2, 0, если равны, -1, если версия 1 меньше версии 2.
*/
public static function Compare (VersionInfo $version1, VersionInfo $version2): int
{
return $version1->CompareWith($version2);
}
/**
* Сравнивает текущую версию с переданной.
*
* @param VersionInfo $version Переданная версия.
*
* @return int Возвращает 1, если текущая версия больше переданной, 0, если равны, -1, если текущая версия меньше
* переданной.
*/
public function CompareWith (VersionInfo $version): int
{
// Задаем шаблон вывода
$toStringTemplate = '#{Major}.#{Minor}.#{Release}.#{Build}';
// Сначала сравним числа (мажорную, минорную версии, номер релиза и сборки):
$compareResult = version_compare(
$this->ToString($toStringTemplate),
$version->ToString($toStringTemplate)
);
// Если численные части совпадают, проверяем стадии сборки
if ($compareResult === 0) {
// - особый случай: стабильная версия всегда больше любых промежуточных стадий
if ($this->Stage === VersionInfoStage::Stable && self::IsNotUndefinedOrStable($version->Stage))
// - считаем нашу старшей
return 1;
// - особый случай: если наша версия не stable, а другая stable
if ($version->Stage === VersionInfoStage::Stable && self::IsNotUndefinedOrStable($this->Stage))
// - считаем нашу младшей
return -1;
// - преобразуем стадии в целые числа для прямого сравнения
$currentStageValue = $this->Stage->ToInt();
$otherStageValue = $version->Stage->ToInt();
// - если стадии отличаются
if ($currentStageValue !== $otherStageValue)
// - сравниваем их
return $currentStageValue <=> $otherStageValue;
// - если стадии одинаковые
if (self::IsNotUndefinedOrStable($this->Stage) && self::IsNotUndefinedOrStable($version->Stage)
&& $this->StageNumber !== $version->StageNumber)
return $this->StageNumber <=> $version->StageNumber;
// - если все совпадает, то вернём 0
return 0;
}
// Возврат результата сравнения
return $compareResult;
}
/**
* Возвращает строковое представление версии.
*
* @param string $template Шаблон вывода. В шаблоне маркеры #{Major}, #{Minor}, #{Release}, #{Build}, #{Stage} и
* #{StageNumber} заменяются на значения соответствующих свойств. По умолчанию используется
* {@link DefaultTemplate}.
* @param array $stagesNames Имена стадий сборки (по умолчанию из константы {@link StagesNames}).
*
* @return string Строковое представление версии.
*/
public function ToString (string $template = self::DefaultTemplate, array $stagesNames = self::StagesNames): string
{
// Получаем строковое представление стадии сборки
$stage = match ($this->Stage) {
// - для неопределенной стадии сборки и релиза возвращаем пустую строку
VersionInfoStage::Undefined, VersionInfoStage::Stable => '',
// - для остальных стадий сборки возвращаем строковое представление стадии сборки
VersionInfoStage::PreAlpha => $stagesNames[VersionInfoStage::PreAlpha->value],
VersionInfoStage::Alpha => $stagesNames[VersionInfoStage::Alpha->value],
VersionInfoStage::Beta => $stagesNames[VersionInfoStage::Beta->value],
VersionInfoStage::ReleaseCandidate => $stagesNames[VersionInfoStage::ReleaseCandidate->value]
};
// Возвращаем строковое представление номера стадии сборки, если конечно стадия определена и она не релиз
// и номер сборки должен быть задан (больше 0)
$stageNum = self::IsNotUndefinedOrStable($this->Stage) && $this->StageNumber > 0
? "$this->StageNumber" : '';
// Создаём массив для замены
$replaceData = [
'#{Major}' => "$this->Major",
'#{Minor}' => "$this->Minor",
'#{Release}' => "$this->Release",
'#{Build}' => "$this->Build",
'#{Stage}' => $stage,
'#{StageNumber}' => $stageNum
];
// Заменяем все в шаблоне
$result = StringExtension::ReplaceAll($replaceData, $template);
// Возвращаем результат, удаляя лишние пробелы в конце
return rtrim($result, ' ');
}
/**
* Проверяет, является ли версия неопределённой или релизом.
*
* @param VersionInfoStage $versionStage Стадия сборки.
*
* @return bool Возвращает true, если стадия сборки определена и не является релизом.
*/
public static function IsNotUndefinedOrStable (VersionInfoStage $versionStage): bool
{
return $versionStage !== VersionInfoStage::Undefined && $versionStage !== VersionInfoStage::Stable;
}
/**
* Преобразует строку с версией в объект {@link VersionInfo}.
*
* @param string $version Строка с версией (она должна быть в формате {@link DefaultTemplate}).
* @param array $stagesNames Имена стадий сборки (по умолчанию из константы {@link StagesNames}).
*
* @return VersionInfo Возвращает объект {@link VersionInfo} с данными о версии.
*/
public static function Parse (string $version, array $stagesNames = self::StagesNames): VersionInfo
{
// Убираем пробелы в начале и конце строки
$version = trim($version);
// Разбиваем строку на части по пробелам (1 часть - основная - мажор, минор, релиз, сборка,
// 2 часть - стадия и 3 - номер стадии)
$versionParts = explode(' ', $version);
// Проверяем, что строка содержит хотя бы 1 часть
if (count($versionParts) < 1)
// - если нет, то возвращаем пустую версию
return new VersionInfo(0, 0, 0, 0);
// Составим регулярное выражение для парсинга базовой информации о версии
$pattern = '/^(\d+)\.(\d+)\.(\d+)\.(\d+)/';
// Парсим базовую информацию о версии
if (!preg_match($pattern, $versionParts[0], $matches))
// - если не удалось, то возвращаем пустую версию
return new VersionInfo(0, 0, 0, 0);
// Проверяем, что найдены все 4 части
if (!$matches || count($matches) < 5)
// - если нет, то возвращаем пустую версию
return new VersionInfo(0, 0, 0, 0);
// Получаем значения
[, $major, $minor, $release, $build] = $matches;
// Парсим обязательные цифры
// - мажорная версия
$major = intval($major);
// - минорная версия
$minor = intval($minor);
// - номер релиза
$release = intval($release);
// - номер сборки
$build = intval($build);
// Если частей версии больше 1
if (count($versionParts) > 1) {
// - получаем массив для перевода строковых имен стадий в числа
$stageEnumMap = array_flip($stagesNames);
// - получаем стадию
$stage = VersionInfoStage::FromInt(intval($stageEnumMap[$versionParts[1]] ?? 0));
// - если стадия определена и не релиз, и кроме того, есть номер стадии
if (self::IsNotUndefinedOrStable($stage) && count($versionParts) > 2)
// -- получаем номер стадии
$stageNumber = intval($versionParts[2]);
else
// -- иначе, устанавливаем номер стадии 0
$stageNumber = 0;
}
else {
// - иначе, устанавливаем стадию неопределённой
$stage = VersionInfoStage::Undefined;
// - и номер стадии 0
$stageNumber = 0;
}
// Создание объекта VersionInfo
return new VersionInfo($major, $minor, $release, $build, $stage, $stageNumber);
}
/**
* Выводит строковое представление версии (упрощённая версия ToString() с шаблоном по умолчанию, необходимая для
* вывода при попытке привести объект к типу string).
*
* @return string Строковое представление версии.
*/
public function __toString (): string
{
// Получаем строковое представление версии и возвращаем его
return $this->ToString();
}
}