Skip to content
79 changes: 79 additions & 0 deletions src/Classes/ModuleManager/AutoloadEntry.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
<?php

declare(strict_types=1);

/*
* This file is part of MMLC - ModifiedModuleLoaderClient.
*
* (c) Robin Wieschendorf <mail@robinwieschendorf.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace RobinTheHood\ModifiedModuleLoaderClient\ModuleManager;

use RobinTheHood\ModifiedModuleLoaderClient\Module;

class AutoloadEntry
{
public const TYPE_PSR_4 = 1;

/**
* @var int $type
*/
public $type;

/**
* @var ?Module $module
*/
public $module;

/**
* @var string $namespace
*/
public $namespace;

/**
* @var string $path
*/
public $path;

/**
* @var string $realPath
*/
public $realPath;

/**
* AutoloadEntry constructor.
*
* @param int $type
* @param ?Module $module
* @param string $namespace
* @param string $path
* @param string $realPath
*/
public function __construct(int $type, ?Module $module, string $namespace, string $path, string $realPath)
{
//TODO: Kontrolloeren ob es sich bei $namespace, path und $realPath um valide Werte handelt.
$this->type = $type;
$this->module = $module;
$this->namespace = $namespace;
$this->path = $path;
$this->realPath = $realPath;
}

public static function createFromModule(
Module $module,
string $namespace,
string $path,
int $type = self::TYPE_PSR_4
): AutoloadEntry {
$realPath = str_replace(
$module->getSourceMmlcDir(),
'vendor-mmlc/' . $module->getArchiveName(),
$path
);
return new AutoloadEntry($type, $module, $namespace, $path, $realPath);
}
}
202 changes: 202 additions & 0 deletions src/Classes/ModuleManager/AutoloadEntryCollection.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,202 @@
<?php

declare(strict_types=1);

/*
* This file is part of MMLC - ModifiedModuleLoaderClient.
*
* (c) Robin Wieschendorf <mail@robinwieschendorf.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace RobinTheHood\ModifiedModuleLoaderClient\ModuleManager;

use ArrayIterator;
use Exception;
use IteratorAggregate;
use RobinTheHood\ModifiedModuleLoaderClient\Module;

class AutoloadEntryCollection implements IteratorAggregate
{
/**
* @var AutoloadEntry[] $autoloadEntries
*/
private $autoloadEntries = [];

public static function createFromModule(Module $module): AutoloadEntryCollection
{
$collection = new AutoloadEntryCollection();

$autoload = $module->getAutoload();

if (!$autoload) {
return $collection;
}

$psr4Autoload = $autoload['psr-4'] ?? [];
if (!$psr4Autoload) {
return $collection;
}

foreach ($psr4Autoload as $namespace => $path) {
$autoloadEntry = AutoloadEntry::createFromModule($module, $namespace, $path);
$collection->add($autoloadEntry);
}

return $collection;
}

/**
* @param Module[] $modules
*/
public static function createFromModules(array $modules): AutoloadEntryCollection
{
$resultCollection = new AutoloadEntryCollection();
foreach ($modules as $module) {
$collection = AutoloadEntryCollection::createFromModule($module);
$resultCollection = $resultCollection->mergeWith($collection);
}
return $resultCollection;
}

/**
* Get all AutoloadEntry objects in the collection.
*
* @return AutoloadEntry[]
*/
public function getAutoloadEntries(): array
{
return $this->autoloadEntries;
}

public function add(AutoloadEntry $autoloadEntry): void
{
$this->validateNamespace($autoloadEntry);
$this->validateRealPath($autoloadEntry);

$this->autoloadEntries[] = $autoloadEntry;
}

public function mergeWith(AutoloadEntryCollection $otherCollection): AutoloadEntryCollection
{
$mergedCollection = new AutoloadEntryCollection();
$mergedCollection->autoloadEntries = array_merge($this->autoloadEntries, $otherCollection->autoloadEntries);
return $mergedCollection;
}

/**
* Get an AutoloadEntry by namespace.
*
* @param string $namespace
* @return AutoloadEntry|null
*/
public function getEntryByNamespace(string $namespace): ?AutoloadEntry
{
foreach ($this->autoloadEntries as $autoloadEntry) {
if ($autoloadEntry->namespace === $namespace) {
return $autoloadEntry;
}
}

return null;
}

/**
* Get an AutoloadEntry by path.
*
* @param string $path
* @return AutoloadEntry|null
*/
public function getEntryByRealPath(string $realPath): ?AutoloadEntry
{
foreach ($this->autoloadEntries as $autoloadEntry) {
if ($autoloadEntry->realPath === $realPath) {
return $autoloadEntry;
}
}

return null;
}

/**
* Get a new AutoloadEntryCollection with unique namespaces.
*
* @return AutoloadEntryCollection
*/
public function unique(): AutoloadEntryCollection
{
$uniqueCollection = new AutoloadEntryCollection();

foreach ($this->autoloadEntries as $autoloadEntry) {
$existingEntry = $uniqueCollection->getEntryByNamespace($autoloadEntry->namespace);

if ($existingEntry) {
continue;
}

$uniqueCollection->add($autoloadEntry);
}

return $uniqueCollection;
}

/**
* Get the iterator for iterating over AutoloadEntry objects.
*
* @return ArrayIterator<int, AutoloadEntry>
*/
public function getIterator(): ArrayIterator
{
return new ArrayIterator($this->autoloadEntries);
}

private function validateNamespace(AutoloadEntry $autoloadEntry): void
{
$foundAutoloadEntry = $this->getEntryByNamespace($autoloadEntry->namespace);

if (!$foundAutoloadEntry) {
return;
}

if ($foundAutoloadEntry->realPath === $autoloadEntry->realPath) {
return;
}

$archiveName = 'unknown module';
if ($autoloadEntry->module) {
$archiveName = $autoloadEntry->module->getArchiveName() . ':' . $autoloadEntry->module->getVersion();
}

throw new Exception(
"Can not add $archiveName because"
. " Namespace {$autoloadEntry->namespace} with path {$autoloadEntry->realPath} already exists with"
. " different path {$foundAutoloadEntry->realPath}"
);
}

private function validateRealPath(AutoloadEntry $autoloadEntry): void
{
$foundAutoloadEntry = $this->getEntryByRealPath($autoloadEntry->realPath);

if (!$foundAutoloadEntry) {
return;
}

if ($foundAutoloadEntry->namespace === $autoloadEntry->namespace) {
return;
}

$archiveName = 'unknown module';
if ($autoloadEntry->module) {
$archiveName = $autoloadEntry->module->getArchiveName() . ':' . $autoloadEntry->module->getVersion() ;
}

throw new Exception(
"Can not add $archiveName because"
. " path {$autoloadEntry->realPath} with namespace {$autoloadEntry->namespace} already exists with"
. " different namespace {$foundAutoloadEntry->namespace}"
);
}
}
50 changes: 23 additions & 27 deletions src/Classes/ModuleManager/AutoloadFileCreator.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,56 +15,52 @@

use RobinTheHood\ModifiedModuleLoaderClient\App;
use RobinTheHood\ModifiedModuleLoaderClient\Loader\LocalModuleLoader;
use RobinTheHood\ModifiedModuleLoaderClient\Module;

class AutoloadFileCreator
{
// TODO: In createAutoloadFile() Exceptions werfen im Fehlerfall
public function createAutoloadFile(): void
{
$installedLocalModules = $this->getInstalledModules();
$autoloadFileContent = $this->buildAutoloadFile($installedLocalModules);
$this->writeAutoloadFile($autoloadFileContent);
}

private function getInstalledModules()
/**
* @return Module[]
*/
private function getInstalledModules(): array
{
$localModuleLoader = LocalModuleLoader::createFromConfig();
$localModuleLoader->resetCache();
$installedModules = $localModuleLoader->loadAllInstalledVersions();
return $installedModules;
}

private function buildAutoloadFile(array $installedModules): string
private function convertAutoloadEntryToPsr4AutoloadPhp(AutoloadEntry $autoloadEntry): string
{
$namespaceEntrys = [];
foreach ($installedModules as $installedModule) {
$autoload = $installedModule->getAutoload();

if (!$autoload) {
continue;
}

if (!$autoload['psr-4']) {
continue;
}
$namespace = $autoloadEntry->namespace;
$realPath = $autoloadEntry->realPath;
$php = '$loader->setPsr4(\'' . $namespace . '\\\', DIR_FS_DOCUMENT_ROOT . \'' . $realPath . '\');';
return $php;
}

foreach ($autoload['psr-4'] as $namespace => $path) {
$path = str_replace(
$installedModule->getSourceMmlcDir(),
'vendor-mmlc/' . $installedModule->getArchiveName(),
$path
);
/**
* @param Module[] $installedModules
*/
private function buildAutoloadFile(array $installedModules): string
{
$autoloadEntryCollection = AutoloadEntryCollection::createFromModules($installedModules);
$autoloadEntryCollection = $autoloadEntryCollection->unique();

$namespaceEntrys[] =
'$loader->setPsr4(\'' . $namespace . '\\\', DIR_FS_DOCUMENT_ROOT . \'' . $path . '\');';
}
$phpEntries = [];
foreach ($autoloadEntryCollection as $autoloadEntry) {
$phpEntries[] = $this->convertAutoloadEntryToPsr4AutoloadPhp($autoloadEntry);
}

$namespaceEntrys = array_unique($namespaceEntrys);
$namespaceMapping = implode("\n", $namespaceEntrys);
$phpCodeNamespaceMappings = implode("\n", $phpEntries);

$template = file_get_contents(App::getTemplatesRoot() . '/autoload.php.tmpl');
$autoloadFileContent = str_replace('{VENDOR_PSR4_NAMESPACE_MAPPINGS}', $namespaceMapping, $template);
$autoloadFileContent = str_replace('{VENDOR_PSR4_NAMESPACE_MAPPINGS}', $phpCodeNamespaceMappings, $template);

return $autoloadFileContent;
}
Expand Down
Loading