=7.0.0-beta.5") * @param string $extensionWorkingVersion manifest 의 version (예: "1.0.0-beta.5") * @return string|null 의무 시작 버전 또는 null (가드 미발동 — legacy) */ public static function resolveSinceVersion( ?string $g7VersionConstraint, string $extensionWorkingVersion, ): ?string { if ($g7VersionConstraint === null || trim($g7VersionConstraint) === '') { return null; } $minVersion = self::extractMinimumVersion($g7VersionConstraint); if ($minVersion === null) { return null; } if (version_compare($minVersion, self::ABSTRACT_INTRODUCED_AT, '<')) { return null; } return $extensionWorkingVersion; } /** * 확장 step 이 본 가드를 통과하는지 검증합니다. * * stepVersion < sinceVersion 인 step (확장 버전 이전의 legacy step) 은 미발동. * stepVersion >= sinceVersion 인 step 이 AbstractUpgradeStep 미상속이면 fatal. * * @param string $stepVersion 실행 중인 step 의 버전 * @param string $sinceVersion 의무 시작 버전 (resolveSinceVersion 결과; null 아님) * @param UpgradeStepInterface $step step 인스턴스 * @param string $extensionType 확장 타입 ("module" / "plugin") * @param string $extensionIdentifier 확장 식별자 * * @throws \RuntimeException stepVersion >= sinceVersion 인데 AbstractUpgradeStep 미상속 시 */ public static function assertAbstractInheritance( string $stepVersion, string $sinceVersion, UpgradeStepInterface $step, string $extensionType, string $extensionIdentifier, ): void { if (version_compare($stepVersion, $sinceVersion, '<')) { return; } if ($step instanceof AbstractUpgradeStep) { return; } throw new \RuntimeException(sprintf( 'Extension %s "%s" upgrade step %s must extend App\\Extension\\AbstractUpgradeStep ' .'(required from %s; introduced in core %s).', $extensionType, $extensionIdentifier, $stepVersion, $sinceVersion, self::ABSTRACT_INTRODUCED_AT, )); } /** * Semantic Versioning 제약 문자열에서 최소 버전을 추출합니다. * * 지원 형식: * - ">=X.Y.Z[-suffix]" / ">X.Y.Z" / "X.Y.Z" * - "^X.Y.Z" / "~X.Y.Z" * - "A|B" (OR) — 첫 후보 기준 * * 파싱 실패 시 null 반환 (보수적으로 가드 미발동). */ private static function extractMinimumVersion(string $constraint): ?string { $constraint = trim($constraint); $pipeIdx = strpos($constraint, '|'); if ($pipeIdx !== false) { $constraint = trim(substr($constraint, 0, $pipeIdx)); } if (preg_match( '/^(?:>=|>|\^|~|=)?\s*([0-9]+\.[0-9]+\.[0-9]+(?:[\-\.][a-zA-Z0-9\.\-]+)?)/', $constraint, $m, )) { return $m[1]; } return null; } }