(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() of this request computes again; the cached mirror results stay (see invalidate()). */ public static function forget(): void { self::$status = null; } /** * 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 { if ($mirrors) { delete_transient(ReleaseResolver::CACHE); } self::forget(); } /** @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; } $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 $features */ public static function lockOf(array $features): ?DiviLocked { $status = self::status(); $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 { $previous = self::$probe; self::$probe = $postId; try { return $write(); } finally { self::$probe = $previous; } } }