mirror of
https://github.com/crazywhalecc/static-php-cli.git
synced 2026-07-10 10:25:36 +08:00
Add ConditionalOn attribute
This commit is contained in:
27
src/StaticPHP/Attribute/Package/ConditionalOn.php
Normal file
27
src/StaticPHP/Attribute/Package/ConditionalOn.php
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace StaticPHP\Attribute\Package;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Makes a #[BeforeStage] or #[AfterStage] hook conditional on DI container bindings.
|
||||||
|
*
|
||||||
|
* The hook is only invoked when ALL specified classes are currently bound in the
|
||||||
|
* DI container. Multiple #[ConditionalOn] attributes on the same method use AND
|
||||||
|
* semantics — every condition must hold for the hook to run.
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
*
|
||||||
|
* #[ConditionalOn(PgoContext::class)]
|
||||||
|
* #[BeforeStage('php', 'build')]
|
||||||
|
* public function injectPgoFlags(PgoContext $ctx): void { ... }
|
||||||
|
*/
|
||||||
|
#[\Attribute(\Attribute::TARGET_METHOD | \Attribute::TARGET_CLASS | \Attribute::IS_REPEATABLE)]
|
||||||
|
readonly class ConditionalOn
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @param class-string $class the class that must be present in the DI container for this hook to run
|
||||||
|
*/
|
||||||
|
public function __construct(public string $class) {}
|
||||||
|
}
|
||||||
@@ -7,6 +7,7 @@ namespace StaticPHP\Registry;
|
|||||||
use StaticPHP\Attribute\Package\AfterStage;
|
use StaticPHP\Attribute\Package\AfterStage;
|
||||||
use StaticPHP\Attribute\Package\BeforeStage;
|
use StaticPHP\Attribute\Package\BeforeStage;
|
||||||
use StaticPHP\Attribute\Package\BuildFor;
|
use StaticPHP\Attribute\Package\BuildFor;
|
||||||
|
use StaticPHP\Attribute\Package\ConditionalOn;
|
||||||
use StaticPHP\Attribute\Package\CustomPhpConfigureArg;
|
use StaticPHP\Attribute\Package\CustomPhpConfigureArg;
|
||||||
use StaticPHP\Attribute\Package\Extension;
|
use StaticPHP\Attribute\Package\Extension;
|
||||||
use StaticPHP\Attribute\Package\Info;
|
use StaticPHP\Attribute\Package\Info;
|
||||||
@@ -50,14 +51,14 @@ class PackageLoader
|
|||||||
/**
|
/**
|
||||||
* Source metadata for #[BeforeStage] hooks, keyed by target package name → stage name.
|
* Source metadata for #[BeforeStage] hooks, keyed by target package name → stage name.
|
||||||
*
|
*
|
||||||
* @var array<string, array<string, list<array{class: string, method: string, only_when: ?string}>>>
|
* @var array<string, array<string, list<array{class: string, method: string, only_when: ?string, conditionals: list<class-string>}>>>
|
||||||
*/
|
*/
|
||||||
private static array $before_stage_meta = [];
|
private static array $before_stage_meta = [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Source metadata for #[AfterStage] hooks, keyed by target package name → stage name.
|
* Source metadata for #[AfterStage] hooks, keyed by target package name → stage name.
|
||||||
*
|
*
|
||||||
* @var array<string, array<string, list<array{class: string, method: string, only_when: ?string}>>>
|
* @var array<string, array<string, list<array{class: string, method: string, only_when: ?string, conditionals: list<class-string>}>>>
|
||||||
*/
|
*/
|
||||||
private static array $after_stage_meta = [];
|
private static array $after_stage_meta = [];
|
||||||
|
|
||||||
@@ -369,10 +370,15 @@ class PackageLoader
|
|||||||
// match condition
|
// match condition
|
||||||
$installer = ApplicationContext::get(PackageInstaller::class);
|
$installer = ApplicationContext::get(PackageInstaller::class);
|
||||||
$stages = self::$before_stages[$package_name][$stage] ?? [];
|
$stages = self::$before_stages[$package_name][$stage] ?? [];
|
||||||
foreach ($stages as [$callback, $only_when_package_resolved]) {
|
foreach ($stages as [$callback, $only_when_package_resolved, $conditionals]) {
|
||||||
if ($only_when_package_resolved !== null && !$installer->isPackageResolved($only_when_package_resolved)) {
|
if ($only_when_package_resolved !== null && !$installer->isPackageResolved($only_when_package_resolved)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
foreach ($conditionals as $class) {
|
||||||
|
if (!ApplicationContext::has($class)) {
|
||||||
|
continue 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
yield $callback;
|
yield $callback;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -383,10 +389,15 @@ class PackageLoader
|
|||||||
$installer = ApplicationContext::get(PackageInstaller::class);
|
$installer = ApplicationContext::get(PackageInstaller::class);
|
||||||
$stages = self::$after_stages[$package_name][$stage] ?? [];
|
$stages = self::$after_stages[$package_name][$stage] ?? [];
|
||||||
$result = [];
|
$result = [];
|
||||||
foreach ($stages as [$callback, $only_when_package_resolved]) {
|
foreach ($stages as [$callback, $only_when_package_resolved, $conditionals]) {
|
||||||
if ($only_when_package_resolved !== null && !$installer->isPackageResolved($only_when_package_resolved)) {
|
if ($only_when_package_resolved !== null && !$installer->isPackageResolved($only_when_package_resolved)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
foreach ($conditionals as $class) {
|
||||||
|
if (!ApplicationContext::has($class)) {
|
||||||
|
continue 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
$result[] = $callback;
|
$result[] = $callback;
|
||||||
}
|
}
|
||||||
return $result;
|
return $result;
|
||||||
@@ -422,7 +433,7 @@ class PackageLoader
|
|||||||
}
|
}
|
||||||
$pkg = self::getPackage($package_name);
|
$pkg = self::getPackage($package_name);
|
||||||
foreach ($stages as $stage_name => $before_events) {
|
foreach ($stages as $stage_name => $before_events) {
|
||||||
foreach ($before_events as [$event_callable, $only_when_package_resolved]) {
|
foreach ($before_events as [$event_callable, $only_when_package_resolved, $conditionals]) {
|
||||||
// check only_when_package_resolved package exists
|
// check only_when_package_resolved package exists
|
||||||
if ($only_when_package_resolved !== null && !self::hasPackage($only_when_package_resolved)) {
|
if ($only_when_package_resolved !== null && !self::hasPackage($only_when_package_resolved)) {
|
||||||
throw new RegistryException("{$event_name} event in package [{$package_name}] for stage [{$stage_name}] has unknown only_when_package_resolved package [{$only_when_package_resolved}].");
|
throw new RegistryException("{$event_name} event in package [{$package_name}] for stage [{$stage_name}] has unknown only_when_package_resolved package [{$only_when_package_resolved}].");
|
||||||
@@ -488,12 +499,17 @@ class PackageLoader
|
|||||||
throw new RegistryException('Package name must not be empty when no package context is available for BeforeStage attribute.');
|
throw new RegistryException('Package name must not be empty when no package context is available for BeforeStage attribute.');
|
||||||
}
|
}
|
||||||
$package_name = $method_instance->package_name === '' ? $pkg->getName() : $method_instance->package_name;
|
$package_name = $method_instance->package_name === '' ? $pkg->getName() : $method_instance->package_name;
|
||||||
self::$before_stages[$package_name][$stage][] = [[$instance_class, $method->getName()], $method_instance->only_when_package_resolved];
|
$conditionals = array_map(
|
||||||
|
fn (\ReflectionAttribute $a) => $a->newInstance()->class,
|
||||||
|
[...$method->getDeclaringClass()->getAttributes(ConditionalOn::class), ...$method->getAttributes(ConditionalOn::class)],
|
||||||
|
);
|
||||||
|
self::$before_stages[$package_name][$stage][] = [[$instance_class, $method->getName()], $method_instance->only_when_package_resolved, $conditionals];
|
||||||
$registering_class = get_class($instance_class);
|
$registering_class = get_class($instance_class);
|
||||||
self::$before_stage_meta[$package_name][$stage][] = [
|
self::$before_stage_meta[$package_name][$stage][] = [
|
||||||
'class' => $registering_class,
|
'class' => $registering_class,
|
||||||
'method' => $method->getName(),
|
'method' => $method->getName(),
|
||||||
'only_when' => $method_instance->only_when_package_resolved,
|
'only_when' => $method_instance->only_when_package_resolved,
|
||||||
|
'conditionals' => $conditionals,
|
||||||
];
|
];
|
||||||
self::$class_before_stage_meta[$registering_class][$package_name][$stage][] = [
|
self::$class_before_stage_meta[$registering_class][$package_name][$stage][] = [
|
||||||
'method' => $method->getName(),
|
'method' => $method->getName(),
|
||||||
@@ -513,12 +529,17 @@ class PackageLoader
|
|||||||
throw new RegistryException('Package name must not be empty when no package context is available for AfterStage attribute.');
|
throw new RegistryException('Package name must not be empty when no package context is available for AfterStage attribute.');
|
||||||
}
|
}
|
||||||
$package_name = $method_instance->package_name === '' ? $pkg->getName() : $method_instance->package_name;
|
$package_name = $method_instance->package_name === '' ? $pkg->getName() : $method_instance->package_name;
|
||||||
self::$after_stages[$package_name][$stage][] = [[$instance_class, $method->getName()], $method_instance->only_when_package_resolved];
|
$conditionals = array_map(
|
||||||
|
fn (\ReflectionAttribute $a) => $a->newInstance()->class,
|
||||||
|
[...$method->getDeclaringClass()->getAttributes(ConditionalOn::class), ...$method->getAttributes(ConditionalOn::class)],
|
||||||
|
);
|
||||||
|
self::$after_stages[$package_name][$stage][] = [[$instance_class, $method->getName()], $method_instance->only_when_package_resolved, $conditionals];
|
||||||
$registering_class = get_class($instance_class);
|
$registering_class = get_class($instance_class);
|
||||||
self::$after_stage_meta[$package_name][$stage][] = [
|
self::$after_stage_meta[$package_name][$stage][] = [
|
||||||
'class' => $registering_class,
|
'class' => $registering_class,
|
||||||
'method' => $method->getName(),
|
'method' => $method->getName(),
|
||||||
'only_when' => $method_instance->only_when_package_resolved,
|
'only_when' => $method_instance->only_when_package_resolved,
|
||||||
|
'conditionals' => $conditionals,
|
||||||
];
|
];
|
||||||
self::$class_after_stage_meta[$registering_class][$package_name][$stage][] = [
|
self::$class_after_stage_meta[$registering_class][$package_name][$stage][] = [
|
||||||
'method' => $method->getName(),
|
'method' => $method->getName(),
|
||||||
@@ -541,6 +562,7 @@ class PackageLoader
|
|||||||
ResolveBuild::class => 'ResolveBuild',
|
ResolveBuild::class => 'ResolveBuild',
|
||||||
Info::class => 'Info',
|
Info::class => 'Info',
|
||||||
Validate::class => 'Validate',
|
Validate::class => 'Validate',
|
||||||
|
ConditionalOn::class => 'ConditionalOn',
|
||||||
default => null,
|
default => null,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user