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
18 changes: 0 additions & 18 deletions .idea/jsonSchemas.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 0 additions & 14 deletions .tools/psalm/baseline.xml
Original file line number Diff line number Diff line change
Expand Up @@ -1451,31 +1451,17 @@
</PossiblyNullReference>
</file>
<file src="src/Addon/Addon.php">
<MixedArgument>
<code><![CDATA[$value]]></code>
</MixedArgument>
<MixedAssignment>
<code><![CDATA[$value]]></code>
<code><![CDATA[$value]]></code>
</MixedAssignment>
<MixedOperand>
<code><![CDATA[$value]]></code>
</MixedOperand>
<PossiblyFalseArgument>
<code><![CDATA[$f]]></code>
<code><![CDATA[$f]]></code>
</PossiblyFalseArgument>
</file>
<file src="src/Addon/AddonManager.php">
<MixedArgument>
<code><![CDATA[$key]]></code>
</MixedArgument>
<MixedArrayOffset>
<code><![CDATA[$ps[$id]]]></code>
<code><![CDATA[$requires[$id]]]></code>
</MixedArrayOffset>
<MixedAssignment>
<code><![CDATA[$key]]></code>
<code><![CDATA[$normal[]]]></code>
<code><![CDATA[$value]]></code>
</MixedAssignment>
Expand Down
2 changes: 1 addition & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ This repository contains the **REDAXO core** under `src/` (`Redaxo\Core\`), back

### Key concepts
- **`Core` static class** (`src/Core.php`) — central application registry for paths, config, request, current user.
- **Addon system** — `Addon` / `AddonManager` (`src/Addon/`). Each addon has a `package.yml` (metadata + page config) plus optional `boot.php` (runtime init) and `install.php` (schema/data setup — must be idempotent, runs on every `console migrate`).
- **Addon system** — `Addon` / `AddonManager` (`src/Addon/`). Each addon is a subclass of `Addon`, registered via composer.json `extra.redaxo.addon-class`. Metadata comes from composer.json; integration happens through overridable hooks — `boot()` (runtime init), `install()`/`uninstall()` (schema/data setup — must be idempotent, runs on every `console migrate`), `getPages()` (backend pages) — plus the `$load` and `$defaultConfig` properties.
- **Extension points** — REDAXO's hook/event system: register listeners with `Extension::register('NAME', ...)`, fire points with `Extension::registerPoint(new ExtensionPoint(...))`. Classes live under `Redaxo\Core\ExtensionPoint`. This is the primary integration mechanism for addons.
- **Fragments** (`fragments/`) — template snippets rendered via `Fragment` (`src/View/Fragment.php`).
- **Boot flow** — `AbstractProject` (Symfony `RuntimeInterface`) drives boot via `boot/core.php` → `boot/addons.php` → environment entry (`boot/backend.php`, `boot/frontend.php`, `boot/console.php`).
Expand Down
1 change: 0 additions & 1 deletion lang/de_de.lang
Original file line number Diff line number Diff line change
Expand Up @@ -327,7 +327,6 @@ package_activate = aktivieren
package_yes = ja
package_no = nein
package_caption = Liste der verfügbaren Packages
package_invalid_yml_file = Die package.yml ist invalid:
package_install_cant_copy_files = Fehler beim Kopieren des /assets Ordners!
package_install_cant_delete_files = Fehler beim Löschen des /assets Ordners!
package_jump_to = Zu "{0}" springen
Expand Down
1 change: 0 additions & 1 deletion lang/en_gb.lang
Original file line number Diff line number Diff line change
Expand Up @@ -326,7 +326,6 @@ package_activate = activate
package_yes = yes
package_no = no
package_caption = List of available packages
package_invalid_yml_file = The file package.yml is invalid:
package_install_cant_copy_files = An error occurred when copying the /assets folder!
package_install_cant_delete_files = An error occurred when deleting the /assets folder!
package_jump_to = Jump to "{0}"
Expand Down
2 changes: 1 addition & 1 deletion pages/system/report.html.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
foreach ($group as $label => $value) {
if (SystemReport::TITLE_PACKAGES === $title || SystemReport::TITLE_REDAXO === $title) {
if (null === $value) {
throw new RuntimeException('Package ' . $label . ' does not define a proper version in its package.yml.');
throw new RuntimeException('Package ' . $label . ' does not define a proper version in its composer.json.');
}
if (Version::isUnstable($value)) {
$value = '<i class="rex-icon rex-icon-unstable-version" title="' . I18n::msg('unstable_version') . '"></i> ' . escape($value);
Expand Down
13 changes: 0 additions & 13 deletions schemas/package.json

This file was deleted.

93 changes: 7 additions & 86 deletions src/Addon/Addon.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
use Redaxo\Core\Filesystem\Path;
use Redaxo\Core\Filesystem\Url;
use Redaxo\Core\Translation\I18n;
use Redaxo\Core\Util\Exception\YamlParseException;
use Redaxo\Core\Util\Formatter;
use Redaxo\Core\Util\Type;
use Redaxo\Core\View\Fragment;
Expand All @@ -33,10 +32,6 @@

abstract class Addon
{
final public const string FILE_PACKAGE = 'package.yml';

private const string PROPERTIES_CACHE_FILE = 'packages.cache';

/**
* Array of all addons.
*
Expand All @@ -62,6 +57,13 @@ abstract class Addon
/** Loading position relative to other addons during boot. Override to load this addon early or late. */
public protected(set) LoadOrder $load = LoadOrder::Normal;

/**
* Default config values applied on install (only for keys that are not already set). Override to provide defaults.
*
* @var array<string, mixed>
*/
public protected(set) array $defaultConfig = [];

/** Lifecycle state of the addon. */
public private(set) AddonState $state = AddonState::Uninstalled;

Expand All @@ -72,9 +74,6 @@ abstract class Addon
*/
private array $properties = [];

/** Flag whether the properties of package.yml are loaded. */
private bool $propertiesLoaded = false;

/** @var array<string, mixed>|null */
private ?array $composerJson = null;

Expand Down Expand Up @@ -205,9 +204,6 @@ final public function getProperty(string $key, mixed $default = null): mixed
/** @param non-empty-string $key */
final public function hasProperty(string $key): bool
{
if (!isset($this->properties[$key]) && !$this->propertiesLoaded) {
$this->loadProperties();
}
return isset($this->properties[$key]);
}

Expand Down Expand Up @@ -321,75 +317,6 @@ final public function i18n(string $key, string|int ...$replacements): string
return I18n::msg($key, ...$replacements);
}

/** Loads the properties of package.yml. */
final public function loadProperties(bool $force = false): void
{
$file = $this->getPath(self::FILE_PACKAGE);
if (!is_file($file)) {
$this->propertiesLoaded = true;
return;
}

/** @var array<string, array{timestamp: int, data: array<string, mixed>}>|null $cache */
static $cache = null;
if (null === $cache) {
/** @var array<string, array{timestamp: int, data: array<string, mixed>}> $cache */
$cache = File::getCache(Path::coreCache(self::PROPERTIES_CACHE_FILE));
}
$id = $this->name;

if ($force) {
unset($cache[$id]);
}

$isCached = isset($cache[$id]);
$isBackendAdmin = Core::isBackend() && Core::getUser()?->admin;
if (!$isCached || (Core::getConsole() || $isBackendAdmin) && $cache[$id]['timestamp'] < filemtime($file)) {
try {
$properties = File::getConfig($file);

$cache[$id]['timestamp'] = filemtime($file);
$cache[$id]['data'] = $properties;

/** @var bool $registeredShutdown */
static $registeredShutdown = false;
if (!$registeredShutdown) {
$registeredShutdown = true;
register_shutdown_function(static function () use (&$cache) {
foreach ($cache as $addon => $_) {
if (!self::exists($addon)) {
unset($cache[$addon]);
}
}
File::putCache(Path::coreCache(self::PROPERTIES_CACHE_FILE), $cache);
});
}
} catch (YamlParseException $exception) {
if ($this->isInstalled()) {
throw $exception;
}

$properties = [];
}
} else {
$properties = $cache[$id]['data'];
}

$this->properties = [];
if ($properties) {
foreach ($properties as $key => $value) {
$key = Type::string($key);
if ('supportpage' !== $key) {
$value = I18n::translateArray($value, false, $this->i18n(...));
} elseif (null !== $value && !preg_match('@^https?://@i', $value)) {
$value = 'https://' . $value;
}
$this->properties[$key] = $value;
}
}
$this->propertiesLoaded = true;
}

final public function getLicense(): ?string
{
/** @var string|list<string>|null $license */
Expand Down Expand Up @@ -423,12 +350,6 @@ final public function clearCache(): void
throw new RuntimeException('Addon cache directory "' . $cacheDir . '" is not writable.');
}

$cache = File::getCache($path = Path::coreCache(self::PROPERTIES_CACHE_FILE));
if ($cache) {
unset($cache[$this->name]);
File::putCache($path, $cache);
}

Extension::registerPoint(new AddonCacheDeleted($this));
}

Expand Down
11 changes: 1 addition & 10 deletions src/Addon/AddonManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
use Redaxo\Core\Filesystem\Path;
use Redaxo\Core\Filesystem\Url;
use Redaxo\Core\Translation\I18n;
use Redaxo\Core\Util\Exception\YamlParseException;
use Redaxo\Core\Util\Str;
use Redaxo\Core\Util\Type;

Expand Down Expand Up @@ -66,14 +65,6 @@ public function getMessage(): string
public function install(): bool
{
try {
// check package.yml
$addonFile = $this->addon->getPath(Addon::FILE_PACKAGE);
try {
File::getConfig($addonFile);
} catch (YamlParseException $e) {
throw new UserMessageException($this->i18n('invalid_yml_file') . ' ' . $e->getMessage());
}

// check requirements and conflicts
$message = '';
if (!$this->checkRequirements()) {
Expand All @@ -91,7 +82,7 @@ public function install(): bool
$this->addon->install();
$successMessage = (string) $this->addon->getProperty('successmsg', '');

foreach ($this->addon->getProperty('default_config', []) as $key => $value) {
foreach ($this->addon->defaultConfig as $key => $value) {
if (!$this->addon->hasConfig($key)) {
$this->addon->setConfig($key, $value);
}
Expand Down
2 changes: 1 addition & 1 deletion src/Console/CommandLoader.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
/**
* Discovers all commands that are marked with the {@see AsCommand} attribute and extend {@see AbstractCommand},
* both in the core and in the active addons. Addons therefore register their commands simply by adding the
* attribute to a command class — no `package.yml` configuration is required.
* attribute to a command class.
*
* Commands are returned as {@see LazyCommand}, so that listing the commands (e.g. `console list`) does not
* instantiate every command class — only the command that is actually executed is instantiated.
Expand Down