refactor: ReleaseGate::invalidate() als einzige Stelle zum Zurücksetzen des Freigabe-Zustands; CompatibilityMatrix::locked() und ReleaseGate::lockOf() ersetzen die drei Kopien der Sperrprüfung
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
7f9a087b8b
commit
63389f35a8
@@ -76,6 +76,27 @@ final class CompatibilityMatrix
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* The statuses of those of $features that are not usable – each once, in the order of $features. The one answer
|
||||
* to "what locks this call" for the gate (DiviFeatureGate), the adapters (ReleaseGate::assertFeatures()) and the
|
||||
* refusal (ReleaseStatus::refusalFor()).
|
||||
*
|
||||
* @param list<DiviFeature> $features
|
||||
* @return list<FeatureStatus>
|
||||
*/
|
||||
public function locked(array $features): array
|
||||
{
|
||||
$locked = [];
|
||||
foreach ($features as $feature) {
|
||||
$status = $this->of($feature);
|
||||
if (! $status->usable()) {
|
||||
$locked[$feature->value] = $status;
|
||||
}
|
||||
}
|
||||
|
||||
return array_values($locked);
|
||||
}
|
||||
|
||||
/** @return list<FeatureStatus> */
|
||||
public function unusable(): array
|
||||
{
|
||||
|
||||
@@ -63,7 +63,7 @@ final class DiviCheckRoute
|
||||
try {
|
||||
$report = ($this->check)()->run(get_current_user_id());
|
||||
($this->reports ?? new CheckReportStore())->save($report);
|
||||
ReleaseGate::forget();
|
||||
ReleaseGate::invalidate();
|
||||
$notice = 'divi_checked';
|
||||
} catch (Throwable $e) {
|
||||
Log::failure('divi check', $e);
|
||||
|
||||
@@ -25,27 +25,9 @@ final class DiviFeatureGate implements AbilityGuard
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* The lock for the usable-ness of $features, or null when every one is usable. Public: the Divi short form of
|
||||
* lit/content-create asks the same question for its own capabilities (DiviContentComposer::refusal()).
|
||||
*
|
||||
* @param list<DiviFeature> $features
|
||||
*/
|
||||
public static function lockFor(array $features): ?DiviLocked
|
||||
{
|
||||
$unusable = [];
|
||||
foreach ($features as $feature) {
|
||||
if (! ReleaseGate::feature($feature)->usable()) {
|
||||
$unusable[$feature->value] = $feature;
|
||||
}
|
||||
}
|
||||
|
||||
return $unusable === [] ? null : new DiviLocked(ReleaseGate::status(), array_values($unusable));
|
||||
}
|
||||
|
||||
public function refusal(Ability $ability, array $input): ?WP_Error
|
||||
{
|
||||
$lock = self::lockFor(FeatureSets::declaredBy($ability, $input));
|
||||
$lock = ReleaseGate::lockOf(FeatureSets::declaredBy($ability, $input));
|
||||
if ($lock === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -51,15 +51,25 @@ final class ReleaseGate
|
||||
self::$probe = null;
|
||||
}
|
||||
|
||||
/** The next status() computes again (after a check, a release or a withdrawal). */
|
||||
/** The next status() of this request computes again; the cached mirror results stay (see invalidate()). */
|
||||
public static function forget(): void
|
||||
{
|
||||
self::$status = null;
|
||||
}
|
||||
|
||||
public static function feature(DiviFeature $feature): FeatureStatus
|
||||
/**
|
||||
* The single way to make the release state current again: forgets the status of this request and, with
|
||||
* $mirrors, also deletes the cached mirror results (transient ReleaseResolver::CACHE) so the next status()
|
||||
* fingerprints Divi's code again. Without $mirrors: after a release or a withdrawal and after the admin check
|
||||
* (only the source of the state changed). With $mirrors: after a theme update, a CLI check or a new reference
|
||||
* (the code or the reference may have changed).
|
||||
*/
|
||||
public static function invalidate(bool $mirrors = false): void
|
||||
{
|
||||
return self::status()->matrix->of($feature);
|
||||
if ($mirrors) {
|
||||
delete_transient(ReleaseResolver::CACHE);
|
||||
}
|
||||
self::forget();
|
||||
}
|
||||
|
||||
/** @throws DiviLocked When $feature is not usable – before anything is written. */
|
||||
@@ -80,16 +90,28 @@ final class ReleaseGate
|
||||
return;
|
||||
}
|
||||
|
||||
$lock = self::lockOf($features);
|
||||
if ($lock !== null) {
|
||||
throw $lock;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The lock of this request's status for the locked ones of $features, or null when every one is usable. Asked by
|
||||
* DiviFeatureGate before a tool runs and by the Divi short form of lit/content-create (DiviContentComposer::
|
||||
* refusal()); no probe exception – tool calls never write the probe page.
|
||||
*
|
||||
* @param list<DiviFeature> $features
|
||||
*/
|
||||
public static function lockOf(array $features): ?DiviLocked
|
||||
{
|
||||
$status = self::status();
|
||||
$locked = [];
|
||||
foreach ($features as $feature) {
|
||||
if (! $status->matrix->of($feature)->usable()) {
|
||||
$locked[$feature->value] = $feature;
|
||||
}
|
||||
}
|
||||
if ($locked !== []) {
|
||||
throw new DiviLocked($status, array_values($locked));
|
||||
}
|
||||
$locked = $status->matrix->locked($features);
|
||||
|
||||
return $locked === [] ? null : new DiviLocked(
|
||||
$status,
|
||||
array_map(static fn (FeatureStatus $feature): DiviFeature => $feature->feature, $locked)
|
||||
);
|
||||
}
|
||||
|
||||
public static function whileProbing(int $postId, callable $write): mixed
|
||||
|
||||
@@ -77,18 +77,11 @@ final class ReleaseStatus
|
||||
*/
|
||||
public function refusalFor(array $features): WP_Error
|
||||
{
|
||||
$locked = [];
|
||||
foreach ($features as $feature) {
|
||||
$status = $this->matrix->of($feature);
|
||||
if (! $status->usable()) {
|
||||
$locked[$feature->value] = $status;
|
||||
}
|
||||
}
|
||||
$locked = $this->matrix->locked($features);
|
||||
if ($locked === []) {
|
||||
throw new LogicException('usable features refuse nothing');
|
||||
}
|
||||
|
||||
$locked = array_values($locked);
|
||||
$incompatible = array_values(array_filter(
|
||||
$locked,
|
||||
static fn (FeatureStatus $status): bool => $status->state === ReleaseState::Incompatible
|
||||
|
||||
Reference in New Issue
Block a user