(new ReleaseResolver())->resolve())(); } catch (Throwable $e) { Log::failure('divi release status', $e); self::$status = ReleaseStatus::of('', CompatibilityMatrix::allIncompatible(self::UNRESOLVED)); } return self::$status; } /** @param (Closure(): ReleaseStatus)|null $resolver null = ReleaseResolver; tests set their own. */ public static function useResolver(?Closure $resolver): void { self::$resolver = $resolver; self::$status = null; self::$probe = null; } /** The next status() computes again (after a check, a release or a withdrawal). */ public static function forget(): void { self::$status = null; } public static function feature(DiviFeature $feature): FeatureStatus { return self::status()->matrix->of($feature); } /** @throws DiviLocked When $feature is not usable – before anything is written. */ public static function assertFeature(DiviFeature $feature, ?int $postId = null): void { self::assertFeatures([$feature], $postId); } /** * Every one of $features usable, else DiviLocked with the locked ones. The probe post passes whatever the status. * * @param list $features * @throws DiviLocked */ public static function assertFeatures(array $features, ?int $postId = null): void { if (self::$probe !== null && $postId === self::$probe) { return; } $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)); } } public static function whileProbing(int $postId, callable $write): mixed { $previous = self::$probe; self::$probe = $postId; try { return $write(); } finally { self::$probe = $previous; } } }