Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 0 additions & 6 deletions .tools/psalm/baseline.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2075,9 +2075,6 @@
</MixedReturnStatement>
</file>
<file src="src/Core.php">
<LessSpecificReturnStatement>
<code><![CDATA[Type::array(self::getConfig('package-order', []))]]></code>
</LessSpecificReturnStatement>
<MixedArgument>
<code><![CDATA[$value]]></code>
<code><![CDATA[$value]]></code>
Expand All @@ -2101,9 +2098,6 @@
<code><![CDATA[$result | $item]]></code>
<code><![CDATA[Config::get(self::CONFIG_NAMESPACE, $key, $default)]]></code>
</MixedReturnStatement>
<MoreSpecificReturnType>
<code><![CDATA[list<non-empty-string>]]></code>
</MoreSpecificReturnType>
<PossiblyUndefinedArrayOffset>
<code><![CDATA[$server]]></code>
</PossiblyUndefinedArrayOffset>
Expand Down
3 changes: 2 additions & 1 deletion boot/addons.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

use Redaxo\Core\AbstractProject;
use Redaxo\Core\Addon\Addon;
use Redaxo\Core\Addon\AddonManager;
use Redaxo\Core\Core;
use Redaxo\Core\ExtensionPoint\Extension;
use Redaxo\Core\ExtensionPoint\ExtensionPoint;
Expand All @@ -17,7 +18,7 @@
if (Core::isSetup() || Core::isSafeMode()) {
$packageOrder = array_keys(Addon::getSetupAddons());
} else {
$packageOrder = Core::getPackageOrder();
$packageOrder = AddonManager::getAddonOrder();
}

// in the first run, we register all folders for class- and fragment-loading,
Expand Down
3 changes: 2 additions & 1 deletion boot/console.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

use Redaxo\Core\AbstractProject;
use Redaxo\Core\Addon\Addon;
use Redaxo\Core\Addon\AddonManager;
use Redaxo\Core\Console\Application;
use Redaxo\Core\Console\Command\ListCommand;
use Redaxo\Core\Console\CommandLoader;
Expand All @@ -25,7 +26,7 @@
Addon::initialize(!Core::isSetup());

if (!Core::isSetup()) {
foreach (Core::getPackageOrder() as $packageId) {
foreach (AddonManager::getAddonOrder() as $packageId) {
Addon::require($packageId)->enlist();
}

Expand Down
2 changes: 2 additions & 0 deletions rector.php
Original file line number Diff line number Diff line change
Expand Up @@ -443,6 +443,8 @@
new MethodCallRename(Cronjob\CronjobManager::class, 'hasManager', 'hasExecutor'),
])
->withConfiguredRule(RenameStaticMethodRector::class, [
new RenameStaticMethod(Core::class, 'getPackageConfig', Addon\AddonManager::class, 'getAddonConfig'),
new RenameStaticMethod(Core::class, 'getPackageOrder', Addon\AddonManager::class, 'getAddonOrder'),
new RenameStaticMethod(Core::class, 'getVersionHash', Util\Version::class, 'gitHash'),
new RenameStaticMethod(Util\Str::class, 'versionSplit', Util\Version::class, 'split'),
new RenameStaticMethod(Util\Str::class, 'versionCompare', Util\Version::class, 'compare'),
Expand Down
2 changes: 1 addition & 1 deletion src/Addon/Addon.php
Original file line number Diff line number Diff line change
Expand Up @@ -509,7 +509,7 @@ final public static function getSetupAddons(): array
final public static function initialize(bool $dbExists = true): void
{
if ($dbExists) {
$config = Core::getPackageConfig();
$config = AddonManager::getAddonConfig();
} else {
$config = [];
foreach (Core::getProperty('setup_addons') as $addon) {
Expand Down
95 changes: 76 additions & 19 deletions src/Addon/AddonManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
use Redaxo\Core\Backend\Controller;
use Redaxo\Core\Base\FactoryTrait;
use Redaxo\Core\Config;
use Redaxo\Core\Core;
use Redaxo\Core\Exception\RuntimeException;
use Redaxo\Core\Exception\UserMessageException;
use Redaxo\Core\Filesystem\Dir;
Expand All @@ -24,13 +23,22 @@
use function is_string;
use function sprintf;

use const JSON_PRETTY_PRINT;
use const JSON_THROW_ON_ERROR;
use const JSON_UNESCAPED_SLASHES;
use const JSON_UNESCAPED_UNICODE;

/**
* @phpstan-type TAddonConfig array<non-empty-string, array{class: class-string<Addon>, install: bool, status: bool}>
* @phpstan-type TAddonOrder list<non-empty-string>
*/
class AddonManager
{
use FactoryTrait;

protected bool $generatePackageOrder = true;
/** @var array{config: TAddonConfig, order: TAddonOrder}|null */
private static ?array $addonsData = null;

protected string $message = '';

final protected function __construct(
Expand Down Expand Up @@ -97,9 +105,7 @@ public function install(): bool
$this->addon->setProperty('status', true);
}
static::saveConfig();
if ($this->generatePackageOrder) {
self::generatePackageOrder();
}
self::generateAddonOrder();

foreach ($this->addon->getProperty('default_config', []) as $key => $value) {
if (!$this->addon->hasConfig($key)) {
Expand Down Expand Up @@ -209,8 +215,8 @@ public function activate(): bool
$this->addon->setProperty('status', true);
static::saveConfig();
}
if (true === $state && $this->generatePackageOrder) {
self::generatePackageOrder();
if (true === $state) {
self::generateAddonOrder();
}
} else {
$state = $this->i18n('not_installed', $this->addon->name);
Expand Down Expand Up @@ -243,9 +249,7 @@ public function deactivate(): bool
// clear cache of addon
$this->addon->clearCache();

if ($this->generatePackageOrder) {
self::generatePackageOrder();
}
self::generateAddonOrder();

$this->message = $this->i18n('deactivated', $this->addon->name);
return true;
Expand Down Expand Up @@ -330,16 +334,28 @@ protected function i18n(string $key, string|int ...$replacements): string
return I18n::msg($fullKey, ...$replacements);
}

/** @return TAddonConfig */
public static function getAddonConfig(): array
{
return self::loadAddonsData()['config'];
}

/** @return TAddonOrder */
public static function getAddonOrder(): array
{
return self::loadAddonsData()['order'];
}

/** Generates the addon order. */
public static function generatePackageOrder(): void
public static function generateAddonOrder(): void
{
/** @var list<string> $early */
/** @var list<non-empty-string> $early */
$early = [];
/** @var list<string> $normal */
/** @var list<non-empty-string> $normal */
$normal = [];
/** @var list<string> $late */
/** @var list<non-empty-string> $late */
$late = [];
/** @var array<string, array<string, true>> $requires */
/** @var array<non-empty-string, array<non-empty-string, true>> $requires */
$requires = [];

$add = static function ($id) use (&$add, &$normal, &$requires) {
Expand Down Expand Up @@ -369,7 +385,10 @@ public static function generatePackageOrder(): void
}
}
}
Core::setConfig('package-order', array_merge($early, $normal, array_keys($requires), $late));

/** @var TAddonOrder $order */
$order = array_merge($early, $normal, array_keys($requires), $late);
self::saveAddonsData(order: $order);
}

/** Saves the addon config. */
Expand All @@ -381,13 +400,14 @@ protected static function saveConfig(): void
$config[$addonName]['install'] = $addon->isInstalled();
$config[$addonName]['status'] = $addon->isAvailable();
}
Core::setConfig('package-config', $config);

self::saveAddonsData(config: $config);
}

/** Synchronizes the addons with the file system. */
public static function synchronizeWithFileSystem(): void
{
$config = Core::getPackageConfig();
$config = self::getAddonConfig();
$registeredAddons = Addon::getRegisteredAddons();
$packages = self::getComposerPackages();
$addonClasses = self::getAddonClasses();
Expand All @@ -413,10 +433,47 @@ public static function synchronizeWithFileSystem(): void
}
ksort($config);

Core::setConfig('package-config', $config);
self::saveAddonsData(config: $config);
Addon::initialize();
}

/** @return array{config: TAddonConfig, order: TAddonOrder} */
private static function loadAddonsData(): array
{
if (null !== self::$addonsData) {
return self::$addonsData;
}

$file = Path::coreData('addons.json');
if (!is_file($file)) {
return self::$addonsData = ['config' => [], 'order' => []];
}

/** @var array{config: TAddonConfig, order: TAddonOrder} $data */
$data = File::getCache($file) ?? ['config' => [], 'order' => []];

return self::$addonsData = $data;
}

/**
* @param TAddonConfig|null $config
* @param TAddonOrder|null $order
*/
private static function saveAddonsData(?array $config = null, ?array $order = null): void
{
$data = self::loadAddonsData();

if (null !== $config) {
$data['config'] = $config;
}
if (null !== $order) {
$data['order'] = $order;
}

self::$addonsData = $data;
File::put(Path::coreData('addons.json'), (string) json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE));
}

/**
* Returns the addon-class mapping for all registered `redaxo-addon` packages, read from `vendor/composer/installed.json`.
*
Expand Down
3 changes: 2 additions & 1 deletion src/Console/Application.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use ParseError;
use Redaxo\Core\AbstractProject;
use Redaxo\Core\Addon\Addon;
use Redaxo\Core\Addon\AddonManager;
use Redaxo\Core\Console\Command\AbstractCommand;
use Redaxo\Core\Console\Command\OnlySetupAddonsInterface;
use Redaxo\Core\Console\Command\StandaloneInterface;
Expand Down Expand Up @@ -119,7 +120,7 @@ private function loadPackages(AbstractCommand $command): void
if (!Core::isSetup()) {
// boot all known packages in the defined order
// which reflects dependencies before consumers
foreach (Core::getPackageOrder() as $packageId) {
foreach (AddonManager::getAddonOrder() as $packageId) {
Addon::require($packageId)->boot();
}
}
Expand Down
3 changes: 1 addition & 2 deletions src/Console/Command/MigrateCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

use Redaxo\Core\Addon\Addon;
use Redaxo\Core\Addon\AddonManager;
use Redaxo\Core\Core;
use Redaxo\Core\Database\Sql;
use Redaxo\Core\Exception\UserMessageException;
use Redaxo\Core\Filesystem\File;
Expand Down Expand Up @@ -47,7 +46,7 @@ public function __invoke(SymfonyStyle $io): int
// align registered addons with composer state: drop config of orphaned addons, register new ones
AddonManager::synchronizeWithFileSystem();

$packages = array_merge(['core'], Core::getPackageOrder());
$packages = array_merge(['core'], AddonManager::getAddonOrder());

$io->section('Migrating');

Expand Down
16 changes: 0 additions & 16 deletions src/Core.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
namespace Redaxo\Core;

use Composer\InstalledVersions;
use Redaxo\Core\Addon\Addon;
use Redaxo\Core\Console\Application;
use Redaxo\Core\Database\Configuration as DatabaseConfiguration;
use Redaxo\Core\Exception\InvalidArgumentException;
Expand Down Expand Up @@ -455,21 +454,6 @@ public static function getVersion(?string $format = null): string
return $version;
}

/**
* @return array<non-empty-string, array{class: class-string<Addon>, install: bool, status: bool}>
* @psalm-suppress MixedReturnTypeCoercion
*/
public static function getPackageConfig(): array
{
return Type::array(self::getConfig('package-config', []));
}

/** @return list<non-empty-string> */
public static function getPackageOrder(): array
{
return Type::array(self::getConfig('package-order', []));
}

/**
* Returns the title tag and if the property "use_accesskeys" is true, the accesskey tag.
*
Expand Down
4 changes: 2 additions & 2 deletions src/Setup/Importer.php
Original file line number Diff line number Diff line change
Expand Up @@ -172,10 +172,10 @@ private static function reinstallPackages(): string
AddonManager::synchronizeWithFileSystem();

// enlist activated packages to ensure that all their classess are known in autoloader and can be referenced in other package's install.php
foreach (Core::getPackageOrder() as $packageId) {
foreach (AddonManager::getAddonOrder() as $packageId) {
Addon::require($packageId)->enlist();
}
foreach (Core::getPackageOrder() as $packageId) {
foreach (AddonManager::getAddonOrder() as $packageId) {
$package = Addon::require($packageId);
$manager = AddonManager::factory($package);

Expand Down