Files
server/core/lib/Module/ModuleObject.php
2026-02-10 18:46:11 -05:00

180 lines
4.3 KiB
PHP

<?php
namespace KTXC\Module;
use JsonSerializable;
use KTXC\Module\Store\ModuleEntry;
use KTXF\Module\ModuleBrowserInterface;
use KTXF\Module\ModuleConsoleInterface;
use KTXF\Module\ModuleInstanceInterface;
/**
* Module is a unified wrapper that combines both the ModuleInterface instance
* (from filesystem) and ModuleEntry (from database) into a single object.
*
* This provides a single source of truth for all module information.
*/
class ModuleObject implements JsonSerializable
{
private ?ModuleInstanceInterface $instance = null;
private ?ModuleEntry $entry = null;
public function __construct(?ModuleInstanceInterface $instance = null, ?ModuleEntry $entry = null)
{
$this->instance = $instance;
$this->entry = $entry;
}
// ===== Serialization =====
public function jsonSerialize(): array
{
return [
'id' => $this->id(),
'handle' => $this->handle(),
'version' => $this->version(),
'namespace' => $this->namespace(),
'installed' => $this->installed(),
'enabled' => $this->enabled(),
'needsUpgrade' => $this->needsUpgrade(),
];
}
// ===== State from ModuleEntry (database) =====
public function id(): ?string
{
return $this->entry?->getId();
}
public function installed(): bool
{
return $this->entry?->getInstalled() ?? false;
}
public function enabled(): bool
{
return $this->entry?->getEnabled() ?? false;
}
// ===== Information from ModuleInterface (filesystem) =====
public function handle(): string
{
if ($this->instance) {
return $this->instance->handle();
}
if ($this->entry) {
return $this->entry->getHandle();
}
throw new \RuntimeException('Module has neither instance nor entry');
}
public function namespace(): ?string
{
if ($this->entry) {
return $this->entry->getNamespace();
}
if ($this->instance) {
// Extract namespace from class name
$className = get_class($this->instance);
$parts = explode('\\', $className);
if (count($parts) >= 2 && $parts[0] === 'KTXM') {
return $parts[1];
}
}
return null;
}
public function version(): string
{
// Prefer current version from filesystem
if ($this->instance) {
return $this->instance->version();
}
// Fallback to stored version
if ($this->entry) {
return $this->entry->getVersion();
}
return '0.0.0';
}
public function permissions(): array
{
return $this->instance?->permissions() ?? [];
}
// ===== Computed properties =====
public function needsUpgrade(): bool
{
if (!$this->instance || !$this->entry || !$this->installed()) {
return false;
}
$currentVersion = $this->instance->version();
$storedVersion = $this->entry->getVersion();
return version_compare($currentVersion, $storedVersion, '>');
}
// ===== Access to underlying objects =====
public function instance(): ?ModuleInstanceInterface
{
return $this->instance;
}
public function entry(): ?ModuleEntry
{
return $this->entry;
}
// ===== Lifecycle methods (delegate to instance) =====
public function boot(): void
{
$this->instance?->boot();
}
public function install(): void
{
$this->instance?->install();
}
public function uninstall(): void
{
$this->instance?->uninstall();
}
public function enable(): void
{
$this->instance?->enable();
}
public function disable(): void
{
$this->instance?->disable();
}
public function upgrade(): void
{
$this->instance?->upgrade();
}
public function registerBI(): array | null
{
if ($this->instance instanceof ModuleBrowserInterface) {
return $this->instance->registerBI();
}
return null;
}
public function registerCI(): array | null
{
if ($this->instance instanceof ModuleConsoleInterface) {
return $this->instance->registerCI();
}
return null;
}
}