mirror of
https://github.com/woocommerce/woocommerce-paypal-payments.git
synced 2025-08-30 05:00:51 +08:00
728 lines
21 KiB
PHP
728 lines
21 KiB
PHP
|
<?php
|
||
|
|
||
|
declare(strict_types=1);
|
||
|
|
||
|
namespace WooCommerce\PayPalCommerce\Vendor\Inpsyde\Modularity;
|
||
|
|
||
|
use WooCommerce\PayPalCommerce\Vendor\Inpsyde\Modularity\Container\ContainerConfigurator;
|
||
|
use WooCommerce\PayPalCommerce\Vendor\Inpsyde\Modularity\Container\PackageProxyContainer;
|
||
|
use WooCommerce\PayPalCommerce\Vendor\Inpsyde\Modularity\Module\ExtendingModule;
|
||
|
use WooCommerce\PayPalCommerce\Vendor\Inpsyde\Modularity\Module\ExecutableModule;
|
||
|
use WooCommerce\PayPalCommerce\Vendor\Inpsyde\Modularity\Module\FactoryModule;
|
||
|
use WooCommerce\PayPalCommerce\Vendor\Inpsyde\Modularity\Module\Module;
|
||
|
use WooCommerce\PayPalCommerce\Vendor\Inpsyde\Modularity\Module\ServiceModule;
|
||
|
use WooCommerce\PayPalCommerce\Vendor\Inpsyde\Modularity\Properties\Properties;
|
||
|
use WooCommerce\PayPalCommerce\Vendor\Psr\Container\ContainerInterface;
|
||
|
|
||
|
class Package
|
||
|
{
|
||
|
/**
|
||
|
* All the hooks fired in this class use this prefix.
|
||
|
* @var string
|
||
|
*/
|
||
|
private const HOOK_PREFIX = 'inpsyde.modularity.';
|
||
|
|
||
|
/**
|
||
|
* Identifier to access Properties in Container.
|
||
|
*
|
||
|
* @example
|
||
|
* <code>
|
||
|
* $package = Package::new();
|
||
|
* $package->boot();
|
||
|
*
|
||
|
* $container = $package->container();
|
||
|
* $container->has(Package::PROPERTIES);
|
||
|
* $container->get(Package::PROPERTIES);
|
||
|
* </code>
|
||
|
*
|
||
|
* @var string
|
||
|
*/
|
||
|
public const PROPERTIES = 'properties';
|
||
|
|
||
|
/**
|
||
|
* Custom action to be used to add Modules to the package.
|
||
|
* It might also be used to access package properties.
|
||
|
*
|
||
|
* @example
|
||
|
* <code>
|
||
|
* $package = Package::new();
|
||
|
*
|
||
|
* add_action(
|
||
|
* $package->hookName(Package::ACTION_INIT),
|
||
|
* $callback
|
||
|
* );
|
||
|
* </code>
|
||
|
*/
|
||
|
public const ACTION_INIT = 'init';
|
||
|
|
||
|
/**
|
||
|
* Custom action which is triggered after the application
|
||
|
* is booted to access container and properties.
|
||
|
*
|
||
|
* @example
|
||
|
* <code>
|
||
|
* $package = Package::new();
|
||
|
*
|
||
|
* add_action(
|
||
|
* $package->hookName(Package::ACTION_READY),
|
||
|
* $callback
|
||
|
* );
|
||
|
* </code>
|
||
|
*/
|
||
|
public const ACTION_READY = 'ready';
|
||
|
|
||
|
/**
|
||
|
* Custom action which is triggered when a failure happens during the building stage.
|
||
|
*
|
||
|
* @example
|
||
|
* <code>
|
||
|
* $package = Package::new();
|
||
|
*
|
||
|
* add_action(
|
||
|
* $package->hookName(Package::ACTION_FAILED_BUILD),
|
||
|
* $callback
|
||
|
* );
|
||
|
* </code>
|
||
|
*/
|
||
|
public const ACTION_FAILED_BUILD = 'failed-build';
|
||
|
|
||
|
/**
|
||
|
* Custom action which is triggered when a failure happens during the booting stage.
|
||
|
*
|
||
|
* @example
|
||
|
* <code>
|
||
|
* $package = Package::new();
|
||
|
*
|
||
|
* add_action(
|
||
|
* $package->hookName(Package::ACTION_FAILED_BOOT),
|
||
|
* $callback
|
||
|
* );
|
||
|
* </code>
|
||
|
*/
|
||
|
public const ACTION_FAILED_BOOT = 'failed-boot';
|
||
|
|
||
|
/**
|
||
|
* Custom action which is triggered when a package is connected.
|
||
|
*/
|
||
|
public const ACTION_PACKAGE_CONNECTED = 'package-connected';
|
||
|
|
||
|
/**
|
||
|
* Custom action which is triggered when a package cannot be connected.
|
||
|
*/
|
||
|
public const ACTION_FAILED_CONNECTION = 'failed-connection';
|
||
|
|
||
|
/**
|
||
|
* Module states can be used to get information about your module.
|
||
|
*
|
||
|
* @example
|
||
|
* <code>
|
||
|
* $package = Package::new();
|
||
|
* $package->moduleIs(SomeModule::class, Package::MODULE_ADDED); // false
|
||
|
* $package->boot(new SomeModule());
|
||
|
* $package->moduleIs(SomeModule::class, Package::MODULE_ADDED); // true
|
||
|
* </code>
|
||
|
*/
|
||
|
public const MODULE_ADDED = 'added';
|
||
|
public const MODULE_NOT_ADDED = 'not-added';
|
||
|
public const MODULE_REGISTERED = 'registered';
|
||
|
public const MODULE_REGISTERED_FACTORIES = 'registered-factories';
|
||
|
public const MODULE_EXTENDED = 'extended';
|
||
|
public const MODULE_EXECUTED = 'executed';
|
||
|
public const MODULE_EXECUTION_FAILED = 'executed-failed';
|
||
|
public const MODULES_ALL = '*';
|
||
|
|
||
|
/**
|
||
|
* Custom states for the class.
|
||
|
*
|
||
|
* @example
|
||
|
* <code>
|
||
|
* $package = Package::new();
|
||
|
* $package->statusIs(Package::IDLE); // true
|
||
|
* $package->boot();
|
||
|
* $package->statusIs(Package::BOOTED); // true
|
||
|
* </code>
|
||
|
*/
|
||
|
public const STATUS_IDLE = 2;
|
||
|
public const STATUS_INITIALIZED = 4;
|
||
|
public const STATUS_MODULES_ADDED = 5;
|
||
|
public const STATUS_READY = 7;
|
||
|
public const STATUS_BOOTED = 8;
|
||
|
public const STATUS_FAILED = -8;
|
||
|
|
||
|
/**
|
||
|
* Current state of the application.
|
||
|
*
|
||
|
* @see Package::STATUS_*
|
||
|
*
|
||
|
* @var int
|
||
|
*/
|
||
|
private $status = self::STATUS_IDLE;
|
||
|
|
||
|
/**
|
||
|
* Contains the progress of all modules.
|
||
|
*
|
||
|
* @see Package::moduleProgress()
|
||
|
*
|
||
|
* @var array<string, list<string>>
|
||
|
*/
|
||
|
private $moduleStatus = [self::MODULES_ALL => []];
|
||
|
|
||
|
/**
|
||
|
* Hashmap of where keys are names of connected packages, and values are boolean, true
|
||
|
* if connection was successful.
|
||
|
*
|
||
|
* @see Package::connect()
|
||
|
*
|
||
|
* @var array<string, bool>
|
||
|
*/
|
||
|
private $connectedPackages = [];
|
||
|
|
||
|
/**
|
||
|
* @var list<ExecutableModule>
|
||
|
*/
|
||
|
private $executables = [];
|
||
|
|
||
|
/**
|
||
|
* @var Properties
|
||
|
*/
|
||
|
private $properties;
|
||
|
|
||
|
/**
|
||
|
* @var ContainerConfigurator
|
||
|
*/
|
||
|
private $containerConfigurator;
|
||
|
|
||
|
/**
|
||
|
* @var bool
|
||
|
*/
|
||
|
private $built = false;
|
||
|
|
||
|
/**
|
||
|
* @var bool
|
||
|
*/
|
||
|
private $hasContainer = false;
|
||
|
|
||
|
/**
|
||
|
* @var \Throwable|null
|
||
|
*/
|
||
|
private $lastError = null;
|
||
|
|
||
|
/**
|
||
|
* @param Properties $properties
|
||
|
* @param ContainerInterface[] $containers
|
||
|
*
|
||
|
* @return Package
|
||
|
*/
|
||
|
public static function new(Properties $properties, ContainerInterface ...$containers): Package
|
||
|
{
|
||
|
return new self($properties, ...$containers);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param Properties $properties
|
||
|
* @param ContainerInterface[] $containers
|
||
|
*/
|
||
|
private function __construct(Properties $properties, ContainerInterface ...$containers)
|
||
|
{
|
||
|
$this->properties = $properties;
|
||
|
|
||
|
$this->containerConfigurator = new ContainerConfigurator($containers);
|
||
|
$this->containerConfigurator->addService(
|
||
|
self::PROPERTIES,
|
||
|
static function () use ($properties) {
|
||
|
return $properties;
|
||
|
}
|
||
|
);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param Module $module
|
||
|
*
|
||
|
* @return static
|
||
|
* @throws \Exception
|
||
|
*/
|
||
|
public function addModule(Module $module): Package
|
||
|
{
|
||
|
try {
|
||
|
$this->assertStatus(self::STATUS_IDLE, sprintf('add module %s', $module->id()));
|
||
|
|
||
|
$registeredServices = $this->addModuleServices(
|
||
|
$module,
|
||
|
self::MODULE_REGISTERED
|
||
|
);
|
||
|
$registeredFactories = $this->addModuleServices(
|
||
|
$module,
|
||
|
self::MODULE_REGISTERED_FACTORIES
|
||
|
);
|
||
|
$extended = $this->addModuleServices(
|
||
|
$module,
|
||
|
self::MODULE_EXTENDED
|
||
|
);
|
||
|
$isExecutable = $module instanceof ExecutableModule;
|
||
|
|
||
|
// ExecutableModules are collected and executed on Package::boot()
|
||
|
// when the Container is being compiled.
|
||
|
if ($isExecutable) {
|
||
|
/** @var ExecutableModule $module */
|
||
|
$this->executables[] = $module;
|
||
|
}
|
||
|
|
||
|
$added = $registeredServices || $registeredFactories || $extended || $isExecutable;
|
||
|
$status = $added ? self::MODULE_ADDED : self::MODULE_NOT_ADDED;
|
||
|
$this->moduleProgress($module->id(), $status);
|
||
|
} catch (\Throwable $throwable) {
|
||
|
$this->handleFailure($throwable, self::ACTION_FAILED_BUILD);
|
||
|
}
|
||
|
|
||
|
return $this;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param Package $package
|
||
|
* @return bool
|
||
|
* @throws \Exception
|
||
|
*/
|
||
|
public function connect(Package $package): bool
|
||
|
{
|
||
|
try {
|
||
|
if ($package === $this) {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
$packageName = $package->name();
|
||
|
$errorData = ['package' => $packageName, 'status' => $this->status];
|
||
|
$errorMessage = "Failed connecting package {$packageName}";
|
||
|
|
||
|
// Don't connect, if already connected
|
||
|
if (array_key_exists($packageName, $this->connectedPackages)) {
|
||
|
$error = "{$errorMessage} because it was already connected.";
|
||
|
do_action(
|
||
|
$this->hookName(self::ACTION_FAILED_CONNECTION),
|
||
|
$packageName,
|
||
|
new \WP_Error('already_connected', $error, $errorData)
|
||
|
);
|
||
|
|
||
|
throw new \Exception($error, 0, $this->lastError);
|
||
|
}
|
||
|
|
||
|
// Don't connect, if already booted or boot failed
|
||
|
$failed = $this->statusIs(self::STATUS_FAILED);
|
||
|
if ($failed || $this->statusIs(self::STATUS_BOOTED)) {
|
||
|
$status = $failed ? 'errored' : 'booted';
|
||
|
$error = "{$errorMessage} to a {$status} package.";
|
||
|
do_action(
|
||
|
$this->hookName(self::ACTION_FAILED_CONNECTION),
|
||
|
$packageName,
|
||
|
new \WP_Error("no_connect_on_{$status}", $error, $errorData)
|
||
|
);
|
||
|
|
||
|
throw new \Exception($error, 0, $this->lastError);
|
||
|
}
|
||
|
|
||
|
$this->connectedPackages[$packageName] = true;
|
||
|
|
||
|
// We put connected package's properties in this package's container, so that in modules
|
||
|
// "run" method we can access them if we need to.
|
||
|
$this->containerConfigurator->addService(
|
||
|
sprintf('%s.%s', $package->name(), self::PROPERTIES),
|
||
|
static function () use ($package): Properties {
|
||
|
return $package->properties();
|
||
|
}
|
||
|
);
|
||
|
|
||
|
// If the other package is booted, we can obtain a container, otherwise
|
||
|
// we build a proxy container
|
||
|
$container = $package->statusIs(self::STATUS_BOOTED)
|
||
|
? $package->container()
|
||
|
: new PackageProxyContainer($package);
|
||
|
|
||
|
$this->containerConfigurator->addContainer($container);
|
||
|
|
||
|
do_action(
|
||
|
$this->hookName(self::ACTION_PACKAGE_CONNECTED),
|
||
|
$packageName,
|
||
|
$this->status,
|
||
|
$container instanceof PackageProxyContainer
|
||
|
);
|
||
|
|
||
|
return true;
|
||
|
} catch (\Throwable $throwable) {
|
||
|
if (isset($packageName)) {
|
||
|
$this->connectedPackages[$packageName] = false;
|
||
|
}
|
||
|
$this->handleFailure($throwable, self::ACTION_FAILED_BUILD);
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @return static
|
||
|
*/
|
||
|
public function build(): Package
|
||
|
{
|
||
|
try {
|
||
|
// Don't allow building the application multiple times.
|
||
|
$this->assertStatus(self::STATUS_IDLE, 'build package');
|
||
|
|
||
|
do_action(
|
||
|
$this->hookName(self::ACTION_INIT),
|
||
|
$this
|
||
|
);
|
||
|
// Changing the status here ensures we can not call this method again, and also we can not
|
||
|
// add new modules, because both this and `addModule()` methods check for idle status.
|
||
|
// For backward compatibility, adding new modules via `boot()` will still be possible, even
|
||
|
// if deprecated, at the condition that the container was not yet accessed at that point.
|
||
|
$this->progress(self::STATUS_INITIALIZED);
|
||
|
} catch (\Throwable $throwable) {
|
||
|
$this->handleFailure($throwable, self::ACTION_FAILED_BUILD);
|
||
|
} finally {
|
||
|
$this->built = true;
|
||
|
}
|
||
|
|
||
|
return $this;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param Module ...$defaultModules Deprecated, use `addModule()` to add default modules.
|
||
|
* @return bool
|
||
|
*
|
||
|
* @throws \Throwable
|
||
|
*/
|
||
|
public function boot(Module ...$defaultModules): bool
|
||
|
{
|
||
|
try {
|
||
|
// Call build() if not called yet, and ensure any new module passed here is added
|
||
|
// as well, throwing if the container was already built.
|
||
|
$this->doBuild(...$defaultModules);
|
||
|
|
||
|
// Don't allow booting the application multiple times.
|
||
|
$this->assertStatus(self::STATUS_MODULES_ADDED, 'boot application', '<');
|
||
|
$this->assertStatus(self::STATUS_FAILED, 'boot application', '!=');
|
||
|
|
||
|
$this->progress(self::STATUS_MODULES_ADDED);
|
||
|
|
||
|
$this->doExecute();
|
||
|
|
||
|
$this->progress(self::STATUS_READY);
|
||
|
|
||
|
do_action(
|
||
|
$this->hookName(self::ACTION_READY),
|
||
|
$this
|
||
|
);
|
||
|
} catch (\Throwable $throwable) {
|
||
|
$this->handleFailure($throwable, self::ACTION_FAILED_BOOT);
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
$this->progress(self::STATUS_BOOTED);
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param Module ...$defaultModules
|
||
|
* @return void
|
||
|
*/
|
||
|
private function doBuild(Module ...$defaultModules): void
|
||
|
{
|
||
|
if ($defaultModules) {
|
||
|
$this->deprecatedArgument(
|
||
|
sprintf(
|
||
|
'Passing default modules to %1$s::boot() is deprecated since version 1.7.0.'
|
||
|
. ' Please add modules via %1$s::addModule().',
|
||
|
__CLASS__
|
||
|
),
|
||
|
__METHOD__,
|
||
|
'1.7.0'
|
||
|
);
|
||
|
}
|
||
|
|
||
|
if (!$this->built) {
|
||
|
array_map([$this, 'addModule'], $defaultModules);
|
||
|
$this->build();
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (
|
||
|
!$defaultModules
|
||
|
|| ($this->status >= self::STATUS_MODULES_ADDED)
|
||
|
|| ($this->statusIs(self::STATUS_FAILED))
|
||
|
) {
|
||
|
// if we don't have default modules, there's nothing to do, and if the status is beyond
|
||
|
// "modules added" or is failed, we do nothing as well and let `boot()` throw.
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
$backup = $this->status;
|
||
|
|
||
|
try {
|
||
|
// simulate idle status to prevent `addModule()` from throwing
|
||
|
// only if we don't have a container yet
|
||
|
$this->hasContainer or $this->status = self::STATUS_IDLE;
|
||
|
|
||
|
foreach ($defaultModules as $defaultModule) {
|
||
|
// If a module was added by `build()` or `addModule()` we can skip it, a
|
||
|
// deprecation was trigger to make it noticeable without breakage
|
||
|
if (!$this->moduleIs($defaultModule->id(), self::MODULE_ADDED)) {
|
||
|
$this->addModule($defaultModule);
|
||
|
}
|
||
|
}
|
||
|
} finally {
|
||
|
$this->status = $backup;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param Module $module
|
||
|
* @param string $status
|
||
|
* @return bool
|
||
|
*/
|
||
|
private function addModuleServices(Module $module, string $status): bool
|
||
|
{
|
||
|
$services = null;
|
||
|
$addCallback = null;
|
||
|
switch ($status) {
|
||
|
case self::MODULE_REGISTERED:
|
||
|
$services = $module instanceof ServiceModule ? $module->services() : null;
|
||
|
$addCallback = [$this->containerConfigurator, 'addService'];
|
||
|
break;
|
||
|
case self::MODULE_REGISTERED_FACTORIES:
|
||
|
$services = $module instanceof FactoryModule ? $module->factories() : null;
|
||
|
$addCallback = [$this->containerConfigurator, 'addFactory'];
|
||
|
break;
|
||
|
case self::MODULE_EXTENDED:
|
||
|
$services = $module instanceof ExtendingModule ? $module->extensions() : null;
|
||
|
$addCallback = [$this->containerConfigurator, 'addExtension'];
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (!$services) {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
$ids = [];
|
||
|
array_walk(
|
||
|
$services,
|
||
|
static function (callable $service, string $id) use ($addCallback, &$ids) {
|
||
|
/** @var callable(string, callable) $addCallback */
|
||
|
$addCallback($id, $service);
|
||
|
/** @var list<string> $ids */
|
||
|
$ids[] = $id;
|
||
|
}
|
||
|
);
|
||
|
/** @var list<string> $ids */
|
||
|
$this->moduleProgress($module->id(), $status, $ids);
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @return void
|
||
|
*
|
||
|
* @throws \Throwable
|
||
|
*/
|
||
|
private function doExecute(): void
|
||
|
{
|
||
|
foreach ($this->executables as $executable) {
|
||
|
$success = $executable->run($this->container());
|
||
|
$this->moduleProgress(
|
||
|
$executable->id(),
|
||
|
$success
|
||
|
? self::MODULE_EXECUTED
|
||
|
: self::MODULE_EXECUTION_FAILED
|
||
|
);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param string $moduleId
|
||
|
* @param string $status
|
||
|
* @param list<string>|null $serviceIds
|
||
|
*
|
||
|
* @return void
|
||
|
*/
|
||
|
private function moduleProgress(string $moduleId, string $status, ?array $serviceIds = null)
|
||
|
{
|
||
|
isset($this->moduleStatus[$status]) or $this->moduleStatus[$status] = [];
|
||
|
$this->moduleStatus[$status][] = $moduleId;
|
||
|
|
||
|
if (!$serviceIds || !$this->properties->isDebug()) {
|
||
|
$this->moduleStatus[self::MODULES_ALL][] = "{$moduleId} {$status}";
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
$description = sprintf('%s %s (%s)', $moduleId, $status, implode(', ', $serviceIds));
|
||
|
$this->moduleStatus[self::MODULES_ALL][] = $description;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @return array<string, list<string>>
|
||
|
*/
|
||
|
public function modulesStatus(): array
|
||
|
{
|
||
|
return $this->moduleStatus;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @return array<string, bool>
|
||
|
*/
|
||
|
public function connectedPackages(): array
|
||
|
{
|
||
|
return $this->connectedPackages;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param string $packageName
|
||
|
* @return bool
|
||
|
*/
|
||
|
public function isPackageConnected(string $packageName): bool
|
||
|
{
|
||
|
return $this->connectedPackages[$packageName] ?? false;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param string $moduleId
|
||
|
* @param string $status
|
||
|
*
|
||
|
* @return bool
|
||
|
*/
|
||
|
public function moduleIs(string $moduleId, string $status): bool
|
||
|
{
|
||
|
return in_array($moduleId, $this->moduleStatus[$status] ?? [], true);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Return the filter name to be used to extend modules of the plugin.
|
||
|
*
|
||
|
* If the plugin is single file `my-plugin.php` in plugins folder the filter name will be:
|
||
|
* `inpsyde.modularity.my-plugin`.
|
||
|
*
|
||
|
* If the plugin is in a sub-folder e.g. `my-plugin/index.php` the filter name will be:
|
||
|
* `inpsyde.modularity.my-plugin` anyway, so the file name is not relevant.
|
||
|
*
|
||
|
* @param string $suffix
|
||
|
*
|
||
|
* @return string
|
||
|
* @see Package::name()
|
||
|
*
|
||
|
*/
|
||
|
public function hookName(string $suffix = ''): string
|
||
|
{
|
||
|
$filter = self::HOOK_PREFIX . $this->properties->baseName();
|
||
|
|
||
|
if ($suffix) {
|
||
|
$filter .= '.' . $suffix;
|
||
|
}
|
||
|
|
||
|
return $filter;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @return Properties
|
||
|
*/
|
||
|
public function properties(): Properties
|
||
|
{
|
||
|
return $this->properties;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @return ContainerInterface
|
||
|
*
|
||
|
* @throws \Exception
|
||
|
*/
|
||
|
public function container(): ContainerInterface
|
||
|
{
|
||
|
$this->assertStatus(self::STATUS_INITIALIZED, 'obtain the container instance', '>=');
|
||
|
$this->hasContainer = true;
|
||
|
|
||
|
return $this->containerConfigurator->createReadOnlyContainer();
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @return string
|
||
|
*/
|
||
|
public function name(): string
|
||
|
{
|
||
|
return $this->properties->baseName();
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param int $status
|
||
|
*/
|
||
|
private function progress(int $status): void
|
||
|
{
|
||
|
$this->status = $status;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param int $status
|
||
|
*
|
||
|
* @return bool
|
||
|
*/
|
||
|
public function statusIs(int $status): bool
|
||
|
{
|
||
|
return $this->status === $status;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param \Throwable $throwable
|
||
|
* @param Package::ACTION_FAILED_* $action
|
||
|
* @return void
|
||
|
* @throws \Throwable
|
||
|
*/
|
||
|
private function handleFailure(\Throwable $throwable, string $action): void
|
||
|
{
|
||
|
$this->progress(self::STATUS_FAILED);
|
||
|
$hook = $this->hookName($action);
|
||
|
did_action($hook) or do_action($hook, $throwable);
|
||
|
|
||
|
if ($this->properties->isDebug()) {
|
||
|
throw $throwable;
|
||
|
}
|
||
|
|
||
|
$this->lastError = $throwable;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param int $status
|
||
|
* @param string $action
|
||
|
* @param string $operator
|
||
|
*
|
||
|
* @throws \Exception
|
||
|
* @psalm-suppress ArgumentTypeCoercion
|
||
|
*/
|
||
|
private function assertStatus(int $status, string $action, string $operator = '=='): void
|
||
|
{
|
||
|
if (!version_compare((string) $this->status, (string) $status, $operator)) {
|
||
|
throw new \Exception(
|
||
|
sprintf("Can't %s at this point of application.", $action),
|
||
|
0,
|
||
|
$this->lastError
|
||
|
);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Similar to WP's `_deprecated_argument()`, but executes regardless of WP_DEBUG and without
|
||
|
* translated message (so without attempting loading translation files).
|
||
|
*
|
||
|
* @param string $message
|
||
|
* @param string $function
|
||
|
* @param string $version
|
||
|
*
|
||
|
* @return void
|
||
|
*/
|
||
|
private function deprecatedArgument(string $message, string $function, string $version): void
|
||
|
{
|
||
|
do_action('deprecated_argument_run', $function, $message, $version);
|
||
|
|
||
|
if (apply_filters('deprecated_argument_trigger_error', true)) {
|
||
|
trigger_error($message, \E_USER_DEPRECATED);
|
||
|
}
|
||
|
}
|
||
|
}
|