From eebcee928291abce4be36138d30dd940286cd13f Mon Sep 17 00:00:00 2001 From: Coen Jacobs Date: Thu, 12 Sep 2024 15:45:30 +0200 Subject: [PATCH 01/24] Remove phpstan baseline as it is old and obsolete --- phpstan-baseline.neon | 211 ------------------------------------------ phpstan.neon.dist | 3 - 2 files changed, 214 deletions(-) delete mode 100644 phpstan-baseline.neon diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon deleted file mode 100644 index eb0b0284..00000000 --- a/phpstan-baseline.neon +++ /dev/null @@ -1,211 +0,0 @@ -parameters: - ignoreErrors: - - - message: "#^Method CoenJacobs\\\\Mozart\\\\Composer\\\\Autoload\\\\Autoloader\\:\\:getSearchNamespace\\(\\) has no return type specified\\.$#" - count: 1 - path: src/Composer/Autoload/Autoloader.php - - - - message: "#^Method CoenJacobs\\\\Mozart\\\\Composer\\\\Autoload\\\\Autoloader\\:\\:processConfig\\(\\) has no return type specified\\.$#" - count: 1 - path: src/Composer/Autoload/Autoloader.php - - - - message: "#^Method CoenJacobs\\\\Mozart\\\\Composer\\\\Autoload\\\\Autoloader\\:\\:processConfig\\(\\) has parameter \\$autoloadConfig with no type specified\\.$#" - count: 1 - path: src/Composer/Autoload/Autoloader.php - - - - message: "#^Method CoenJacobs\\\\Mozart\\\\Composer\\\\Autoload\\\\Classmap\\:\\:processConfig\\(\\) has parameter \\$autoloadConfig with no type specified\\.$#" - count: 1 - path: src/Composer/Autoload/Classmap.php - - - - message: "#^Property CoenJacobs\\\\Mozart\\\\Composer\\\\Autoload\\\\Classmap\\:\\:\\$files type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/Composer/Autoload/Classmap.php - - - - message: "#^Property CoenJacobs\\\\Mozart\\\\Composer\\\\Autoload\\\\Classmap\\:\\:\\$paths type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/Composer/Autoload/Classmap.php - - - - message: "#^Method CoenJacobs\\\\Mozart\\\\Composer\\\\Autoload\\\\NamespaceAutoloader\\:\\:processConfig\\(\\) has parameter \\$autoloadConfig with no type specified\\.$#" - count: 1 - path: src/Composer/Autoload/NamespaceAutoloader.php - - - - message: "#^PHPDoc tag @var has invalid value \\(\\)\\: Unexpected token \"\\*/\", expected type at offset 9$#" - count: 1 - path: src/Composer/Package.php - - - - message: "#^Parameter \\#1 \\$json of function json_decode expects string, string\\|false given\\.$#" - count: 1 - path: src/Composer/Package.php - - - - message: "#^Property CoenJacobs\\\\Mozart\\\\Composer\\\\Package\\:\\:\\$config has no type specified\\.$#" - count: 1 - path: src/Composer/Package.php - - - - message: "#^Property CoenJacobs\\\\Mozart\\\\Composer\\\\Package\\:\\:\\$dependencies type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/Composer/Package.php - - - - message: "#^Access to an undefined property object\\:\\:\\$dep_namespace\\.$#" - count: 2 - path: src/Console/Commands/Compose.php - - - - message: "#^Method CoenJacobs\\\\Mozart\\\\Console\\\\Commands\\\\Compose\\:\\:getAllDependenciesOfPackage\\(\\) has parameter \\$dependencies with no value type specified in iterable type array\\.$#" - count: 1 - path: src/Console/Commands/Compose.php - - - - message: "#^Method CoenJacobs\\\\Mozart\\\\Console\\\\Commands\\\\Compose\\:\\:getAllDependenciesOfPackage\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/Console/Commands/Compose.php - - - - message: "#^Method CoenJacobs\\\\Mozart\\\\Console\\\\Commands\\\\Compose\\:\\:movePackage\\(\\) has parameter \\$package with no type specified\\.$#" - count: 1 - path: src/Console/Commands/Compose.php - - - - message: "#^Method CoenJacobs\\\\Mozart\\\\Console\\\\Commands\\\\Compose\\:\\:movePackages\\(\\) has parameter \\$packages with no value type specified in iterable type array\\.$#" - count: 1 - path: src/Console/Commands/Compose.php - - - - message: "#^Method CoenJacobs\\\\Mozart\\\\Console\\\\Commands\\\\Compose\\:\\:replacePackage\\(\\) has parameter \\$package with no type specified\\.$#" - count: 1 - path: src/Console/Commands/Compose.php - - - - message: "#^Method CoenJacobs\\\\Mozart\\\\Console\\\\Commands\\\\Compose\\:\\:replacePackages\\(\\) has parameter \\$packages with no value type specified in iterable type array\\.$#" - count: 1 - path: src/Console/Commands/Compose.php - - - - message: "#^Method CoenJacobs\\\\Mozart\\\\Console\\\\Commands\\\\Compose\\:\\:replaceParentInTree\\(\\) has parameter \\$packages with no value type specified in iterable type array\\.$#" - count: 1 - path: src/Console/Commands/Compose.php - - - - message: "#^PHPDoc tag @var has invalid value \\(\\)\\: Unexpected token \"\\*/\", expected type at offset 9$#" - count: 1 - path: src/Console/Commands/Compose.php - - - - message: "#^Parameter \\#1 \\$json of function json_decode expects string, string\\|false given\\.$#" - count: 2 - path: src/Console/Commands/Compose.php - - - - message: "#^Property CoenJacobs\\\\Mozart\\\\Console\\\\Commands\\\\Compose\\:\\:\\$config has no type specified\\.$#" - count: 1 - path: src/Console/Commands/Compose.php - - - - message: "#^Property CoenJacobs\\\\Mozart\\\\Console\\\\Commands\\\\Compose\\:\\:\\$workingDir \\(string\\) does not accept string\\|false\\.$#" - count: 1 - path: src/Console/Commands/Compose.php - - - - message: "#^Access to an undefined property CoenJacobs\\\\Mozart\\\\Composer\\\\Autoload\\\\Autoloader\\:\\:\\$namespace\\.$#" - count: 1 - path: src/Mover.php - - - - message: "#^Method CoenJacobs\\\\Mozart\\\\Mover\\:\\:__construct\\(\\) has parameter \\$config with no type specified\\.$#" - count: 1 - path: src/Mover.php - - - - message: "#^Method CoenJacobs\\\\Mozart\\\\Mover\\:\\:__construct\\(\\) has parameter \\$workingDir with no type specified\\.$#" - count: 1 - path: src/Mover.php - - - - message: "#^Property CoenJacobs\\\\Mozart\\\\Mover\\:\\:\\$movedPackages type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/Mover.php - - - - message: "#^Anonymous function has an unused use \\$contents\\.$#" - count: 1 - path: src/Replace/ClassmapReplacer.php - - - - message: "#^Method CoenJacobs\\\\Mozart\\\\Replace\\\\ClassmapReplacer\\:\\:replace\\(\\) should return string but returns string\\|null\\.$#" - count: 1 - path: src/Replace/ClassmapReplacer.php - - - - message: "#^Method CoenJacobs\\\\Mozart\\\\Replace\\\\ClassmapReplacer\\:\\:saveReplacedClass\\(\\) has parameter \\$classname with no type specified\\.$#" - count: 1 - path: src/Replace/ClassmapReplacer.php - - - - message: "#^Strict comparison using \\=\\=\\= between false and non\\-falsy\\-string will always evaluate to false\\.$#" - count: 1 - path: src/Replace/ClassmapReplacer.php - - - - message: "#^Method CoenJacobs\\\\Mozart\\\\Replace\\\\NamespaceReplacer\\:\\:replace\\(\\) should return string but returns string\\|null\\.$#" - count: 1 - path: src/Replace/NamespaceReplacer.php - - - - message: "#^Method CoenJacobs\\\\Mozart\\\\Replace\\\\Replacer\\:\\:replace\\(\\) has no return type specified\\.$#" - count: 1 - path: src/Replace/Replacer.php - - - - message: "#^Method CoenJacobs\\\\Mozart\\\\Replace\\\\Replacer\\:\\:replace\\(\\) has parameter \\$contents with no type specified\\.$#" - count: 1 - path: src/Replace/Replacer.php - - - - message: "#^Method CoenJacobs\\\\Mozart\\\\Replace\\\\Replacer\\:\\:setAutoloader\\(\\) has no return type specified\\.$#" - count: 1 - path: src/Replace/Replacer.php - - - - message: "#^Method CoenJacobs\\\\Mozart\\\\Replacer\\:\\:__construct\\(\\) has parameter \\$config with no type specified\\.$#" - count: 1 - path: src/Replacer.php - - - - message: "#^Method CoenJacobs\\\\Mozart\\\\Replacer\\:\\:__construct\\(\\) has parameter \\$workingDir with no type specified\\.$#" - count: 1 - path: src/Replacer.php - - - - message: "#^Method CoenJacobs\\\\Mozart\\\\Replacer\\:\\:replaceInFile\\(\\) has parameter \\$targetFile with no type specified\\.$#" - count: 1 - path: src/Replacer.php - - - - message: "#^Parameter \\#2 \\$contents of method League\\\\Flysystem\\\\Filesystem\\:\\:put\\(\\) expects string, string\\|null given\\.$#" - count: 1 - path: src/Replacer.php - - - - message: "#^Parameter \\#3 \\$subject of function preg_replace_callback expects array\\|string, string\\|null given\\.$#" - count: 1 - path: src/Replacer.php - - - - message: "#^Property CoenJacobs\\\\Mozart\\\\Replacer\\:\\:\\$replacedClasses type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/Replacer.php - - - - message: "#^Strict comparison using \\=\\=\\= between false and non\\-falsy\\-string will always evaluate to false\\.$#" - count: 2 - path: src/Replacer.php diff --git a/phpstan.neon.dist b/phpstan.neon.dist index dcc32dd4..38df4a92 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -1,6 +1,3 @@ -includes: - - phpstan-baseline.neon - parameters: level: 8 reportUnmatchedIgnoredErrors: false From ef3b2dc0bd0f1b48e6b42ba1b2b0e96f0deabcd7 Mon Sep 17 00:00:00 2001 From: Coen Jacobs Date: Thu, 12 Sep 2024 15:46:05 +0200 Subject: [PATCH 02/24] Fixes resulting from no phpstan baseline being used anymore --- src/Console/Commands/Compose.php | 9 ++++++++- src/Mover.php | 2 +- src/Replace/ClassmapReplacer.php | 21 +++++++++++++-------- src/Replace/NamespaceReplacer.php | 12 ++++++++++-- src/Replace/Replacer.php | 4 ++-- src/Replacer.php | 15 ++++++--------- 6 files changed, 40 insertions(+), 23 deletions(-) diff --git a/src/Console/Commands/Compose.php b/src/Console/Commands/Compose.php index aad21e6a..2a9b762d 100644 --- a/src/Console/Commands/Compose.php +++ b/src/Console/Commands/Compose.php @@ -22,7 +22,14 @@ class Compose extends Command public function __construct() { - $this->workingDir = getcwd(); + $workingDir = getcwd(); + + if (! $workingDir) { + throw new Exception('Unable to determine the working directory.'); + } + + $this->workingDir = $workingDir; + parent::__construct(); } diff --git a/src/Mover.php b/src/Mover.php index 4f3d65d6..8b676be7 100644 --- a/src/Mover.php +++ b/src/Mover.php @@ -73,7 +73,7 @@ private function deleteDepTargetDirs(Package $package): void switch ($autoloaderType) { case Psr0::class: case Psr4::class: - $outputDir = $this->config->getDepDirectory() . $packageAutoloader->namespace; + $outputDir = $this->config->getDepDirectory() . $packageAutoloader->getSearchNamespace(); $outputDir = str_replace('\\', DIRECTORY_SEPARATOR, $outputDir); $this->filesystem->deleteDirectory($outputDir); break; diff --git a/src/Replace/ClassmapReplacer.php b/src/Replace/ClassmapReplacer.php index 41323fa3..39b4fa52 100644 --- a/src/Replace/ClassmapReplacer.php +++ b/src/Replace/ClassmapReplacer.php @@ -6,6 +6,8 @@ namespace CoenJacobs\Mozart\Replace; +use Exception; + class ClassmapReplacer extends BaseReplacer { @@ -15,16 +17,13 @@ class ClassmapReplacer extends BaseReplacer /** @var string */ public $classmap_prefix; - /** - * @param false|string $contents - */ - public function replace($contents): string + public function replace(string $contents): string { - if (empty($contents) || false === $contents) { + if (empty($contents)) { return ''; } - return preg_replace_callback( + $replaced = preg_replace_callback( " / # Start the pattern namespace\s+[a-zA-Z0-9_\x7f-\xff\\\\]+[;{\s\n]{1}.*?(?=namespace|$) @@ -39,7 +38,7 @@ public function replace($contents): string (?:{|extends|implements|\n) # Class declaration can be followed by {, extends, # implements, or a new line /sx", // # dot matches newline, ignore whitespace in regex. - function ($matches) use ($contents) { + function ($matches) { // If we're inside a namespace other than the global namesspace, just return. if (preg_match('/^namespace\s+[a-zA-Z0-9_\x7f-\xff\\\\]+[;{\s\n]{1}.*/', $matches[0])) { @@ -53,9 +52,15 @@ function ($matches) use ($contents) { }, $contents ); + + if (empty($replaced)) { + throw new Exception('Failed to replace contents of the file.'); + } + + return $replaced; } - public function saveReplacedClass($classname, string $replacedName): void + public function saveReplacedClass(string $classname, string $replacedName): void { $this->replacedClasses[ $classname ] = $replacedName; } diff --git a/src/Replace/NamespaceReplacer.php b/src/Replace/NamespaceReplacer.php index 680fb413..b348fb24 100644 --- a/src/Replace/NamespaceReplacer.php +++ b/src/Replace/NamespaceReplacer.php @@ -2,6 +2,8 @@ namespace CoenJacobs\Mozart\Replace; +use Exception; + class NamespaceReplacer extends BaseReplacer { /** @@ -15,12 +17,12 @@ class NamespaceReplacer extends BaseReplacer * @param string $contents The text to make replacements in. * @param null $file Only used in ClassmapReplacer (for recording which files were changed). */ - public function replace($contents, $file = null): string + public function replace(string $contents, string $file = null): string { $searchNamespace = preg_quote($this->autoloader->getSearchNamespace(), '/'); $dependencyNamespace = preg_quote($this->dep_namespace, '/'); - return preg_replace_callback( + $replaced = preg_replace_callback( " / # Start the pattern ([^a-zA-Z0-9_\x7f-\xff]) # Match the non-class character before the namespace @@ -37,5 +39,11 @@ function ($matches) { }, $contents ); + + if (empty($replaced)) { + throw new Exception('Failed to replace contents of the file.'); + } + + return $replaced; } } diff --git a/src/Replace/Replacer.php b/src/Replace/Replacer.php index 33b1a150..907bdf9e 100644 --- a/src/Replace/Replacer.php +++ b/src/Replace/Replacer.php @@ -6,6 +6,6 @@ interface Replacer { - public function setAutoloader(Autoloader $autoloader); - public function replace($contents); + public function setAutoloader(Autoloader $autoloader): void; + public function replace(string $contents): string; } diff --git a/src/Replacer.php b/src/Replacer.php index bc2668b2..c092bcf9 100644 --- a/src/Replacer.php +++ b/src/Replacer.php @@ -9,6 +9,7 @@ use CoenJacobs\Mozart\Config\Package; use CoenJacobs\Mozart\Replace\ClassmapReplacer; use CoenJacobs\Mozart\Replace\NamespaceReplacer; +use Exception; use League\Flysystem\Local\LocalFilesystemAdapter; use League\Flysystem\UnableToReadFile; use League\Flysystem\Filesystem; @@ -25,7 +26,7 @@ class Replacer /** @var Mozart */ protected $config; - /** @var array */ + /** @var array */ protected $replacedClasses = []; /** @var Filesystem */ @@ -48,7 +49,7 @@ public function __construct(string $workingDir, Mozart $config) /** * @param Package[] $packages */ - public function replacePackages($packages): void + public function replacePackages(array $packages): void { foreach ($packages as $package) { $this->replacePackages($package->getDependencies()); @@ -141,10 +142,6 @@ public function replaceParentClassesInDirectory(string $directory): void continue; } - if (!$contents) { - continue; - } - foreach ($replacedClasses as $original => $replacement) { $contents = preg_replace_callback( '/(.*)([^a-zA-Z0-9_\x7f-\xff])'. $original . '([^a-zA-Z0-9_\x7f-\xff])/U', @@ -156,10 +153,10 @@ function ($matches) use ($replacement) { }, $contents ); - } - if (empty($contents)) { - continue; + if (empty($contents)) { + throw new Exception('Failed to replace parent classes in directory.'); + } } $this->filesystem->write($targetFile, $contents); From eac01ed2af9c3cad614010260c9a80458ddb811d Mon Sep 17 00:00:00 2001 From: Coen Jacobs Date: Thu, 12 Sep 2024 15:56:41 +0200 Subject: [PATCH 03/24] Bump PHP and Composer versions to latest stables --- Dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index 06ec0fdb..175e1e3d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ -FROM composer:2.7.7 -FROM php:8.3.9-cli-alpine AS base +FROM composer:2.7.9 +FROM php:8.3.11-cli-alpine AS base FROM base AS builder RUN apk update && apk add git From 7bc393e259a6897c4b5b9afc4110f35e10854734 Mon Sep 17 00:00:00 2001 From: Coen Jacobs Date: Thu, 12 Sep 2024 17:42:12 +0200 Subject: [PATCH 04/24] Installed phpmd and basic configuration file --- composer.json | 3 ++- phpmd.xml.dist | 16 ++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) create mode 100644 phpmd.xml.dist diff --git a/composer.json b/composer.json index 05f06aa5..6f0af7e6 100644 --- a/composer.json +++ b/composer.json @@ -40,7 +40,8 @@ "symfony/console": "^5.4", "symfony/finder": "^5.4", "dealerdirect/phpcodesniffer-composer-installer": "^1.0", - "phpcompatibility/php-compatibility": "dev-develop" + "phpcompatibility/php-compatibility": "dev-develop", + "phpmd/phpmd": "^2.15" }, "scripts": { "test": [ diff --git a/phpmd.xml.dist b/phpmd.xml.dist new file mode 100644 index 00000000..185b7f28 --- /dev/null +++ b/phpmd.xml.dist @@ -0,0 +1,16 @@ + + + + + + + + + + From 45f76f578cac687f06817f6eb1f00627429cae75 Mon Sep 17 00:00:00 2001 From: Coen Jacobs Date: Thu, 12 Sep 2024 17:42:32 +0200 Subject: [PATCH 05/24] Fixed all code smells in main replacer class --- src/FilesHandler.php | 50 ++++++++++++++++++++ src/Replacer.php | 108 ++++++++++++++++++++----------------------- 2 files changed, 99 insertions(+), 59 deletions(-) create mode 100644 src/FilesHandler.php diff --git a/src/FilesHandler.php b/src/FilesHandler.php new file mode 100644 index 00000000..a1d21b2e --- /dev/null +++ b/src/FilesHandler.php @@ -0,0 +1,50 @@ +config = $config; + + $adapter = new LocalFilesystemAdapter( + $this->config->getWorkingDir() + ); + + // The FilesystemOperator + $this->filesystem = new Filesystem($adapter); + } + + public function readFile(string $path): string + { + try { + $contents = $this->filesystem->read($path); + } catch (UnableToReadFile $e) { + $contents = ''; + } + + return $contents; + } + + public function writeFile(string $path, string $contents): void + { + $this->filesystem->write($path, $contents); + } + + public function getFilesFromPath(string $path): Iterator + { + $finder = new Finder(); + return $finder->files()->in($path)->getIterator(); + } +} diff --git a/src/Replacer.php b/src/Replacer.php index c092bcf9..2da61921 100644 --- a/src/Replacer.php +++ b/src/Replacer.php @@ -9,11 +9,8 @@ use CoenJacobs\Mozart\Config\Package; use CoenJacobs\Mozart\Replace\ClassmapReplacer; use CoenJacobs\Mozart\Replace\NamespaceReplacer; +use CoenJacobs\Mozart\Replace\Replacer as ReplacerInterface; use Exception; -use League\Flysystem\Local\LocalFilesystemAdapter; -use League\Flysystem\UnableToReadFile; -use League\Flysystem\Filesystem; -use Symfony\Component\Finder\Finder; class Replacer { @@ -29,21 +26,15 @@ class Replacer /** @var array */ protected $replacedClasses = []; - /** @var Filesystem */ - protected $filesystem; + /** @var FilesHandler */ + protected $files; public function __construct(string $workingDir, Mozart $config) { $this->workingDir = $workingDir; $this->config = $config; $this->targetDir = $this->config->getDepDirectory(); - - $adapter = new LocalFilesystemAdapter( - $this->workingDir - ); - - // The FilesystemOperator - $this->filesystem = new Filesystem($adapter); + $this->files = new FilesHandler($config); } /** @@ -67,32 +58,35 @@ public function replacePackage(Package $package): void public function replaceInFile(string $targetFile, Autoloader $autoloader): void { $targetFile = str_replace($this->workingDir, '', $targetFile); - try { - $contents = $this->filesystem->read($targetFile); - } catch (UnableToReadFile $e) { - return; - } + $contents = $this->files->readFile($targetFile); if (!$contents) { return; } - if ($autoloader instanceof NamespaceAutoloader) { - $replacer = new NamespaceReplacer(); - $replacer->dep_namespace = $this->config->getDependencyNamespace(); - } else { - $replacer = new ClassmapReplacer(); - $replacer->classmap_prefix = $this->config->getClassmapPrefix(); - } - - $replacer->setAutoloader($autoloader); + $replacer = $this->getReplacerByAutoloader($autoloader); $contents = $replacer->replace($contents); if ($replacer instanceof ClassmapReplacer) { $this->replacedClasses = array_merge($this->replacedClasses, $replacer->replacedClasses); } - $this->filesystem->write($targetFile, $contents); + $this->files->writeFile($targetFile, $contents); + } + + public function getReplacerByAutoloader(Autoloader $autoloader): ReplacerInterface + { + if ($autoloader instanceof NamespaceAutoloader) { + $replacer = new NamespaceReplacer(); + $replacer->dep_namespace = $this->config->getDependencyNamespace(); + $replacer->setAutoloader($autoloader); + return $replacer; + } + + $replacer = new ClassmapReplacer(); + $replacer->classmap_prefix = $this->config->getClassmapPrefix(); + $replacer->setAutoloader($autoloader); + return $replacer; } public function replacePackageByAutoloader(Package $package, Autoloader $autoloader): void @@ -102,15 +96,14 @@ public function replacePackageByAutoloader(Package $package, Autoloader $autoloa } if ($autoloader instanceof NamespaceAutoloader) { - $source_path = $this->workingDir . $this->targetDir + $sourcePath = $this->workingDir . $this->targetDir . str_replace('\\', DIRECTORY_SEPARATOR, $autoloader->getNamespace()); - $this->replaceInDirectory($autoloader, $source_path); + $this->replaceInDirectory($autoloader, $sourcePath); } elseif ($autoloader instanceof Classmap) { - $finder = new Finder(); - $source_path = $this->workingDir . $this->config->getClassmapDirectory() . $package->getName(); - $finder->files()->in($source_path); + $sourcePath = $this->workingDir . $this->config->getClassmapDirectory() . $package->getName(); + $files = $this->files->getFilesFromPath($sourcePath); - foreach ($finder as $foundFile) { + foreach ($files as $foundFile) { $targetFile = $foundFile->getRealPath(); if ('.php' == substr($targetFile, -4, 4)) { @@ -127,26 +120,21 @@ public function replaceParentClassesInDirectory(string $directory): void } $directory = trim($directory, '//'); - $finder = new Finder(); - $finder->files()->in($directory); + $files = $this->files->getFilesFromPath($directory); $replacedClasses = $this->replacedClasses; - foreach ($finder as $file) { + foreach ($files as $file) { $targetFile = $file->getPathName(); if ('.php' == substr($targetFile, -4, 4)) { - try { - $contents = $this->filesystem->read($targetFile); - } catch (UnableToReadFile $e) { - continue; - } + $contents = $this->files->readFile($targetFile); foreach ($replacedClasses as $original => $replacement) { $contents = preg_replace_callback( '/(.*)([^a-zA-Z0-9_\x7f-\xff])'. $original . '([^a-zA-Z0-9_\x7f-\xff])/U', function ($matches) use ($replacement) { - if (preg_match('/(include|require)/', $matches[0], $output_array)) { + if (preg_match('/(include|require)/', $matches[0])) { return $matches[0]; } return $matches[1] . $matches[2] . $replacement . $matches[3]; @@ -159,17 +147,16 @@ function ($matches) use ($replacement) { } } - $this->filesystem->write($targetFile, $contents); + $this->files->writeFile($targetFile, $contents); } } } public function replaceInDirectory(NamespaceAutoloader $autoloader, string $directory): void { - $finder = new Finder(); - $finder->files()->in($directory); + $files = $this->files->getFilesFromPath($directory); - foreach ($finder as $file) { + foreach ($files as $file) { $targetFile = $file->getPathName(); if ('.php' == substr($targetFile, -4, 4)) { @@ -198,21 +185,24 @@ public function replaceParentPackage(Package $package, Package $parent): void if ($autoloader instanceof NamespaceAutoloader) { $this->replaceInDirectory($autoloader, $directory); - } else { - $directory = str_replace($this->workingDir, '', $directory); - $this->replaceParentClassesInDirectory($directory); + return; } - } else { - $directory = $this->workingDir . - $this->config->getClassmapDirectory() . $parent->getName(); - if ($autoloader instanceof NamespaceAutoloader) { - $this->replaceInDirectory($autoloader, $directory); - } else { - $directory = str_replace($this->workingDir, '', $directory); - $this->replaceParentClassesInDirectory($directory); - } + $directory = str_replace($this->workingDir, '', $directory); + $this->replaceParentClassesInDirectory($directory); + return; + } + + $directory = $this->workingDir . + $this->config->getClassmapDirectory() . $parent->getName(); + + if ($autoloader instanceof NamespaceAutoloader) { + $this->replaceInDirectory($autoloader, $directory); + return; } + + $directory = str_replace($this->workingDir, '', $directory); + $this->replaceParentClassesInDirectory($directory); } } } From 707f808eb177a477be1ad41394b6d00073de3298 Mon Sep 17 00:00:00 2001 From: Coen Jacobs Date: Thu, 12 Sep 2024 17:47:55 +0200 Subject: [PATCH 06/24] Change boolean load dependencies flag to separate method --- src/Console/Commands/Compose.php | 2 +- src/PackageFactory.php | 11 ++--------- src/PackageFinder.php | 4 +++- tests/Config/ConfigMapperTest.php | 1 + tests/MoverTest.php | 1 + 5 files changed, 8 insertions(+), 11 deletions(-) diff --git a/src/Console/Commands/Compose.php b/src/Console/Commands/Compose.php index 2a9b762d..c74a82d1 100644 --- a/src/Console/Commands/Compose.php +++ b/src/Console/Commands/Compose.php @@ -48,7 +48,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int $composerFile = $this->workingDir . DIRECTORY_SEPARATOR. 'composer.json'; try { - $package = PackageFactory::createPackage($composerFile, null, false); + $package = PackageFactory::createPackage($composerFile); } catch (Exception $e) { $output->write('Unable to read the composer.json file'); return 1; diff --git a/src/PackageFactory.php b/src/PackageFactory.php index da67d61e..fcf4cb59 100644 --- a/src/PackageFactory.php +++ b/src/PackageFactory.php @@ -10,11 +10,8 @@ class PackageFactory /** @var array */ public static array $cache = []; - public static function createPackage( - string $path, - stdClass $overrideAutoload = null, - bool $loadDependencies = true - ): Package { + public static function createPackage(string $path, stdClass $overrideAutoload = null): Package + { if (isset(self::$cache[$path])) { return self::$cache[$path]; } @@ -25,10 +22,6 @@ public static function createPackage( $package->setAutoload($overrideAutoload); } - if ($loadDependencies) { - $package->loadDependencies(); - } - self::$cache[$path] = $package; return $package; } diff --git a/src/PackageFinder.php b/src/PackageFinder.php index 9f162c63..d0470fa3 100644 --- a/src/PackageFinder.php +++ b/src/PackageFinder.php @@ -53,7 +53,9 @@ public function getPackageBySlug(string $slug): ?Package $autoloaders = $override_autoload->$slug; } - return PackageFactory::createPackage($packageDir . 'composer.json', $autoloaders, true); + $package = PackageFactory::createPackage($packageDir . 'composer.json', $autoloaders); + $package->loadDependencies(); + return $package; } /** diff --git a/tests/Config/ConfigMapperTest.php b/tests/Config/ConfigMapperTest.php index 42e1ed7a..433ae202 100644 --- a/tests/Config/ConfigMapperTest.php +++ b/tests/Config/ConfigMapperTest.php @@ -16,6 +16,7 @@ class ConfigMapperTest extends TestCase public function it_creates_a_valid_config_object_based_on_composer_file() { $package = PackageFactory::createPackage(__DIR__ . '/config-mapper-test.json'); + $package->loadDependencies(); $this->assertInstanceOf(Package::class, $package); $this->assertInstanceOf(Mozart::class, $package->getExtra()->getMozart()); $this->assertCount(4, $package->autoload->getAutoloaders()); diff --git a/tests/MoverTest.php b/tests/MoverTest.php index 8945f49e..d5de5d94 100644 --- a/tests/MoverTest.php +++ b/tests/MoverTest.php @@ -138,6 +138,7 @@ public function it_deletes_subdirs_for_packages_about_to_be_moved(): void $overrideAutoload = $overrideAutoload->getByKey( $packageString ); } $parsedPackage = PackageFactory::createPackage($testDummyComposerPath, $overrideAutoload); + $parsedPackage->loadDependencies(); $packages[] = $parsedPackage; } From 716cb13626016653f0baa8bdb7d8509795051f10 Mon Sep 17 00:00:00 2001 From: Coen Jacobs Date: Thu, 12 Sep 2024 17:54:28 +0200 Subject: [PATCH 07/24] CamelCasing all the things --- src/PackageFinder.php | 6 +++--- src/Replace/ClassmapReplacer.php | 4 ++-- src/Replace/NamespaceReplacer.php | 6 +++--- src/Replacer.php | 4 ++-- tests/replacers/ClassMapReplacerTest.php | 22 +++++++++++----------- tests/replacers/NamespaceReplacerTest.php | 2 +- 6 files changed, 22 insertions(+), 22 deletions(-) diff --git a/src/PackageFinder.php b/src/PackageFinder.php index d0470fa3..df5b210a 100644 --- a/src/PackageFinder.php +++ b/src/PackageFinder.php @@ -48,9 +48,9 @@ public function getPackageBySlug(string $slug): ?Package } $autoloaders = null; - $override_autoload = $this->config->getOverrideAutoload(); - if ($override_autoload !== false && isset($override_autoload->$slug)) { - $autoloaders = $override_autoload->$slug; + $overrideAutoload = $this->config->getOverrideAutoload(); + if ($overrideAutoload !== false && isset($overrideAutoload->$slug)) { + $autoloaders = $overrideAutoload->$slug; } $package = PackageFactory::createPackage($packageDir . 'composer.json', $autoloaders); diff --git a/src/Replace/ClassmapReplacer.php b/src/Replace/ClassmapReplacer.php index 39b4fa52..803467fd 100644 --- a/src/Replace/ClassmapReplacer.php +++ b/src/Replace/ClassmapReplacer.php @@ -15,7 +15,7 @@ class ClassmapReplacer extends BaseReplacer public $replacedClasses = []; /** @var string */ - public $classmap_prefix; + public $classmapPrefix; public function replace(string $contents): string { @@ -46,7 +46,7 @@ function ($matches) { } // The prepended class name. - $replace = $this->classmap_prefix . $matches[1]; + $replace = $this->classmapPrefix . $matches[1]; $this->saveReplacedClass($matches[1], $replace); return str_replace($matches[1], $replace, $matches[0]); }, diff --git a/src/Replace/NamespaceReplacer.php b/src/Replace/NamespaceReplacer.php index b348fb24..9c324c5e 100644 --- a/src/Replace/NamespaceReplacer.php +++ b/src/Replace/NamespaceReplacer.php @@ -11,7 +11,7 @@ class NamespaceReplacer extends BaseReplacer * * @var string "My\Mozart\Prefix". */ - public $dep_namespace = ''; + public $depNamespace = ''; /** * @param string $contents The text to make replacements in. @@ -20,7 +20,7 @@ class NamespaceReplacer extends BaseReplacer public function replace(string $contents, string $file = null): string { $searchNamespace = preg_quote($this->autoloader->getSearchNamespace(), '/'); - $dependencyNamespace = preg_quote($this->dep_namespace, '/'); + $dependencyNamespace = preg_quote($this->depNamespace, '/'); $replaced = preg_replace_callback( " @@ -35,7 +35,7 @@ public function replace(string $contents, string $file = null): string ) # End the namespace matcher /Ux", function ($matches) { - return $matches[1] . $this->dep_namespace . $matches[2]; + return $matches[1] . $this->depNamespace . $matches[2]; }, $contents ); diff --git a/src/Replacer.php b/src/Replacer.php index 2da61921..8cc76433 100644 --- a/src/Replacer.php +++ b/src/Replacer.php @@ -78,13 +78,13 @@ public function getReplacerByAutoloader(Autoloader $autoloader): ReplacerInterfa { if ($autoloader instanceof NamespaceAutoloader) { $replacer = new NamespaceReplacer(); - $replacer->dep_namespace = $this->config->getDependencyNamespace(); + $replacer->depNamespace = $this->config->getDependencyNamespace(); $replacer->setAutoloader($autoloader); return $replacer; } $replacer = new ClassmapReplacer(); - $replacer->classmap_prefix = $this->config->getClassmapPrefix(); + $replacer->classmapPrefix = $this->config->getClassmapPrefix(); $replacer->setAutoloader($autoloader); return $replacer; } diff --git a/tests/replacers/ClassMapReplacerTest.php b/tests/replacers/ClassMapReplacerTest.php index 10b10ce8..6f08af06 100644 --- a/tests/replacers/ClassMapReplacerTest.php +++ b/tests/replacers/ClassMapReplacerTest.php @@ -13,7 +13,7 @@ public function it_replaces_class_declarations(): void { $contents = 'class Hello_World {'; $replacer = new ClassmapReplacer(); - $replacer->classmap_prefix = 'Mozart_'; + $replacer->classmapPrefix = 'Mozart_'; $contents = $replacer->replace($contents); $this->assertEquals('class Mozart_Hello_World {', $contents); } @@ -24,7 +24,7 @@ public function it_replaces_abstract_class_declarations(): void { $contents = 'abstract class Hello_World {'; $replacer = new ClassmapReplacer(); - $replacer->classmap_prefix = 'Mozart_'; + $replacer->classmapPrefix = 'Mozart_'; $contents = $replacer->replace($contents); $this->assertEquals('abstract class Mozart_Hello_World {', $contents); } @@ -35,7 +35,7 @@ public function it_replaces_interface_class_declarations(): void { $contents = 'interface Hello_World {'; $replacer = new ClassmapReplacer(); - $replacer->classmap_prefix = 'Mozart_'; + $replacer->classmapPrefix = 'Mozart_'; $contents = $replacer->replace($contents); $this->assertEquals('interface Mozart_Hello_World {', $contents); } @@ -46,7 +46,7 @@ public function it_replaces_class_declarations_that_extend_other_classes(): void { $contents = 'class Hello_World extends Bye_World {'; $replacer = new ClassmapReplacer(); - $replacer->classmap_prefix = 'Mozart_'; + $replacer->classmapPrefix = 'Mozart_'; $contents = $replacer->replace($contents); $this->assertEquals('class Mozart_Hello_World extends Bye_World {', $contents); } @@ -57,7 +57,7 @@ public function it_replaces_class_declarations_that_implement_interfaces(): void { $contents = 'class Hello_World implements Bye_World {'; $replacer = new ClassmapReplacer(); - $replacer->classmap_prefix = 'Mozart_'; + $replacer->classmapPrefix = 'Mozart_'; $contents = $replacer->replace($contents); $this->assertEquals('class Mozart_Hello_World implements Bye_World {', $contents); } @@ -68,7 +68,7 @@ public function it_stores_replaced_class_names(): void { $contents = 'class Hello_World {'; $replacer = new ClassmapReplacer(); - $replacer->classmap_prefix = 'Mozart_'; + $replacer->classmapPrefix = 'Mozart_'; $replacer->replace($contents); $this->assertArrayHasKey('Hello_World', $replacer->replacedClasses); } @@ -79,7 +79,7 @@ public function it_replaces_class_declarations_psr2(): void { $contents = "class Hello_World\n{"; $replacer = new ClassmapReplacer(); - $replacer->classmap_prefix = 'Mozart_'; + $replacer->classmapPrefix = 'Mozart_'; $contents = $replacer->replace($contents); $this->assertEquals("class Mozart_Hello_World\n{", $contents); } @@ -94,7 +94,7 @@ public function it_replaces_class(): void { $contents = "class Hello_World"; $replacer = new ClassmapReplacer(); - $replacer->classmap_prefix = 'Mozart_'; + $replacer->classmapPrefix = 'Mozart_'; $contents = $replacer->replace($contents); $this->assertEquals("class Mozart_Hello_World", $contents); } @@ -114,7 +114,7 @@ public function it_does_not_replace_inside_namespace_multiline(): void class Hello_World "; $replacer = new ClassmapReplacer(); - $replacer->classmap_prefix = 'Mozart_'; + $replacer->classmapPrefix = 'Mozart_'; $result = $replacer->replace($input); $this->assertEquals($input, $result); @@ -131,7 +131,7 @@ public function it_does_not_replace_inside_namespace_singleline(): void { $input = "namespace Mozart; class Hello_World"; $replacer = new ClassmapReplacer(); - $replacer->classmap_prefix = 'Mozart_'; + $replacer->classmapPrefix = 'Mozart_'; $result = $replacer->replace($input); $this->assertEquals($input, $result); @@ -158,7 +158,7 @@ class B_Class { } "; $replacer = new ClassmapReplacer(); - $replacer->classmap_prefix = 'Mozart_'; + $replacer->classmapPrefix = 'Mozart_'; $result = $replacer->replace($input); $this->assertStringNotContainsString('Mozart_A_Class', $result); diff --git a/tests/replacers/NamespaceReplacerTest.php b/tests/replacers/NamespaceReplacerTest.php index b0651bc7..2fa41651 100644 --- a/tests/replacers/NamespaceReplacerTest.php +++ b/tests/replacers/NamespaceReplacerTest.php @@ -27,7 +27,7 @@ protected static function createReplacer(string $namespace, string $prefix = sel $autoloader->namespace = $namespace; $replacer = new NamespaceReplacer(); $replacer->setAutoloader($autoloader); - $replacer->dep_namespace = $prefix; + $replacer->depNamespace = $prefix; return $replacer; } From f40546a2862b7f5aa9a0d1410c0b75632a0e566b Mon Sep 17 00:00:00 2001 From: Coen Jacobs Date: Thu, 12 Sep 2024 17:58:18 +0200 Subject: [PATCH 08/24] Dumbed down if else constructions in autoloader classes --- src/Composer/Autoload/NamespaceAutoloader.php | 5 +++-- src/Config/Classmap.php | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/Composer/Autoload/NamespaceAutoloader.php b/src/Composer/Autoload/NamespaceAutoloader.php index 62ef6328..314bf179 100644 --- a/src/Composer/Autoload/NamespaceAutoloader.php +++ b/src/Composer/Autoload/NamespaceAutoloader.php @@ -27,9 +27,10 @@ public function processConfig($autoloadConfig): void foreach ($autoloadConfig as $path) { array_push($this->paths, $path); } - } else { - array_push($this->paths, $autoloadConfig); + + return; } + array_push($this->paths, $autoloadConfig); } public function getNamespace(): string diff --git a/src/Config/Classmap.php b/src/Config/Classmap.php index c53529ed..5077e732 100644 --- a/src/Config/Classmap.php +++ b/src/Config/Classmap.php @@ -21,9 +21,10 @@ public function processConfig($autoloadConfig): void foreach ($autoloadConfig as $value) { if ('.php' == substr($value, -4, 4)) { array_push($this->files, $value); - } else { - array_push($this->paths, $value); + continue; } + + array_push($this->paths, $value); } } From b8ebe6838197498312572432b0901724a1b0f3ca Mon Sep 17 00:00:00 2001 From: Coen Jacobs Date: Fri, 13 Sep 2024 15:13:26 +0200 Subject: [PATCH 09/24] Reduce Mover complexity by abstracting file handling to FileHandler --- src/FilesHandler.php | 26 ++++++++++++++ src/Mover.php | 80 ++++++++++++++++---------------------------- tests/MoverTest.php | 1 + 3 files changed, 56 insertions(+), 51 deletions(-) diff --git a/src/FilesHandler.php b/src/FilesHandler.php index a1d21b2e..b8ffda58 100644 --- a/src/FilesHandler.php +++ b/src/FilesHandler.php @@ -47,4 +47,30 @@ public function getFilesFromPath(string $path): Iterator $finder = new Finder(); return $finder->files()->in($path)->getIterator(); } + + public function getFile(string $path, string $fileName): Iterator + { + $finder = new Finder(); + return $finder->files()->name($fileName)->in($path)->getIterator(); + } + + public function createDirectory(string $path): void + { + $this->filesystem->createDirectory($path); + } + + public function deleteDirectory(string $path): void + { + $this->filesystem->deleteDirectory($path); + } + + public function isDirectoryEmpty(string $path): bool + { + return count($this->filesystem->listContents($path, true)->toArray()) === 0; + } + + public function copyFile(string $origin, string $destination): void + { + $this->filesystem->copy($origin, $destination); + } } diff --git a/src/Mover.php b/src/Mover.php index 8b676be7..18f976d1 100644 --- a/src/Mover.php +++ b/src/Mover.php @@ -9,9 +9,6 @@ use CoenJacobs\Mozart\Config\Package; use CoenJacobs\Mozart\Config\Psr0; use CoenJacobs\Mozart\Config\Psr4; -use League\Flysystem\Local\LocalFilesystemAdapter; -use League\Flysystem\Filesystem; -use Symfony\Component\Finder\Finder; use Symfony\Component\Finder\SplFileInfo; class Mover @@ -25,8 +22,7 @@ class Mover /** @var Mozart */ protected $config; - /** @var Filesystem */ - protected $filesystem; + protected FilesHandler $files; /** @var array */ protected $movedPackages = []; @@ -36,13 +32,7 @@ public function __construct(string $workingDir, Mozart $config) $this->config = $config; $this->workingDir = $workingDir; $this->targetDir = $this->config->getDepDirectory(); - - $adapter = new LocalFilesystemAdapter( - $this->workingDir - ); - - // The FilesystemOperator - $this->filesystem = new Filesystem($adapter); + $this->files = new FilesHandler($config); } /** @@ -52,8 +42,8 @@ public function __construct(string $workingDir, Mozart $config) */ public function deleteTargetDirs($packages): void { - $this->filesystem->createDirectory($this->config->getDepDirectory()); - $this->filesystem->createDirectory($this->config->getClassmapDirectory()); + $this->files->createDirectory($this->config->getDepDirectory()); + $this->files->createDirectory($this->config->getClassmapDirectory()); foreach ($packages as $package) { $this->deleteDepTargetDirs($package); @@ -75,12 +65,12 @@ private function deleteDepTargetDirs(Package $package): void case Psr4::class: $outputDir = $this->config->getDepDirectory() . $packageAutoloader->getSearchNamespace(); $outputDir = str_replace('\\', DIRECTORY_SEPARATOR, $outputDir); - $this->filesystem->deleteDirectory($outputDir); + $this->files->deleteDirectory($outputDir); break; case Classmap::class: $outputDir = $this->config->getClassmapDirectory() . $package->getName(); $outputDir = str_replace('\\', DIRECTORY_SEPARATOR, $outputDir); - $this->filesystem->deleteDirectory($outputDir); + $this->files->deleteDirectory($outputDir); break; } } @@ -92,12 +82,12 @@ private function deleteDepTargetDirs(Package $package): void public function deleteEmptyDirs(): void { - if (count($this->filesystem->listContents($this->config->getDepDirectory(), true)->toArray()) === 0) { - $this->filesystem->deleteDirectory($this->config->getDepDirectory()); + if ($this->files->isDirectoryEmpty($this->config->getDepDirectory())) { + $this->files->deleteDirectory($this->config->getDepDirectory()); } - if (count($this->filesystem->listContents($this->config->getClassmapDirectory(), true)->toArray()) === 0) { - $this->filesystem->deleteDirectory($this->config->getClassmapDirectory()); + if ($this->files->isDirectoryEmpty($this->config->getClassmapDirectory())) { + $this->files->deleteDirectory($this->config->getClassmapDirectory()); } } @@ -126,51 +116,45 @@ public function movePackage(Package $package): void foreach ($package->getAutoloaders() as $autoloader) { if ($autoloader instanceof NamespaceAutoloader) { - $finder = new Finder(); - foreach ($autoloader->paths as $path) { - $source_path = $this->workingDir . DIRECTORY_SEPARATOR . 'vendor' . DIRECTORY_SEPARATOR + $sourcePath = $this->workingDir . DIRECTORY_SEPARATOR . 'vendor' . DIRECTORY_SEPARATOR . $package->getName() . DIRECTORY_SEPARATOR . $path; - $source_path = str_replace('/', DIRECTORY_SEPARATOR, $source_path); + $sourcePath = str_replace('/', DIRECTORY_SEPARATOR, $sourcePath); - $finder->files()->in($source_path); - foreach ($finder as $file) { + $files = $this->files->getFilesFromPath($sourcePath); + foreach ($files as $file) { $this->moveFile($package, $autoloader, $file, $path); } } } elseif ($autoloader instanceof Classmap) { - $finder = new Finder(); - - $files_to_move = array(); + $filesToMove = array(); foreach ($autoloader->files as $file) { - $source_path = $this->workingDir . DIRECTORY_SEPARATOR . 'vendor' + $sourcePath = $this->workingDir . DIRECTORY_SEPARATOR . 'vendor' . DIRECTORY_SEPARATOR . $package->getName(); - $finder->files()->name($file)->in($source_path); - foreach ($finder as $foundFile) { + $files = $this->files->getFile($sourcePath, $file); + + foreach ($files as $foundFile) { $filePath = $foundFile->getRealPath(); - $files_to_move[ $filePath ] = $foundFile; + $filesToMove[ $filePath ] = $foundFile; } } - $finder = new Finder(); - foreach ($autoloader->paths as $path) { - $source_path = $this->workingDir . DIRECTORY_SEPARATOR . 'vendor' + $sourcePath = $this->workingDir . DIRECTORY_SEPARATOR . 'vendor' . DIRECTORY_SEPARATOR . $package->getName() . DIRECTORY_SEPARATOR . $path; - $finder->files()->in($source_path); - - foreach ($finder as $foundFile) { + $files = $this->files->getFilesFromPath($sourcePath); + foreach ($files as $foundFile) { $filePath = $foundFile->getRealPath(); - $files_to_move[ $filePath ] = $foundFile; + $filesToMove[ $filePath ] = $foundFile; } } - foreach ($files_to_move as $foundFile) { + foreach ($filesToMove as $foundFile) { $this->moveFile($package, $autoloader, $foundFile); } } @@ -207,7 +191,7 @@ public function moveFile(Package $package, Autoloader $autoloader, SplFileInfo $ $targetFile = str_replace($packageVendorPath, DIRECTORY_SEPARATOR, $targetFile); } - $this->filesystem->copy( + $this->files->copyFile( str_replace($this->workingDir, '', $file->getPathname()), $targetFile ); @@ -228,20 +212,14 @@ protected function deletePackageVendorDirectories(): void continue; } - $this->filesystem->deleteDirectory($packageDir); + $this->files->deleteDirectory($packageDir); //Delete parent directory too if it became empty //(because that package was the only one from that vendor) $parentDir = dirname($packageDir); - if ($this->dirIsEmpty($parentDir)) { - $this->filesystem->deleteDirectory($parentDir); + if ($this->files->isDirectoryEmpty($parentDir)) { + $this->files->deleteDirectory($parentDir); } } } - - private function dirIsEmpty(string $dir): bool - { - $di = new \RecursiveDirectoryIterator($dir, \FilesystemIterator::SKIP_DOTS); - return iterator_count($di) === 0; - } } diff --git a/tests/MoverTest.php b/tests/MoverTest.php index d5de5d94..af4ba47f 100644 --- a/tests/MoverTest.php +++ b/tests/MoverTest.php @@ -55,6 +55,7 @@ public function setUp(): void ); $this->config = Mozart::loadFromString( json_encode($configArgs) ); + $this->config->setWorkingDir($this->testsWorkingDir); } /** From 8974877ec4793564e748449f442bcda0e7eaa796 Mon Sep 17 00:00:00 2001 From: Coen Jacobs Date: Fri, 13 Sep 2024 15:19:35 +0200 Subject: [PATCH 10/24] Remove else case from moveFile method to reduce complexity --- src/Mover.php | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/src/Mover.php b/src/Mover.php index 18f976d1..1bf90337 100644 --- a/src/Mover.php +++ b/src/Mover.php @@ -180,23 +180,28 @@ public function moveFile(Package $package, Autoloader $autoloader, SplFileInfo $ . DIRECTORY_SEPARATOR . $path; $packageVendorPath = str_replace('/', DIRECTORY_SEPARATOR, $packageVendorPath); $targetFile = str_replace($packageVendorPath, '', $targetFile); - } else { - $namespacePath = $package->getName(); - $replaceWith = $this->config->getClassmapDirectory() . $namespacePath; - $targetFile = str_replace($this->workingDir, $replaceWith, $file->getPathname()); - - $packageVendorPath = DIRECTORY_SEPARATOR . 'vendor' . DIRECTORY_SEPARATOR . $package->getName() - . DIRECTORY_SEPARATOR; - $packageVendorPath = str_replace('/', DIRECTORY_SEPARATOR, $packageVendorPath); - $targetFile = str_replace($packageVendorPath, DIRECTORY_SEPARATOR, $targetFile); + $this->copyFile($file, $targetFile); + return $targetFile; } + $namespacePath = $package->getName(); + $replaceWith = $this->config->getClassmapDirectory() . $namespacePath; + $targetFile = str_replace($this->workingDir, $replaceWith, $file->getPathname()); + + $packageVendorPath = DIRECTORY_SEPARATOR . 'vendor' . DIRECTORY_SEPARATOR . $package->getName() + . DIRECTORY_SEPARATOR; + $packageVendorPath = str_replace('/', DIRECTORY_SEPARATOR, $packageVendorPath); + $targetFile = str_replace($packageVendorPath, DIRECTORY_SEPARATOR, $targetFile); + $this->copyFile($file, $targetFile); + return $targetFile; + } + + protected function copyFile(SplFileInfo $file, string $targetFile): void + { $this->files->copyFile( str_replace($this->workingDir, '', $file->getPathname()), $targetFile ); - - return $targetFile; } /** From 7f1a1404e54d4ec67f93a96f8d7c5cf7a6e8ecb7 Mon Sep 17 00:00:00 2001 From: Coen Jacobs Date: Mon, 16 Sep 2024 15:32:58 +0200 Subject: [PATCH 11/24] Setters for underscore case properties translated to snakeCase --- src/Config/Mozart.php | 63 ++++++++++++++++++++++++++++++------------- 1 file changed, 44 insertions(+), 19 deletions(-) diff --git a/src/Config/Mozart.php b/src/Config/Mozart.php index a07c5b5b..4367d26e 100644 --- a/src/Config/Mozart.php +++ b/src/Config/Mozart.php @@ -11,22 +11,42 @@ class Mozart { use ReadsConfig; - public string $dep_namespace; - public string $dep_directory; - public string $classmap_directory; - public string $classmap_prefix; + public string $depNamespace; + public string $depDirectory; + public string $classmapDir; + public string $classmapPrefix; /** @var string[] */ public array $packages = []; /** @var string[] */ - public array $excluded_packages = []; + public array $excludedPackages = []; - public OverrideAutoload $override_autoload; - public bool $delete_vendor_directories; + public OverrideAutoload $overrideAutoload; + public bool $deleteVendorDir = true; public string $workingDir = ''; + public function setDepNamespace(string $depNamespace): void + { + $this->depNamespace = $depNamespace; + } + + public function setDepDirectory(string $depDirectory): void + { + $this->depDirectory = $depDirectory; + } + + public function setClassmapDirectory(string $classmapDirectory): void + { + $this->classmapDir = $classmapDirectory; + } + + public function setClassmapPrefix(string $classmapPrefix): void + { + $this->classmapPrefix = $classmapPrefix; + } + /** * @return string[] */ @@ -44,21 +64,26 @@ public function setPackages(array $packages): void } /** - * @param string[] $excluded_packages + * @param string[] $excludedPackages */ - public function setExcludedPackages(array $excluded_packages): void + public function setExcludedPackages(array $excludedPackages): void { - $this->excluded_packages = $excluded_packages; + $this->excludedPackages = $excludedPackages; } public function setOverrideAutoload(stdClass $object): void { - $this->override_autoload = new OverrideAutoload($object); + $this->overrideAutoload = new OverrideAutoload($object); + } + + public function setDeleteVendorDir(bool $deleteVendorDir): void + { + $this->deleteVendorDir = $deleteVendorDir; } public function isValidMozartConfig(): bool { - $required = [ 'dep_namespace', 'dep_directory', 'classmap_directory', 'classmap_prefix' ]; + $required = [ 'depNamespace', 'depDirectory', 'classmapDir', 'classmapPrefix' ]; foreach ($required as $requiredProp) { if (empty($this->$requiredProp)) { @@ -80,22 +105,22 @@ public function isExcludedPackage(Package $package): bool */ public function getDepDirectory(): string { - return rtrim($this->dep_directory, DIRECTORY_SEPARATOR).DIRECTORY_SEPARATOR; + return rtrim($this->depDirectory, DIRECTORY_SEPARATOR).DIRECTORY_SEPARATOR; } public function getClassmapDirectory(): string { - return rtrim($this->classmap_directory, DIRECTORY_SEPARATOR).DIRECTORY_SEPARATOR; + return rtrim($this->classmapDir, DIRECTORY_SEPARATOR).DIRECTORY_SEPARATOR; } public function getDeleteVendorDirectories(): bool { - return $this->delete_vendor_directories; + return $this->deleteVendorDir; } public function getDependencyNamespace(): string { - $namespace = preg_replace("/\\\{2,}$/", "\\", $this->dep_namespace."\\"); + $namespace = preg_replace("/\\\{2,}$/", "\\", $this->depNamespace."\\"); if (empty($namespace)) { throw new Exception('Could not get target dependency namespace'); @@ -106,12 +131,12 @@ public function getDependencyNamespace(): string public function getClassmapPrefix(): string { - return $this->classmap_prefix; + return $this->classmapPrefix; } public function getOverrideAutoload(): OverrideAutoload { - return $this->override_autoload; + return $this->overrideAutoload; } /** @@ -119,7 +144,7 @@ public function getOverrideAutoload(): OverrideAutoload */ public function getExcludedPackages(): array { - return $this->excluded_packages; + return $this->excludedPackages; } public function setWorkingDir(string $workingDir): void From 26cc7d63d6fc9d868af548c5a5faec20240fe886 Mon Sep 17 00:00:00 2001 From: Coen Jacobs Date: Mon, 16 Sep 2024 15:57:57 +0200 Subject: [PATCH 12/24] Removed all static calls that shouldn't be static in the first place --- src/Config/Package.php | 3 +-- src/Config/ReadsConfig.php | 12 ++++++------ src/Console/Commands/Compose.php | 14 +++++++------- src/PackageFactory.php | 13 +++++++------ src/PackageFinder.php | 15 +++++---------- tests/Config/ConfigMapperTest.php | 7 +++++-- tests/MoverTest.php | 10 +++++++--- 7 files changed, 38 insertions(+), 36 deletions(-) diff --git a/src/Config/Package.php b/src/Config/Package.php index c466ee9f..68746edb 100644 --- a/src/Config/Package.php +++ b/src/Config/Package.php @@ -83,9 +83,8 @@ public function getDependencies(): array return $this->dependencies; } - public function loadDependencies(): void + public function loadDependencies(PackageFinder $finder): void { - $finder = PackageFinder::instance(); if ($this->isValidMozartConfig() && !empty($this->getExtra())) { $mozart = $this->getExtra()->getMozart(); diff --git a/src/Config/ReadsConfig.php b/src/Config/ReadsConfig.php index 4e7f3d30..22f7a83e 100644 --- a/src/Config/ReadsConfig.php +++ b/src/Config/ReadsConfig.php @@ -8,7 +8,7 @@ trait ReadsConfig { - public static function loadFromFile(string $filePath): self + public function loadFromFile(string $filePath): self { $fileContents = file_get_contents($filePath); @@ -16,13 +16,13 @@ public static function loadFromFile(string $filePath): self throw new Exception('Could not read config from provided file.'); } - return self::loadFromString($fileContents); + return $this->loadFromString($fileContents); } /** * @param array $config */ - public static function loadFromArray(array $config): self + public function loadFromArray(array $config): self { $encoded = json_encode($config); @@ -36,10 +36,10 @@ public static function loadFromArray(array $config): self throw new Exception('Could not read config from provided array.'); } - return self::loadFromStdClass($config); + return $this->loadFromStdClass($config); } - public static function loadFromStdClass(stdClass $config): self + public function loadFromStdClass(stdClass $config): self { $mapper = new JsonMapper(); $mapper->bEnforceMapType = false; @@ -52,7 +52,7 @@ public static function loadFromStdClass(stdClass $config): self return $object; } - public static function loadFromString(string $config): self + public function loadFromString(string $config): self { $config = json_decode($config); diff --git a/src/Console/Commands/Compose.php b/src/Console/Commands/Compose.php index c74a82d1..b17c1876 100644 --- a/src/Console/Commands/Compose.php +++ b/src/Console/Commands/Compose.php @@ -17,7 +17,6 @@ class Compose extends Command private Mover $mover; private Replacer $replacer; private Mozart $config; - private PackageFinder $finder; private string $workingDir; public function __construct() @@ -48,7 +47,8 @@ protected function execute(InputInterface $input, OutputInterface $output): int $composerFile = $this->workingDir . DIRECTORY_SEPARATOR. 'composer.json'; try { - $package = PackageFactory::createPackage($composerFile); + $factory = new PackageFactory(); + $package = $factory->createPackage($composerFile); } catch (Exception $e) { $output->write('Unable to read the composer.json file'); return 1; @@ -74,13 +74,13 @@ protected function execute(InputInterface $input, OutputInterface $output): int $require = $package->getRequire(); } - $this->finder = PackageFinder::instance(); - $this->finder->setConfig($this->config); + $finder = new PackageFinder(); + $finder->setConfig($this->config); - $package->loadDependencies(); + $package->loadDependencies($finder); - $packages = $this->finder->getPackagesBySlugs($require); - $packages = $this->finder->findPackages($packages); + $packages = $finder->getPackagesBySlugs($require); + $packages = $finder->findPackages($packages); $this->mover = new Mover($this->workingDir, $this->config); $this->replacer = new Replacer($this->workingDir, $this->config); diff --git a/src/PackageFactory.php b/src/PackageFactory.php index fcf4cb59..4591181a 100644 --- a/src/PackageFactory.php +++ b/src/PackageFactory.php @@ -8,21 +8,22 @@ class PackageFactory { /** @var array */ - public static array $cache = []; + public array $cache = []; - public static function createPackage(string $path, stdClass $overrideAutoload = null): Package + public function createPackage(string $path, stdClass $overrideAutoload = null): Package { - if (isset(self::$cache[$path])) { - return self::$cache[$path]; + if (isset($this->cache[$path])) { + return $this->cache[$path]; } - $package = Package::loadFromFile($path); + $package = new Package(); + $package = $package->loadFromFile($path); if (! empty($overrideAutoload)) { $package->setAutoload($overrideAutoload); } - self::$cache[$path] = $package; + $this->cache[$path] = $package; return $package; } } diff --git a/src/PackageFinder.php b/src/PackageFinder.php index df5b210a..73367ccf 100644 --- a/src/PackageFinder.php +++ b/src/PackageFinder.php @@ -9,16 +9,11 @@ class PackageFinder { private ?Mozart $config; + public PackageFactory $factory; - public static function instance(): self + public function __construct() { - static $instance; - - if (! is_object($instance) || ! $instance instanceof self) { - $instance = new self(); - } - - return $instance; + $this->factory = new PackageFactory(); } public function setConfig(Mozart $config): void @@ -53,8 +48,8 @@ public function getPackageBySlug(string $slug): ?Package $autoloaders = $overrideAutoload->$slug; } - $package = PackageFactory::createPackage($packageDir . 'composer.json', $autoloaders); - $package->loadDependencies(); + $package = $this->factory->createPackage($packageDir . 'composer.json', $autoloaders); + $package->loadDependencies($this); return $package; } diff --git a/tests/Config/ConfigMapperTest.php b/tests/Config/ConfigMapperTest.php index 433ae202..46d5553f 100644 --- a/tests/Config/ConfigMapperTest.php +++ b/tests/Config/ConfigMapperTest.php @@ -5,6 +5,7 @@ use CoenJacobs\Mozart\Config\Mozart; use CoenJacobs\Mozart\Config\Package; use CoenJacobs\Mozart\PackageFactory; +use CoenJacobs\Mozart\PackageFinder; use PHPUnit\Framework\TestCase; class ConfigMapperTest extends TestCase @@ -15,8 +16,10 @@ class ConfigMapperTest extends TestCase #[Test] public function it_creates_a_valid_config_object_based_on_composer_file() { - $package = PackageFactory::createPackage(__DIR__ . '/config-mapper-test.json'); - $package->loadDependencies(); + $finder = new PackageFinder(); + $factory = new PackageFactory(); + $package = $factory->createPackage(__DIR__ . '/config-mapper-test.json'); + $package->loadDependencies($finder); $this->assertInstanceOf(Package::class, $package); $this->assertInstanceOf(Mozart::class, $package->getExtra()->getMozart()); $this->assertCount(4, $package->autoload->getAutoloaders()); diff --git a/tests/MoverTest.php b/tests/MoverTest.php index af4ba47f..a21dbce6 100644 --- a/tests/MoverTest.php +++ b/tests/MoverTest.php @@ -5,6 +5,7 @@ use CoenJacobs\Mozart\PackageFactory; use CoenJacobs\Mozart\Console\Commands\Compose; use CoenJacobs\Mozart\Mover; +use CoenJacobs\Mozart\PackageFinder; use PHPUnit\Framework\TestCase; use PHPUnit\Framework\Attributes\Test; use Symfony\Component\Console\Input\InputInterface; @@ -54,7 +55,8 @@ public function setUp(): void ), ); - $this->config = Mozart::loadFromString( json_encode($configArgs) ); + $mozart = new Mozart(); + $this->config = $mozart->loadFromString( json_encode($configArgs) ); $this->config->setWorkingDir($this->testsWorkingDir); } @@ -138,8 +140,10 @@ public function it_deletes_subdirs_for_packages_about_to_be_moved(): void if ( ! empty( $overrideAutoload ) ) { $overrideAutoload = $overrideAutoload->getByKey( $packageString ); } - $parsedPackage = PackageFactory::createPackage($testDummyComposerPath, $overrideAutoload); - $parsedPackage->loadDependencies(); + $factory = new PackageFactory(); + $finder = new PackageFinder(); + $parsedPackage = $factory->createPackage($testDummyComposerPath, $overrideAutoload); + $parsedPackage->loadDependencies($finder); $packages[] = $parsedPackage; } From 10e709b46d4abbbaaba452fc560fd92788d2d2a2 Mon Sep 17 00:00:00 2001 From: Coen Jacobs Date: Tue, 17 Sep 2024 11:42:53 +0200 Subject: [PATCH 13/24] Reduce complexity of moveFile method on Mover class --- src/Console/Commands/Compose.php | 4 +++ src/Mover.php | 42 ++++++++++++++++++++------------ 2 files changed, 30 insertions(+), 16 deletions(-) diff --git a/src/Console/Commands/Compose.php b/src/Console/Commands/Compose.php index b17c1876..9d6207ee 100644 --- a/src/Console/Commands/Compose.php +++ b/src/Console/Commands/Compose.php @@ -91,6 +91,10 @@ protected function execute(InputInterface $input, OutputInterface $output): int $this->replacer->replaceParentInTree($packages); $this->replacer->replaceParentClassesInDirectory($this->config->getClassmapDirectory()); + if ($this->config->getDeleteVendorDirectories()) { + $this->mover->deletePackageVendorDirectories(); + } + return 0; } } diff --git a/src/Mover.php b/src/Mover.php index 1bf90337..6729ab6a 100644 --- a/src/Mover.php +++ b/src/Mover.php @@ -163,27 +163,39 @@ public function movePackage(Package $package): void $this->movedPackages[] = $package->getName(); } } - - if ($this->config->getDeleteVendorDirectories()) { - $this->deletePackageVendorDirectories(); - } } public function moveFile(Package $package, Autoloader $autoloader, SplFileInfo $file, string $path = ''): string { if ($autoloader instanceof NamespaceAutoloader) { - $namespacePath = $autoloader->getNamespacePath(); - $replaceWith = $this->config->getDepDirectory() . $namespacePath; - $targetFile = str_replace($this->workingDir, $replaceWith, $file->getPathname()); - - $packageVendorPath = DIRECTORY_SEPARATOR . 'vendor' . DIRECTORY_SEPARATOR . $package->getName() - . DIRECTORY_SEPARATOR . $path; - $packageVendorPath = str_replace('/', DIRECTORY_SEPARATOR, $packageVendorPath); - $targetFile = str_replace($packageVendorPath, '', $targetFile); + $targetFile = $this->getNamespaceTargetFile($package, $autoloader, $file, $path); $this->copyFile($file, $targetFile); return $targetFile; } + $targetFile = $this->getClassmapTargetFile($package, $file); + $this->copyFile($file, $targetFile); + return $targetFile; + } + + private function getNamespaceTargetFile( + Package $package, + NamespaceAutoloader $autoloader, + SplFileInfo $file, + string $path + ): string { + $namespacePath = $autoloader->getNamespacePath(); + $replaceWith = $this->config->getDepDirectory() . $namespacePath; + $targetFile = str_replace($this->workingDir, $replaceWith, $file->getPathname()); + + $packageVendorPath = DIRECTORY_SEPARATOR . 'vendor' . DIRECTORY_SEPARATOR . $package->getName() + . DIRECTORY_SEPARATOR . $path; + $packageVendorPath = str_replace('/', DIRECTORY_SEPARATOR, $packageVendorPath); + return str_replace($packageVendorPath, '', $targetFile); + } + + private function getClassmapTargetFile(Package $package, SplFileInfo $file): string + { $namespacePath = $package->getName(); $replaceWith = $this->config->getClassmapDirectory() . $namespacePath; $targetFile = str_replace($this->workingDir, $replaceWith, $file->getPathname()); @@ -191,9 +203,7 @@ public function moveFile(Package $package, Autoloader $autoloader, SplFileInfo $ $packageVendorPath = DIRECTORY_SEPARATOR . 'vendor' . DIRECTORY_SEPARATOR . $package->getName() . DIRECTORY_SEPARATOR; $packageVendorPath = str_replace('/', DIRECTORY_SEPARATOR, $packageVendorPath); - $targetFile = str_replace($packageVendorPath, DIRECTORY_SEPARATOR, $targetFile); - $this->copyFile($file, $targetFile); - return $targetFile; + return str_replace($packageVendorPath, DIRECTORY_SEPARATOR, $targetFile); } protected function copyFile(SplFileInfo $file, string $targetFile): void @@ -209,7 +219,7 @@ protected function copyFile(SplFileInfo $file, string $targetFile): void * prevent packages that are prefixed/namespaced from being used or * influencing the output of the code. They just need to be gone. */ - protected function deletePackageVendorDirectories(): void + public function deletePackageVendorDirectories(): void { foreach ($this->movedPackages as $movedPackage) { $packageDir = 'vendor' . DIRECTORY_SEPARATOR . $movedPackage; From 00470e70e3182a18d157400aadb4053e32d316de Mon Sep 17 00:00:00 2001 From: Coen Jacobs Date: Tue, 17 Sep 2024 12:03:31 +0200 Subject: [PATCH 14/24] Reduce complexity of movePackage method --- src/Mover.php | 109 +++++++++++++++++++++++++++++++++----------------- 1 file changed, 72 insertions(+), 37 deletions(-) diff --git a/src/Mover.php b/src/Mover.php index 6729ab6a..b4f9dfe2 100644 --- a/src/Mover.php +++ b/src/Mover.php @@ -106,53 +106,20 @@ public function movePackages($packages): void public function movePackage(Package $package): void { - if (in_array($package->getName(), $this->movedPackages)) { - return; - } - - if ($this->config->isExcludedPackage($package)) { + if (!$this->shouldPackageBeMoved($package)) { return; } foreach ($package->getAutoloaders() as $autoloader) { if ($autoloader instanceof NamespaceAutoloader) { foreach ($autoloader->paths as $path) { - $sourcePath = $this->workingDir . DIRECTORY_SEPARATOR . 'vendor' . DIRECTORY_SEPARATOR - . $package->getName() . DIRECTORY_SEPARATOR . $path; - - $sourcePath = str_replace('/', DIRECTORY_SEPARATOR, $sourcePath); - - - $files = $this->files->getFilesFromPath($sourcePath); - foreach ($files as $file) { + $filesToMove = $this->getNamespaceFilesToMove($package, $path); + foreach ($filesToMove as $file) { $this->moveFile($package, $autoloader, $file, $path); } } } elseif ($autoloader instanceof Classmap) { - $filesToMove = array(); - - foreach ($autoloader->files as $file) { - $sourcePath = $this->workingDir . DIRECTORY_SEPARATOR . 'vendor' - . DIRECTORY_SEPARATOR . $package->getName(); - - $files = $this->files->getFile($sourcePath, $file); - - foreach ($files as $foundFile) { - $filePath = $foundFile->getRealPath(); - $filesToMove[ $filePath ] = $foundFile; - } - } - - foreach ($autoloader->paths as $path) { - $sourcePath = $this->workingDir . DIRECTORY_SEPARATOR . 'vendor' - . DIRECTORY_SEPARATOR . $package->getName() . DIRECTORY_SEPARATOR . $path; - - $files = $this->files->getFilesFromPath($sourcePath); - foreach ($files as $foundFile) { - $filePath = $foundFile->getRealPath(); - $filesToMove[ $filePath ] = $foundFile; - } - } + $filesToMove = $this->getClassmapFilesToMove($autoloader, $package); foreach ($filesToMove as $foundFile) { $this->moveFile($package, $autoloader, $foundFile); @@ -165,6 +132,74 @@ public function movePackage(Package $package): void } } + private function shouldPackageBeMoved(Package $package): bool + { + if (in_array($package->getName(), $this->movedPackages)) { + return false; + } + + if ($this->config->isExcludedPackage($package)) { + return false; + } + + return true; + } + + /** + * @return array + */ + private function getNamespaceFilesToMove(Package $package, string $path): array + { + $filesToMove = array(); + + $sourcePath = $this->workingDir . DIRECTORY_SEPARATOR . 'vendor' . DIRECTORY_SEPARATOR + . $package->getName() . DIRECTORY_SEPARATOR . $path; + + $sourcePath = str_replace('/', DIRECTORY_SEPARATOR, $sourcePath); + + $files = $this->files->getFilesFromPath($sourcePath); + + foreach ($files as $foundFile) { + $filePath = $foundFile->getRealPath(); + $filesToMove[ $filePath ] = $foundFile; + } + + return $filesToMove; + } + + /** + * @return array + */ + private function getClassmapFilesToMove(Classmap $autoloader, Package $package): array + { + $filesToMove = array(); + + foreach ($autoloader->files as $file) { + $sourcePath = $this->workingDir . DIRECTORY_SEPARATOR . 'vendor' + . DIRECTORY_SEPARATOR . $package->getName(); + + $files = $this->files->getFile($sourcePath, $file); + + foreach ($files as $foundFile) { + $filePath = $foundFile->getRealPath(); + $filesToMove[ $filePath ] = $foundFile; + } + } + + foreach ($autoloader->paths as $path) { + $sourcePath = $this->workingDir . DIRECTORY_SEPARATOR . 'vendor' + . DIRECTORY_SEPARATOR . $package->getName() . DIRECTORY_SEPARATOR . $path; + + $files = $this->files->getFilesFromPath($sourcePath); + foreach ($files as $foundFile) { + $filePath = $foundFile->getRealPath(); + $filesToMove[ $filePath ] = $foundFile; + } + } + + return $filesToMove; + } + public function moveFile(Package $package, Autoloader $autoloader, SplFileInfo $file, string $path = ''): string { if ($autoloader instanceof NamespaceAutoloader) { From defd19010823943d4bc65e7e98123c0dbd119465 Mon Sep 17 00:00:00 2001 From: Coen Jacobs Date: Tue, 17 Sep 2024 12:43:51 +0200 Subject: [PATCH 15/24] Reduce complexity of deleteDepTargetDirs methods --- src/Composer/Autoload/AbstractAutoloader.php | 13 ++++++ src/Composer/Autoload/Autoloader.php | 1 + src/Composer/Autoload/NamespaceAutoloader.php | 2 +- src/Config/Classmap.php | 4 +- src/Mover.php | 43 +++++++++++-------- 5 files changed, 41 insertions(+), 22 deletions(-) create mode 100644 src/Composer/Autoload/AbstractAutoloader.php diff --git a/src/Composer/Autoload/AbstractAutoloader.php b/src/Composer/Autoload/AbstractAutoloader.php new file mode 100644 index 00000000..c2aeedee --- /dev/null +++ b/src/Composer/Autoload/AbstractAutoloader.php @@ -0,0 +1,13 @@ +config = $config; $this->workingDir = $workingDir; - $this->targetDir = $this->config->getDepDirectory(); + $this->config = $config; $this->files = new FilesHandler($config); } @@ -57,30 +53,40 @@ public function deleteTargetDirs($packages): void */ private function deleteDepTargetDirs(Package $package): void { - foreach ($package->getAutoloaders() as $packageAutoloader) { - $autoloaderType = get_class($packageAutoloader); + foreach ($package->getAutoloaders() as $autoloader) { + $autoloaderType = get_class($autoloader); + $outputDir = ''; switch ($autoloaderType) { case Psr0::class: case Psr4::class: - $outputDir = $this->config->getDepDirectory() . $packageAutoloader->getSearchNamespace(); - $outputDir = str_replace('\\', DIRECTORY_SEPARATOR, $outputDir); - $this->files->deleteDirectory($outputDir); + $outputDir = $autoloader->getOutputDir( + $this->config->getDepDirectory(), + $autoloader->getSearchNamespace() + ); break; case Classmap::class: - $outputDir = $this->config->getClassmapDirectory() . $package->getName(); - $outputDir = str_replace('\\', DIRECTORY_SEPARATOR, $outputDir); - $this->files->deleteDirectory($outputDir); + $outputDir = $autoloader->getOutputDir( + $this->config->getClassmapDirectory(), + $package->getName() + ); break; } + + if (empty($outputDir)) { + continue; + } + + $this->files->deleteDirectory($outputDir); } + foreach ($package->getDependencies() as $subPackage) { $this->deleteDepTargetDirs($subPackage); } } - public function deleteEmptyDirs(): void + private function deleteEmptyDirs(): void { if ($this->files->isDirectoryEmpty($this->config->getDepDirectory())) { $this->files->deleteDirectory($this->config->getDepDirectory()); @@ -104,7 +110,7 @@ public function movePackages($packages): void $this->deleteEmptyDirs(); } - public function movePackage(Package $package): void + private function movePackage(Package $package): void { if (!$this->shouldPackageBeMoved($package)) { return; @@ -200,17 +206,16 @@ private function getClassmapFilesToMove(Classmap $autoloader, Package $package): return $filesToMove; } - public function moveFile(Package $package, Autoloader $autoloader, SplFileInfo $file, string $path = ''): string + private function moveFile(Package $package, Autoloader $autoloader, SplFileInfo $file, string $path = ''): void { if ($autoloader instanceof NamespaceAutoloader) { $targetFile = $this->getNamespaceTargetFile($package, $autoloader, $file, $path); $this->copyFile($file, $targetFile); - return $targetFile; + return; } $targetFile = $this->getClassmapTargetFile($package, $file); $this->copyFile($file, $targetFile); - return $targetFile; } private function getNamespaceTargetFile( @@ -241,7 +246,7 @@ private function getClassmapTargetFile(Package $package, SplFileInfo $file): str return str_replace($packageVendorPath, DIRECTORY_SEPARATOR, $targetFile); } - protected function copyFile(SplFileInfo $file, string $targetFile): void + private function copyFile(SplFileInfo $file, string $targetFile): void { $this->files->copyFile( str_replace($this->workingDir, '', $file->getPathname()), From be0ba40d797c6763729418f8578fdd7f5f1b6b24 Mon Sep 17 00:00:00 2001 From: Coen Jacobs Date: Thu, 19 Sep 2024 10:03:44 +0200 Subject: [PATCH 16/24] Reduce Mover complexity by defering file path handling to autoloaders --- src/Composer/Autoload/AbstractAutoloader.php | 14 ++ src/Composer/Autoload/Autoloader.php | 8 ++ src/Composer/Autoload/NamespaceAutoloader.php | 51 +++++++ src/Config/Autoload.php | 5 +- src/Config/Classmap.php | 64 +++++++++ src/Config/Mozart.php | 6 +- src/Config/Package.php | 9 +- src/Console/Commands/Compose.php | 8 +- src/FilesHandler.php | 5 + src/Mover.php | 131 +++--------------- src/PackageFinder.php | 5 +- src/Replacer.php | 24 ++-- tests/MoverTest.php | 6 +- 13 files changed, 194 insertions(+), 142 deletions(-) diff --git a/src/Composer/Autoload/AbstractAutoloader.php b/src/Composer/Autoload/AbstractAutoloader.php index c2aeedee..05b8c379 100644 --- a/src/Composer/Autoload/AbstractAutoloader.php +++ b/src/Composer/Autoload/AbstractAutoloader.php @@ -2,8 +2,22 @@ namespace CoenJacobs\Mozart\Composer\Autoload; +use CoenJacobs\Mozart\Config\Package; + abstract class AbstractAutoloader implements Autoloader { + private Package $package; + + public function getPackage(): Package + { + return $this->package; + } + + public function setPackage(Package $package): void + { + $this->package = $package; + } + public function getOutputDir(string $basePath, string $autoloadPath): string { $outputDir = $basePath . $autoloadPath; diff --git a/src/Composer/Autoload/Autoloader.php b/src/Composer/Autoload/Autoloader.php index 609e2991..06ea8f90 100644 --- a/src/Composer/Autoload/Autoloader.php +++ b/src/Composer/Autoload/Autoloader.php @@ -2,6 +2,9 @@ namespace CoenJacobs\Mozart\Composer\Autoload; +use CoenJacobs\Mozart\FilesHandler; +use Symfony\Component\Finder\SplFileInfo; + interface Autoloader { /** @@ -10,4 +13,9 @@ interface Autoloader public function processConfig($autoloadConfig): void; public function getSearchNamespace(): string; public function getOutputDir(string $basePath, string $autoloadPath): string; + /** + * @return array + */ + public function getFiles(FilesHandler $files): array; + public function getTargetFilePath(SplFileInfo $file): string; } diff --git a/src/Composer/Autoload/NamespaceAutoloader.php b/src/Composer/Autoload/NamespaceAutoloader.php index 34e31c22..5e89eb23 100644 --- a/src/Composer/Autoload/NamespaceAutoloader.php +++ b/src/Composer/Autoload/NamespaceAutoloader.php @@ -2,6 +2,9 @@ namespace CoenJacobs\Mozart\Composer\Autoload; +use CoenJacobs\Mozart\FilesHandler; +use Symfony\Component\Finder\SplFileInfo; + abstract class NamespaceAutoloader extends AbstractAutoloader { /** @var string */ @@ -16,6 +19,8 @@ abstract class NamespaceAutoloader extends AbstractAutoloader */ public $paths = []; + private FilesHandler $fileHandler; + /** * A package's composer.json config autoload key's value, where $key is `psr-1`|`psr-4`|`classmap`. * @@ -47,4 +52,50 @@ public function getNamespacePath(): string { return ''; } + + public function getFiles(FilesHandler $fileHandler): array + { + $this->fileHandler = $fileHandler; + $filesToMove = array(); + + foreach ($this->paths as $path) { + $sourcePath = $fileHandler->getConfig()->getWorkingDir() . 'vendor' . DIRECTORY_SEPARATOR + . $this->getPackage()->getName() . DIRECTORY_SEPARATOR . $path; + + $sourcePath = str_replace('/', DIRECTORY_SEPARATOR, $sourcePath); + + + $files = $fileHandler->getFilesFromPath($sourcePath); + + foreach ($files as $foundFile) { + $filePath = $foundFile->getRealPath(); + $filesToMove[ $filePath ] = $foundFile; + } + } + + return $filesToMove; + } + + public function getTargetFilePath(SplFileInfo $file): string + { + $suffix = ''; + foreach ($this->paths as $path) { + if (! empty(strstr($file->getPathname(), $this->getPackage()->getName() . DIRECTORY_SEPARATOR . $path))) { + $suffix = $path; + break; + } + } + + $replaceWith = $this->fileHandler->getConfig()->getDepDirectory() . $this->getNamespacePath(); + $targetFile = str_replace($this->fileHandler->getConfig()->getWorkingDir(), $replaceWith, $file->getPathname()); + + $packageVendorPath = DIRECTORY_SEPARATOR . 'vendor' . DIRECTORY_SEPARATOR . $this->getPackage()->getName(); + + if (! empty($suffix)) { + $packageVendorPath = $packageVendorPath . DIRECTORY_SEPARATOR . $suffix; + } + + $packageVendorPath = str_replace('/', DIRECTORY_SEPARATOR, $packageVendorPath); + return str_replace($packageVendorPath, DIRECTORY_SEPARATOR, $targetFile); + } } diff --git a/src/Config/Autoload.php b/src/Config/Autoload.php index 55fd1aae..78198e14 100644 --- a/src/Config/Autoload.php +++ b/src/Config/Autoload.php @@ -10,7 +10,7 @@ class Autoload /** @var array */ public array $autoloaders = []; - public function setupAutoloaders(stdClass $autoloadData): void + public function setupAutoloaders(stdClass $autoloadData, Package $package): void { $autoloaders = []; @@ -20,6 +20,7 @@ public function setupAutoloaders(stdClass $autoloadData): void $autoloader = new Psr4(); $autoloader->namespace = $key; $autoloader->processConfig($value); + $autoloader->setPackage($package); $autoloaders[] = $autoloader; } } @@ -30,6 +31,7 @@ public function setupAutoloaders(stdClass $autoloadData): void $autoloader = new Psr0(); $autoloader->namespace = $key; $autoloader->processConfig($value); + $autoloader->setPackage($package); $autoloaders[] = $autoloader; } } @@ -37,6 +39,7 @@ public function setupAutoloaders(stdClass $autoloadData): void if (isset($autoloadData->classmap)) { $autoloader = new Classmap(); $autoloader->processConfig($autoloadData->classmap); + $autoloader->setPackage($package); $autoloaders[] = $autoloader; } diff --git a/src/Config/Classmap.php b/src/Config/Classmap.php index 4225d4be..4788f3d2 100644 --- a/src/Config/Classmap.php +++ b/src/Config/Classmap.php @@ -3,7 +3,9 @@ namespace CoenJacobs\Mozart\Config; use CoenJacobs\Mozart\Composer\Autoload\AbstractAutoloader; +use CoenJacobs\Mozart\FilesHandler; use Exception; +use Symfony\Component\Finder\SplFileInfo; class Classmap extends AbstractAutoloader { @@ -13,6 +15,8 @@ class Classmap extends AbstractAutoloader /** @var string[] */ public $paths = []; + private FilesHandler $fileHandler; + /** * @inheritdoc */ @@ -35,4 +39,64 @@ public function getSearchNamespace(): string { throw new Exception('Classmap autoloaders do not contain a namespace and this method can not be used.'); } + + /** + * @return array + */ + public function getFiles(FilesHandler $fileHandler): array + { + $this->fileHandler = $fileHandler; + $filesToMove = array(); + + foreach ($this->files as $file) { + $sourcePath = $fileHandler->getConfig()->getWorkingDir() . 'vendor' + . DIRECTORY_SEPARATOR . $this->getPackage()->getName(); + + $files = $fileHandler->getFile($sourcePath, $file); + + foreach ($files as $foundFile) { + $filePath = $foundFile->getRealPath(); + $filesToMove[ $filePath ] = $foundFile; + } + } + + foreach ($this->paths as $path) { + $sourcePath = $fileHandler->getConfig()->getWorkingDir() . 'vendor' + . DIRECTORY_SEPARATOR . $this->getPackage()->getName() . DIRECTORY_SEPARATOR . $path; + + $files = $fileHandler->getFilesFromPath($sourcePath); + foreach ($files as $foundFile) { + $filePath = $foundFile->getRealPath(); + $filesToMove[ $filePath ] = $foundFile; + } + } + + return $filesToMove; + } + + public function getTargetFilePath(SplFileInfo $file): string + { + $suffix = ''; + foreach ($this->paths as $path) { + if (! empty(strstr($file->getPathname(), $this->getPackage()->getName() . DIRECTORY_SEPARATOR . $path))) { + $suffix = $path; + break; + } + } + + $namespacePath = $this->getPackage()->getName(); + $replaceWith = $this->fileHandler->getConfig()->getClassmapDirectory() . $namespacePath . DIRECTORY_SEPARATOR; + + $targetFile = str_replace($this->fileHandler->getConfig()->getWorkingDir(), $replaceWith, $file->getPathname()); + + $packageVendorPath = DIRECTORY_SEPARATOR . 'vendor' . DIRECTORY_SEPARATOR . $this->getPackage()->getName() + . DIRECTORY_SEPARATOR; + + if (! empty($suffix)) { + $packageVendorPath = $packageVendorPath . DIRECTORY_SEPARATOR . $suffix; + } + + $packageVendorPath = str_replace('/', DIRECTORY_SEPARATOR, $packageVendorPath); + return str_replace($packageVendorPath, DIRECTORY_SEPARATOR, $targetFile); + } } diff --git a/src/Config/Mozart.php b/src/Config/Mozart.php index 4367d26e..ac02e32f 100644 --- a/src/Config/Mozart.php +++ b/src/Config/Mozart.php @@ -105,12 +105,12 @@ public function isExcludedPackage(Package $package): bool */ public function getDepDirectory(): string { - return rtrim($this->depDirectory, DIRECTORY_SEPARATOR).DIRECTORY_SEPARATOR; + return trim($this->depDirectory, DIRECTORY_SEPARATOR).DIRECTORY_SEPARATOR; } public function getClassmapDirectory(): string { - return rtrim($this->classmapDir, DIRECTORY_SEPARATOR).DIRECTORY_SEPARATOR; + return trim($this->classmapDir, DIRECTORY_SEPARATOR).DIRECTORY_SEPARATOR; } public function getDeleteVendorDirectories(): bool @@ -154,6 +154,6 @@ public function setWorkingDir(string $workingDir): void public function getWorkingDir(): string { - return $this->workingDir; + return rtrim($this->workingDir, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR; } } diff --git a/src/Config/Package.php b/src/Config/Package.php index 68746edb..5e4dece2 100644 --- a/src/Config/Package.php +++ b/src/Config/Package.php @@ -25,10 +25,12 @@ class Package public ?Autoload $autoload = null; public ?Extra $extra = null; + private bool $dependenciesLoaded = false; + public function setAutoload(stdClass $data): void { $autoload = new Autoload(); - $autoload->setupAutoloaders($data); + $autoload->setupAutoloaders($data, $this); $this->autoload = $autoload; } @@ -85,6 +87,10 @@ public function getDependencies(): array public function loadDependencies(PackageFinder $finder): void { + if ($this->dependenciesLoaded) { + return; + } + if ($this->isValidMozartConfig() && !empty($this->getExtra())) { $mozart = $this->getExtra()->getMozart(); @@ -97,6 +103,7 @@ public function loadDependencies(PackageFinder $finder): void $dependencies = $finder->getPackagesBySlugs($this->getRequire()); $this->registerDependencies($dependencies); + $this->dependenciesLoaded = true; } public function registerDependency(Package $package): void diff --git a/src/Console/Commands/Compose.php b/src/Console/Commands/Compose.php index 9d6207ee..63856d8f 100644 --- a/src/Console/Commands/Compose.php +++ b/src/Console/Commands/Compose.php @@ -78,12 +78,10 @@ protected function execute(InputInterface $input, OutputInterface $output): int $finder->setConfig($this->config); $package->loadDependencies($finder); + $packages = $finder->findPackages($package->getDependencies()); - $packages = $finder->getPackagesBySlugs($require); - $packages = $finder->findPackages($packages); - - $this->mover = new Mover($this->workingDir, $this->config); - $this->replacer = new Replacer($this->workingDir, $this->config); + $this->mover = new Mover($this->config); + $this->replacer = new Replacer($this->config); $this->mover->deleteTargetDirs($packages); $this->mover->movePackages($packages); diff --git a/src/FilesHandler.php b/src/FilesHandler.php index b8ffda58..46787b55 100644 --- a/src/FilesHandler.php +++ b/src/FilesHandler.php @@ -37,6 +37,11 @@ public function readFile(string $path): string return $contents; } + public function getConfig(): Mozart + { + return $this->config; + } + public function writeFile(string $path, string $contents): void { $this->filesystem->write($path, $contents); diff --git a/src/Mover.php b/src/Mover.php index 3bcbd446..70b4427d 100644 --- a/src/Mover.php +++ b/src/Mover.php @@ -3,7 +3,6 @@ namespace CoenJacobs\Mozart; use CoenJacobs\Mozart\Composer\Autoload\Autoloader; -use CoenJacobs\Mozart\Composer\Autoload\NamespaceAutoloader; use CoenJacobs\Mozart\Config\Classmap; use CoenJacobs\Mozart\Config\Mozart; use CoenJacobs\Mozart\Config\Package; @@ -13,9 +12,6 @@ class Mover { - /** @var string */ - protected $workingDir; - /** @var Mozart */ protected $config; @@ -24,9 +20,11 @@ class Mover /** @var array */ protected $movedPackages = []; - public function __construct(string $workingDir, Mozart $config) + /** @var array */ + protected $movedFiles = []; + + public function __construct(Mozart $config) { - $this->workingDir = $workingDir; $this->config = $config; $this->files = new FilesHandler($config); } @@ -103,7 +101,6 @@ private function deleteEmptyDirs(): void public function movePackages($packages): void { foreach ($packages as $package) { - $this->movePackages($package->getDependencies()); $this->movePackage($package); } @@ -116,26 +113,21 @@ private function movePackage(Package $package): void return; } + /** + * @todo: This maybe even warrants its own 'File' class, where stuff + * like the SplFileInfo etc can be stored in. + */ foreach ($package->getAutoloaders() as $autoloader) { - if ($autoloader instanceof NamespaceAutoloader) { - foreach ($autoloader->paths as $path) { - $filesToMove = $this->getNamespaceFilesToMove($package, $path); - foreach ($filesToMove as $file) { - $this->moveFile($package, $autoloader, $file, $path); - } - } - } elseif ($autoloader instanceof Classmap) { - $filesToMove = $this->getClassmapFilesToMove($autoloader, $package); - - foreach ($filesToMove as $foundFile) { - $this->moveFile($package, $autoloader, $foundFile); - } - } + $filesToMove = $autoloader->getFiles($this->files); - if (!in_array($package->getName(), $this->movedPackages)) { - $this->movedPackages[] = $package->getName(); + foreach ($filesToMove as $foundFile) { + $this->moveFile($autoloader, $foundFile); } } + + if (!in_array($package->getName(), $this->movedPackages)) { + $this->movedPackages[] = $package->getName(); + } } private function shouldPackageBeMoved(Package $package): bool @@ -151,105 +143,22 @@ private function shouldPackageBeMoved(Package $package): bool return true; } - /** - * @return array - */ - private function getNamespaceFilesToMove(Package $package, string $path): array - { - $filesToMove = array(); - - $sourcePath = $this->workingDir . DIRECTORY_SEPARATOR . 'vendor' . DIRECTORY_SEPARATOR - . $package->getName() . DIRECTORY_SEPARATOR . $path; - - $sourcePath = str_replace('/', DIRECTORY_SEPARATOR, $sourcePath); - - $files = $this->files->getFilesFromPath($sourcePath); - - foreach ($files as $foundFile) { - $filePath = $foundFile->getRealPath(); - $filesToMove[ $filePath ] = $foundFile; - } - - return $filesToMove; - } - - /** - * @return array - */ - private function getClassmapFilesToMove(Classmap $autoloader, Package $package): array - { - $filesToMove = array(); - - foreach ($autoloader->files as $file) { - $sourcePath = $this->workingDir . DIRECTORY_SEPARATOR . 'vendor' - . DIRECTORY_SEPARATOR . $package->getName(); - - $files = $this->files->getFile($sourcePath, $file); - - foreach ($files as $foundFile) { - $filePath = $foundFile->getRealPath(); - $filesToMove[ $filePath ] = $foundFile; - } - } - - foreach ($autoloader->paths as $path) { - $sourcePath = $this->workingDir . DIRECTORY_SEPARATOR . 'vendor' - . DIRECTORY_SEPARATOR . $package->getName() . DIRECTORY_SEPARATOR . $path; - - $files = $this->files->getFilesFromPath($sourcePath); - foreach ($files as $foundFile) { - $filePath = $foundFile->getRealPath(); - $filesToMove[ $filePath ] = $foundFile; - } - } - - return $filesToMove; - } - - private function moveFile(Package $package, Autoloader $autoloader, SplFileInfo $file, string $path = ''): void + private function moveFile(Autoloader $autoloader, SplFileInfo $file): void { - if ($autoloader instanceof NamespaceAutoloader) { - $targetFile = $this->getNamespaceTargetFile($package, $autoloader, $file, $path); - $this->copyFile($file, $targetFile); + if (in_array($file->getRealPath(), $this->movedFiles)) { return; } - $targetFile = $this->getClassmapTargetFile($package, $file); + $targetFile = $autoloader->getTargetFilePath($file); $this->copyFile($file, $targetFile); - } - - private function getNamespaceTargetFile( - Package $package, - NamespaceAutoloader $autoloader, - SplFileInfo $file, - string $path - ): string { - $namespacePath = $autoloader->getNamespacePath(); - $replaceWith = $this->config->getDepDirectory() . $namespacePath; - $targetFile = str_replace($this->workingDir, $replaceWith, $file->getPathname()); - - $packageVendorPath = DIRECTORY_SEPARATOR . 'vendor' . DIRECTORY_SEPARATOR . $package->getName() - . DIRECTORY_SEPARATOR . $path; - $packageVendorPath = str_replace('/', DIRECTORY_SEPARATOR, $packageVendorPath); - return str_replace($packageVendorPath, '', $targetFile); - } - private function getClassmapTargetFile(Package $package, SplFileInfo $file): string - { - $namespacePath = $package->getName(); - $replaceWith = $this->config->getClassmapDirectory() . $namespacePath; - $targetFile = str_replace($this->workingDir, $replaceWith, $file->getPathname()); - - $packageVendorPath = DIRECTORY_SEPARATOR . 'vendor' . DIRECTORY_SEPARATOR . $package->getName() - . DIRECTORY_SEPARATOR; - $packageVendorPath = str_replace('/', DIRECTORY_SEPARATOR, $packageVendorPath); - return str_replace($packageVendorPath, DIRECTORY_SEPARATOR, $targetFile); + array_push($this->movedFiles, $file->getRealPath()); } private function copyFile(SplFileInfo $file, string $targetFile): void { $this->files->copyFile( - str_replace($this->workingDir, '', $file->getPathname()), + str_replace($this->config->getWorkingDir(), '', $file->getPathname()), $targetFile ); } diff --git a/src/PackageFinder.php b/src/PackageFinder.php index 73367ccf..5950cd4e 100644 --- a/src/PackageFinder.php +++ b/src/PackageFinder.php @@ -81,8 +81,9 @@ public function findPackages(array $packages): array foreach ($packages as $package) { $dependencies = $package->getDependencies(); - $package->registerDependencies($this->findPackages($dependencies)); - $packages[$package->getName()] = $package; + if (! empty($dependencies)) { + $packages = array_merge($packages, $this->findPackages($dependencies)); + } } return $packages; diff --git a/src/Replacer.php b/src/Replacer.php index 8cc76433..af4d4832 100644 --- a/src/Replacer.php +++ b/src/Replacer.php @@ -14,12 +14,6 @@ class Replacer { - /** @var string */ - protected $workingDir; - - /** @var string */ - protected $targetDir; - /** @var Mozart */ protected $config; @@ -29,11 +23,9 @@ class Replacer /** @var FilesHandler */ protected $files; - public function __construct(string $workingDir, Mozart $config) + public function __construct(Mozart $config) { - $this->workingDir = $workingDir; $this->config = $config; - $this->targetDir = $this->config->getDepDirectory(); $this->files = new FilesHandler($config); } @@ -57,7 +49,7 @@ public function replacePackage(Package $package): void public function replaceInFile(string $targetFile, Autoloader $autoloader): void { - $targetFile = str_replace($this->workingDir, '', $targetFile); + $targetFile = str_replace($this->config->getWorkingDir(), '', $targetFile); $contents = $this->files->readFile($targetFile); if (!$contents) { @@ -96,11 +88,11 @@ public function replacePackageByAutoloader(Package $package, Autoloader $autoloa } if ($autoloader instanceof NamespaceAutoloader) { - $sourcePath = $this->workingDir . $this->targetDir + $sourcePath = $this->config->getWorkingDir() . $this->config->getDepDirectory() . str_replace('\\', DIRECTORY_SEPARATOR, $autoloader->getNamespace()); $this->replaceInDirectory($autoloader, $sourcePath); } elseif ($autoloader instanceof Classmap) { - $sourcePath = $this->workingDir . $this->config->getClassmapDirectory() . $package->getName(); + $sourcePath = $this->config->getWorkingDir() . $this->config->getClassmapDirectory() . $package->getName(); $files = $this->files->getFilesFromPath($sourcePath); foreach ($files as $foundFile) { @@ -180,7 +172,7 @@ public function replaceParentPackage(Package $package, Package $parent): void foreach ($package->getAutoloaders() as $autoloader) { if ($parentAutoloader instanceof NamespaceAutoloader) { $namespace = str_replace('\\', DIRECTORY_SEPARATOR, $parentAutoloader->namespace); - $directory = $this->workingDir . $this->config->getDepDirectory() . $namespace + $directory = $this->config->getWorkingDir() . $this->config->getDepDirectory() . $namespace . DIRECTORY_SEPARATOR; if ($autoloader instanceof NamespaceAutoloader) { @@ -188,12 +180,12 @@ public function replaceParentPackage(Package $package, Package $parent): void return; } - $directory = str_replace($this->workingDir, '', $directory); + $directory = str_replace($this->config->getWorkingDir(), '', $directory); $this->replaceParentClassesInDirectory($directory); return; } - $directory = $this->workingDir . + $directory = $this->config->getWorkingDir() . $this->config->getClassmapDirectory() . $parent->getName(); if ($autoloader instanceof NamespaceAutoloader) { @@ -201,7 +193,7 @@ public function replaceParentPackage(Package $package, Package $parent): void return; } - $directory = str_replace($this->workingDir, '', $directory); + $directory = str_replace($this->config->getWorkingDir(), '', $directory); $this->replaceParentClassesInDirectory($directory); } } diff --git a/tests/MoverTest.php b/tests/MoverTest.php index a21dbce6..9e6550ad 100644 --- a/tests/MoverTest.php +++ b/tests/MoverTest.php @@ -68,7 +68,7 @@ public function setUp(): void #[Test] public function it_creates_absent_dirs(): void { - $mover = new Mover($this->testsWorkingDir, $this->config); + $mover = new Mover($this->config); $packages = array(); @@ -88,7 +88,7 @@ public function it_creates_absent_dirs(): void #[Test] public function it_is_unpertrubed_by_existing_dirs(): void { - $mover = new Mover($this->testsWorkingDir, $this->config); + $mover = new Mover($this->config); if (!file_exists($this->testsWorkingDir . $this->config->getDepDirectory())) { mkdir($this->testsWorkingDir . $this->config->getDepDirectory()); @@ -147,7 +147,7 @@ public function it_deletes_subdirs_for_packages_about_to_be_moved(): void $packages[] = $parsedPackage; } - $mover = new Mover($this->testsWorkingDir, $this->config); + $mover = new Mover($this->config); $mover->deleteTargetDirs($packages); $this->assertDirectoryDoesNotExist($this->testsWorkingDir . $this->config->getDepDirectory() . 'Pimple'); From 3f8e10c4480801714f8c66b8e8a4781215a8c084 Mon Sep 17 00:00:00 2001 From: Coen Jacobs Date: Thu, 19 Sep 2024 10:11:19 +0200 Subject: [PATCH 17/24] Suppress parameter not being used as it extends Symfony command class --- src/Console/Commands/Compose.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Console/Commands/Compose.php b/src/Console/Commands/Compose.php index 63856d8f..a8bf0dbd 100644 --- a/src/Console/Commands/Compose.php +++ b/src/Console/Commands/Compose.php @@ -39,6 +39,9 @@ protected function configure(): void $this->setHelp(''); } + /** + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ protected function execute(InputInterface $input, OutputInterface $output): int { if (! $this->workingDir) { From b1a58c58e9aea2b722637d8126ab2766ff19e914 Mon Sep 17 00:00:00 2001 From: Coen Jacobs Date: Thu, 19 Sep 2024 10:15:18 +0200 Subject: [PATCH 18/24] Add phpmd to test script and GitHub Actions --- .github/workflows/main.yml | 17 +++++++++++++++++ composer.json | 6 +++++- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index f5583e8a..00f7d12e 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -60,3 +60,20 @@ jobs: cache-to: type=gha,mode=max - name: Run analysis run: docker compose run --rm actions-tester composer test:phpstan + mess-detect: + runs-on: ubuntu-latest + name: Mess detector + steps: + - name: Setup Docker buildx + uses: docker/setup-buildx-action@v2 + - uses: actions/checkout@v4 + - name: Build Docker image + id: build-and-push + uses: docker/build-push-action@v4 + with: + context: "{{defaultContext}}" + push: false + cache-from: type=gha + cache-to: type=gha,mode=max + - name: Run mess detector + run: docker compose run --rm actions-tester composer test:phpmd diff --git a/composer.json b/composer.json index 6f0af7e6..2170597c 100644 --- a/composer.json +++ b/composer.json @@ -47,7 +47,8 @@ "test": [ "@test:lint", "@test:phpunit", - "@test:phpstan" + "@test:phpstan", + "@test:phpmd" ], "test:lint": [ "composer validate", @@ -58,6 +59,9 @@ ], "test:phpstan": [ "./vendor/bin/phpstan analyse -c phpstan.neon.dist --memory-limit=2G" + ], + "test:phpmd": [ + "./vendor/bin/phpmd src ansi phpmd.xml.dist" ] } } From 36a61f754a27bfdbd941f088c05d2ca66b32b885 Mon Sep 17 00:00:00 2001 From: Coen Jacobs Date: Thu, 19 Sep 2024 11:14:58 +0200 Subject: [PATCH 19/24] Cleanup, documentation fixes and formatting --- src/Composer/Autoload/NamespaceAutoloader.php | 20 +++++---- src/Config/Autoload.php | 4 +- src/Console/Commands/Compose.php | 21 +++------- src/Mover.php | 21 +++++----- src/PackageFinder.php | 5 +-- src/Replace/ClassmapReplacer.php | 5 ++- src/Replace/NamespaceReplacer.php | 12 ++---- src/Replace/Replacer.php | 3 ++ src/Replacer.php | 3 +- tests/Console/Commands/ComposeTest.php | 42 +++++++++---------- tests/MoverTest.php | 24 +++++++---- tests/replacers/ClassMapReplacerTest.php | 3 +- tests/replacers/NamespaceReplacerTest.php | 9 ++-- 13 files changed, 86 insertions(+), 86 deletions(-) diff --git a/src/Composer/Autoload/NamespaceAutoloader.php b/src/Composer/Autoload/NamespaceAutoloader.php index 5e89eb23..071b5650 100644 --- a/src/Composer/Autoload/NamespaceAutoloader.php +++ b/src/Composer/Autoload/NamespaceAutoloader.php @@ -7,24 +7,23 @@ abstract class NamespaceAutoloader extends AbstractAutoloader { - /** @var string */ - public $namespace = ''; + public string $namespace = ''; /** - * The subdir of the vendor/domain/package directory that contains the files for this autoloader type. + * The subdir of the vendor/domain/package directory that contains the files + * for this autoloader type. e.g. src/ * - * e.g. src/ - * - * @var array + * @var string[] */ public $paths = []; private FilesHandler $fileHandler; /** - * A package's composer.json config autoload key's value, where $key is `psr-1`|`psr-4`|`classmap`. + * A package's composer.json config autoload key's value, where $key is + * `psr-0`|`psr-4`|`classmap`. * - * @param $autoloadConfig + * @inheritdoc */ public function processConfig($autoloadConfig): void { @@ -38,6 +37,11 @@ public function processConfig($autoloadConfig): void array_push($this->paths, $autoloadConfig); } + public function setNamespace(string $namespace): void + { + $this->namespace = $namespace; + } + public function getNamespace(): string { return rtrim($this->namespace, '\\') . '\\'; diff --git a/src/Config/Autoload.php b/src/Config/Autoload.php index 78198e14..617519d0 100644 --- a/src/Config/Autoload.php +++ b/src/Config/Autoload.php @@ -18,7 +18,7 @@ public function setupAutoloaders(stdClass $autoloadData, Package $package): void $psr4Autoloaders = (array) $autoloadData->{'psr-4'}; foreach ($psr4Autoloaders as $key => $value) { $autoloader = new Psr4(); - $autoloader->namespace = $key; + $autoloader->setNamespace($key); $autoloader->processConfig($value); $autoloader->setPackage($package); $autoloaders[] = $autoloader; @@ -29,7 +29,7 @@ public function setupAutoloaders(stdClass $autoloadData, Package $package): void $psr0Autoloaders = (array) $autoloadData->{'psr-0'}; foreach ($psr0Autoloaders as $key => $value) { $autoloader = new Psr0(); - $autoloader->namespace = $key; + $autoloader->setNamespace($key); $autoloader->processConfig($value); $autoloader->setPackage($package); $autoloaders[] = $autoloader; diff --git a/src/Console/Commands/Compose.php b/src/Console/Commands/Compose.php index a8bf0dbd..7612719a 100644 --- a/src/Console/Commands/Compose.php +++ b/src/Console/Commands/Compose.php @@ -19,19 +19,6 @@ class Compose extends Command private Mozart $config; private string $workingDir; - public function __construct() - { - $workingDir = getcwd(); - - if (! $workingDir) { - throw new Exception('Unable to determine the working directory.'); - } - - $this->workingDir = $workingDir; - - parent::__construct(); - } - protected function configure(): void { $this->setName('compose'); @@ -44,10 +31,14 @@ protected function configure(): void */ protected function execute(InputInterface $input, OutputInterface $output): int { - if (! $this->workingDir) { - throw new Exception('Could not determine working directory.'); + $workingDir = getcwd(); + + if (! $workingDir) { + throw new Exception('Unable to determine the working directory.'); } + $this->workingDir = $workingDir; + $composerFile = $this->workingDir . DIRECTORY_SEPARATOR. 'composer.json'; try { $factory = new PackageFactory(); diff --git a/src/Mover.php b/src/Mover.php index 70b4427d..d1994c42 100644 --- a/src/Mover.php +++ b/src/Mover.php @@ -12,9 +12,7 @@ class Mover { - /** @var Mozart */ - protected $config; - + protected Mozart $config; protected FilesHandler $files; /** @var array */ @@ -30,9 +28,11 @@ public function __construct(Mozart $config) } /** - * Create the required `dep_directory` and `classmap_directory` and delete targetDirs of packages about to be moved. + * Create the required `dep_directory` and `classmap_directory` and delete + * targetDirs of packages about to be moved. * - * @param Package[] $packages The packages that, in the next step, will be moved. + * @param Package[] $packages The packages to delete the target directories + * for, which will be moved in the next step. */ public function deleteTargetDirs($packages): void { @@ -45,9 +45,8 @@ public function deleteTargetDirs($packages): void } /** - * Delete the directories about to be used for packages earmarked for Mozart namespacing. - * - * @visibility private to allow recursion through packages and subpackages. + * Delete the directories about to be used for packages earmarked for Mozart + * namespacing. */ private function deleteDepTargetDirs(Package $package): void { @@ -178,8 +177,10 @@ public function deletePackageVendorDirectories(): void $this->files->deleteDirectory($packageDir); - //Delete parent directory too if it became empty - //(because that package was the only one from that vendor) + /** + * Delete parent directory too if it became empty (because that + * package was the only one from that vendor). + */ $parentDir = dirname($packageDir); if ($this->files->isDirectoryEmpty($parentDir)) { $this->files->deleteDirectory($parentDir); diff --git a/src/PackageFinder.php b/src/PackageFinder.php index 5950cd4e..a257676e 100644 --- a/src/PackageFinder.php +++ b/src/PackageFinder.php @@ -69,11 +69,10 @@ public function getPackagesBySlugs(array $slugs): array } /** - * Loops through all dependencies and their dependencies and so on... - * will eventually return a list of all packages required by the full tree. + * Loops through all dependencies and their dependencies and so on... will + * eventually return a list of all packages required by the full tree. * * @param Package[] $packages - * * @return Package[] */ public function findPackages(array $packages): array diff --git a/src/Replace/ClassmapReplacer.php b/src/Replace/ClassmapReplacer.php index 803467fd..14a18f40 100644 --- a/src/Replace/ClassmapReplacer.php +++ b/src/Replace/ClassmapReplacer.php @@ -1,7 +1,8 @@ autoloader->getSearchNamespace(), '/'); $dependencyNamespace = preg_quote($this->depNamespace, '/'); diff --git a/src/Replace/Replacer.php b/src/Replace/Replacer.php index 907bdf9e..2266169c 100644 --- a/src/Replace/Replacer.php +++ b/src/Replace/Replacer.php @@ -7,5 +7,8 @@ interface Replacer { public function setAutoloader(Autoloader $autoloader): void; + /** + * @param string $contents The text to make replacements in. + */ public function replace(string $contents): string; } diff --git a/src/Replacer.php b/src/Replacer.php index af4d4832..ae341d60 100644 --- a/src/Replacer.php +++ b/src/Replacer.php @@ -200,7 +200,8 @@ public function replaceParentPackage(Package $package, Package $parent): void } /** - * Get an array containing all the dependencies and dependencies + * Get an array containing all the dependencies and dependencies. + * * @param Package $package * @param Package[] $dependencies * @return Package[] diff --git a/tests/Console/Commands/ComposeTest.php b/tests/Console/Commands/ComposeTest.php index 325ea3bc..6ec1d9aa 100644 --- a/tests/Console/Commands/ComposeTest.php +++ b/tests/Console/Commands/ComposeTest.php @@ -18,9 +18,8 @@ public static function setUpBeforeClass(): void } /** - * Before each test ensure the current working directory is this one. - * - * Record the previous PHPUnit cwd to restore after. + * Before each test ensure the current working directory is this one. Record + * the previous PHPUnit cwd to restore after. */ public function setUp(): void { @@ -30,9 +29,9 @@ public function setUp(): void } /** - * When composer.json is absent, instead of failing with: - * "failed to open stream: No such file or directory" - * a better message should be written to the OutputInterface. + * When composer.json is absent, instead of failing with: "failed to open + * stream: No such file or directory" a better message should be written to + * the OutputInterface. * * @test */ @@ -56,9 +55,8 @@ public function __construct($inputInterfaceMock, $outputInterfaceMock) } /** - * When json_decode fails, instead of - * "Trying to get property 'extra' of non-object" - * a better message should be written to the OutputInterface. + * When json_decode fails, instead of "Trying to get property 'extra' of + * non-object" a better message should be written to the OutputInterface. * * @test */ @@ -86,9 +84,9 @@ public function __construct($inputInterfaceMock, $outputInterfaceMock) } /** - * When composer.json->extra is absent, instead of - * "Undefined property: stdClass::$extra" - * a better message should be written to the OutputInterface. + * When composer.json->extra is absent, instead of "Undefined property: + * stdClass::$extra" a better message should be written to the + * OutputInterface. * * @test */ @@ -117,9 +115,9 @@ public function __construct($inputInterfaceMock, $outputInterfaceMock) /** - * When composer.json->extra is not an object, instead of - * "Trying to get property 'mozart' of non-object" - * a better message should be written to the OutputInterface. + * When composer.json->extra is not an object, instead of "Trying to get + * property 'mozart' of non-object" a better message should be written to + * the OutputInterface. * * @test */ @@ -147,9 +145,9 @@ public function __construct($inputInterfaceMock, $outputInterfaceMock) } /** - * When composer.json->extra->mozart is absent, instead of - * "Undefined property: stdClass::$mozart" - * a better message should be written to the OutputInterface. + * When composer.json->extra->mozart is absent, instead of "Undefined + * property: stdClass::$mozart" a better message should be written to the + * OutputInterface. * * @test */ @@ -177,11 +175,9 @@ public function __construct($inputInterfaceMock, $outputInterfaceMock) } /** - * When composer.json->extra->mozart is malformed, instead of - * "Undefined property: stdClass::$mozart" - * a better message should be written to the OutputInterface. - * - * is_object() added. + * When composer.json->extra->mozart is malformed, instead of "Undefined + * property: stdClass::$mozart" a better message should be written to the + * OutputInterface. * * @test */ diff --git a/tests/MoverTest.php b/tests/MoverTest.php index 9e6550ad..ac922d31 100644 --- a/tests/MoverTest.php +++ b/tests/MoverTest.php @@ -61,7 +61,8 @@ public function setUp(): void } /** - * If the specified `dep_directory` or `classmap_directory` are absent, create them. + * If the specified `dep_directory` or `classmap_directory` are absent, + * create them. * * @test */ @@ -81,7 +82,8 @@ public function it_creates_absent_dirs(): void } /** - * If the specified `dep_directory` or `classmap_directory` already exists with contents, it is not an issue. + * If the specified `dep_directory` or `classmap_directory` already exists + * with contents, it is not an issue. * * @test */ @@ -112,8 +114,10 @@ public function it_is_unpertrubed_by_existing_dirs(): void } /** - * If the specified `dep_directory` or `classmap_directory` contains a subdir we are going to need when moving, - * delete the subdir. aka: If subfolders exist for dependencies we are about to manage, delete those subfolders. + * If the specified `dep_directory` or `classmap_directory` contains a + * subdir we are going to need when moving, delete the subdir. aka: If + * subfolders exist for dependencies we are about to manage, delete those + * subfolders. * * @test */ @@ -155,14 +159,16 @@ public function it_deletes_subdirs_for_packages_about_to_be_moved(): void } /** - * If a file is specified more than once in an autoloader, e.g. is explicitly listed and is also in a folder listed, - * a "File already exists at path" error occurs. + * If a file is specified more than once in an autoloader, e.g. is + * explicitly listed and is also in a folder listed, a "File already exists + * at path" error occurs. * - * To fix this, we enumerate the files to be copied using a dictionary indexed with the source file path, then loop - * and copy, thus only copying each one once. + * To fix this, we list the files being moved/copied by their absolute path + * resulting in only copying each file only once. * * Original error: - * "League\Flysystem\FileExistsException : File already exists at path: lib/classes/tecnickcom/tcpdf/tcpdf.php" + * "League\Flysystem\FileExistsException : File already exists at path: + * lib/classes/tecnickcom/tcpdf/tcpdf.php" * * Test is using a known problematic autoloader: * "iio/libmergepdf": { diff --git a/tests/replacers/ClassMapReplacerTest.php b/tests/replacers/ClassMapReplacerTest.php index 6f08af06..131d2089 100644 --- a/tests/replacers/ClassMapReplacerTest.php +++ b/tests/replacers/ClassMapReplacerTest.php @@ -140,7 +140,8 @@ public function it_does_not_replace_inside_namespace_singleline(): void /** * It's possible to have multiple namespaces inside one file. * - * To have two classes in one file, one in a namespace and the other not, the global namespace needs to be explicit. + * To have two classes in one file, one in a namespace and the other not, + * the global namespace needs to be explicit. * * @test */ diff --git a/tests/replacers/NamespaceReplacerTest.php b/tests/replacers/NamespaceReplacerTest.php index 2fa41651..ea88c53e 100644 --- a/tests/replacers/NamespaceReplacerTest.php +++ b/tests/replacers/NamespaceReplacerTest.php @@ -24,7 +24,8 @@ protected function setUp(): void protected static function createReplacer(string $namespace, string $prefix = self::PREFIX) : NamespaceReplacer { $autoloader = new Psr0; - $autoloader->namespace = $namespace; + $autoloader->setNamespace($namespace); + $replacer = new NamespaceReplacer(); $replacer->setAutoloader($autoloader); $replacer->depNamespace = $prefix; @@ -83,8 +84,10 @@ public function it_doesnt_double_replace_namespaces_that_also_exist_inside_anoth $chickenReplacer = self::createReplacer('Chicken'); $eggReplacer = self::createReplacer('Egg'); - // This is a tricky situation. We are referencing Chicken\Egg, - // but Egg *also* exists as a separate top level class. + /** + * This is a tricky situation. We are referencing Chicken\Egg,but Egg + * *also* exists as a separate top level class. + */ $contents = 'use Chicken\\Egg;'; $expected = 'use My\\Mozart\\Prefix\\Chicken\\Egg;'; From 4a5a07d1e5b1921f617886305f57672b3e26d344 Mon Sep 17 00:00:00 2001 From: Coen Jacobs Date: Thu, 19 Sep 2024 11:30:39 +0200 Subject: [PATCH 20/24] Enforce docblocks for complex methods by set thresholds --- composer.json | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index 2170597c..140cc2fb 100644 --- a/composer.json +++ b/composer.json @@ -41,14 +41,16 @@ "symfony/finder": "^5.4", "dealerdirect/phpcodesniffer-composer-installer": "^1.0", "phpcompatibility/php-compatibility": "dev-develop", - "phpmd/phpmd": "^2.15" + "phpmd/phpmd": "^2.15", + "niels-de-blaauw/php-doc-check": "^0.4.0" }, "scripts": { "test": [ "@test:lint", "@test:phpunit", "@test:phpstan", - "@test:phpmd" + "@test:phpmd", + "@test:docs" ], "test:lint": [ "composer validate", @@ -62,6 +64,9 @@ ], "test:phpmd": [ "./vendor/bin/phpmd src ansi phpmd.xml.dist" + ], + "test:docs": [ + "./vendor/bin/php-doc-check src" ] } } From 58e0644e7f157c051c676105382080ba1f716bb1 Mon Sep 17 00:00:00 2001 From: Coen Jacobs Date: Thu, 19 Sep 2024 13:38:18 +0200 Subject: [PATCH 21/24] Added enforced docblocks for complex methods --- src/Composer/Autoload/Autoloader.php | 7 +++++++ src/Composer/Autoload/NamespaceAutoloader.php | 3 +++ src/Config/Autoload.php | 6 ++++++ src/Config/Classmap.php | 3 +++ src/Config/Package.php | 7 +++++++ src/Mover.php | 5 +++++ src/PackageFinder.php | 9 +++++++++ src/Replacer.php | 9 +++++++++ 8 files changed, 49 insertions(+) diff --git a/src/Composer/Autoload/Autoloader.php b/src/Composer/Autoload/Autoloader.php index 06ea8f90..92a10ebf 100644 --- a/src/Composer/Autoload/Autoloader.php +++ b/src/Composer/Autoload/Autoloader.php @@ -17,5 +17,12 @@ public function getOutputDir(string $basePath, string $autoloadPath): string; * @return array */ public function getFiles(FilesHandler $files): array; + /** + * Returns the intended target path of a file, where it should be moved by + * the Mover class. This requires access to the Mozart configuration, for it + * to determine the target directory. This is done by checking the paths + * that are being registered for this autoloader, to see if they can be + * matched with the full path name of the provided file. + */ public function getTargetFilePath(SplFileInfo $file): string; } diff --git a/src/Composer/Autoload/NamespaceAutoloader.php b/src/Composer/Autoload/NamespaceAutoloader.php index 071b5650..fab3d286 100644 --- a/src/Composer/Autoload/NamespaceAutoloader.php +++ b/src/Composer/Autoload/NamespaceAutoloader.php @@ -80,6 +80,9 @@ public function getFiles(FilesHandler $fileHandler): array return $filesToMove; } + /** + * @inheritdoc + */ public function getTargetFilePath(SplFileInfo $file): string { $suffix = ''; diff --git a/src/Config/Autoload.php b/src/Config/Autoload.php index 617519d0..e6a0cddc 100644 --- a/src/Config/Autoload.php +++ b/src/Config/Autoload.php @@ -10,6 +10,12 @@ class Autoload /** @var array */ public array $autoloaders = []; + /** + * Loads the autoloaders provided in the loaded composer.json file, which is + * then passed to this method as a stdClass. It registers each autoloader, + * which are then used to access the paths to read and replace contents of + * files that these autoloaders allow access to. + */ public function setupAutoloaders(stdClass $autoloadData, Package $package): void { $autoloaders = []; diff --git a/src/Config/Classmap.php b/src/Config/Classmap.php index 4788f3d2..5826db59 100644 --- a/src/Config/Classmap.php +++ b/src/Config/Classmap.php @@ -74,6 +74,9 @@ public function getFiles(FilesHandler $fileHandler): array return $filesToMove; } + /** + * @inheritdoc + */ public function getTargetFilePath(SplFileInfo $file): string { $suffix = ''; diff --git a/src/Config/Package.php b/src/Config/Package.php index 5e4dece2..9794c2e5 100644 --- a/src/Config/Package.php +++ b/src/Config/Package.php @@ -85,6 +85,13 @@ public function getDependencies(): array return $this->dependencies; } + /** + * Loads and registers all dependencies of this package, by checking the + * require-object of the composer.json file of this package. Each package + * listed as a dependency is then loaded and registered as being a + * dependency of this package. Also flags this package for having its + * dependencies already loaded, so it doesn't duplicate dependencies. + */ public function loadDependencies(PackageFinder $finder): void { if ($this->dependenciesLoaded) { diff --git a/src/Mover.php b/src/Mover.php index d1994c42..3c928902 100644 --- a/src/Mover.php +++ b/src/Mover.php @@ -106,6 +106,11 @@ public function movePackages($packages): void $this->deleteEmptyDirs(); } + /** + * Moves each file for each autoloader, for the provided package. Each + * package will only be moved once, to prevent duplicates, so the package + * name is registered at the end of the method. + */ private function movePackage(Package $package): void { if (!$this->shouldPackageBeMoved($package)) { diff --git a/src/PackageFinder.php b/src/PackageFinder.php index a257676e..1c6e268b 100644 --- a/src/PackageFinder.php +++ b/src/PackageFinder.php @@ -21,6 +21,12 @@ public function setConfig(Mozart $config): void $this->config = $config; } + /** + * Returns a Package object for the package based on the provided slug (in + * vendor/package format). The data of the package is loaded if a valid + * installed package could be found based on the slug, which is then being + * used to read the composer.json file of the package. + */ public function getPackageBySlug(string $slug): ?Package { /** @@ -54,6 +60,9 @@ public function getPackageBySlug(string $slug): ?Package } /** + * Returns Package objects which are loaded based on the provided array of + * slugs (in vendor/package format). + * * @param string[] $slugs * @return Package[] */ diff --git a/src/Replacer.php b/src/Replacer.php index ae341d60..6179bbf1 100644 --- a/src/Replacer.php +++ b/src/Replacer.php @@ -81,6 +81,10 @@ public function getReplacerByAutoloader(Autoloader $autoloader): ReplacerInterfa return $replacer; } + /** + * Fetches the files or directories to perform a replace action on, based + * on the provided autoloader, for the provided package. + */ public function replacePackageByAutoloader(Package $package, Autoloader $autoloader): void { if ($this->config->isExcludedPackage($package)) { @@ -105,6 +109,11 @@ public function replacePackageByAutoloader(Package $package, Autoloader $autoloa } } + /** + * Replaces all occurances of previously replaced classes, in the provided + * directory. This to ensure that each package has its parents package + * classes also replaced in its own files. + */ public function replaceParentClassesInDirectory(string $directory): void { if (count($this->replacedClasses)===0) { From e755e61937797a736a998dc3201243e7555735a7 Mon Sep 17 00:00:00 2001 From: Coen Jacobs Date: Thu, 19 Sep 2024 13:41:33 +0200 Subject: [PATCH 22/24] Add doc check to GitHub Actions steps --- .github/workflows/main.yml | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 00f7d12e..5a74b2dd 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -77,3 +77,20 @@ jobs: cache-to: type=gha,mode=max - name: Run mess detector run: docker compose run --rm actions-tester composer test:phpmd + doc-check: + runs-on: ubuntu-latest + name: Documentation check + steps: + - name: Setup Docker buildx + uses: docker/setup-buildx-action@v2 + - uses: actions/checkout@v4 + - name: Build Docker image + id: build-and-push + uses: docker/build-push-action@v4 + with: + context: "{{defaultContext}}" + push: false + cache-from: type=gha + cache-to: type=gha,mode=max + - name: Run doc check + run: docker compose run --rm actions-tester composer test:docs From f054665d837c0cbd4a2d01ef28df1a34dd56c111 Mon Sep 17 00:00:00 2001 From: Coen Jacobs Date: Thu, 19 Sep 2024 13:59:46 +0200 Subject: [PATCH 23/24] Change coding standard to PSR-12 --- phpcs.xml.dist | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/phpcs.xml.dist b/phpcs.xml.dist index a83ef6c4..c260bdaa 100644 --- a/phpcs.xml.dist +++ b/phpcs.xml.dist @@ -1,8 +1,8 @@ - Coding standard ruleset based on the PSR-2 coding standard. - + Coding standard ruleset based on the PSR-12 coding standard. + From 0d7ae1a44f2fe34fd512be7e1a023c1137dd5f2e Mon Sep 17 00:00:00 2001 From: Coen Jacobs Date: Thu, 19 Sep 2024 14:00:02 +0200 Subject: [PATCH 24/24] Minor changes to pass PSR-12 coding standards --- src/Config/Mozart.php | 6 +++--- src/Console/Commands/Compose.php | 2 +- src/Replace/ClassmapReplacer.php | 2 +- src/Replacer.php | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/Config/Mozart.php b/src/Config/Mozart.php index ac02e32f..38f04a7f 100644 --- a/src/Config/Mozart.php +++ b/src/Config/Mozart.php @@ -105,12 +105,12 @@ public function isExcludedPackage(Package $package): bool */ public function getDepDirectory(): string { - return trim($this->depDirectory, DIRECTORY_SEPARATOR).DIRECTORY_SEPARATOR; + return trim($this->depDirectory, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR; } public function getClassmapDirectory(): string { - return trim($this->classmapDir, DIRECTORY_SEPARATOR).DIRECTORY_SEPARATOR; + return trim($this->classmapDir, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR; } public function getDeleteVendorDirectories(): bool @@ -120,7 +120,7 @@ public function getDeleteVendorDirectories(): bool public function getDependencyNamespace(): string { - $namespace = preg_replace("/\\\{2,}$/", "\\", $this->depNamespace."\\"); + $namespace = preg_replace("/\\\{2,}$/", "\\", $this->depNamespace . "\\"); if (empty($namespace)) { throw new Exception('Could not get target dependency namespace'); diff --git a/src/Console/Commands/Compose.php b/src/Console/Commands/Compose.php index 7612719a..98fa1c56 100644 --- a/src/Console/Commands/Compose.php +++ b/src/Console/Commands/Compose.php @@ -39,7 +39,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int $this->workingDir = $workingDir; - $composerFile = $this->workingDir . DIRECTORY_SEPARATOR. 'composer.json'; + $composerFile = $this->workingDir . DIRECTORY_SEPARATOR . 'composer.json'; try { $factory = new PackageFactory(); $package = $factory->createPackage($composerFile); diff --git a/src/Replace/ClassmapReplacer.php b/src/Replace/ClassmapReplacer.php index 14a18f40..27117217 100644 --- a/src/Replace/ClassmapReplacer.php +++ b/src/Replace/ClassmapReplacer.php @@ -1,4 +1,5 @@ replacedClasses)===0) { + if (count($this->replacedClasses) === 0) { return; } @@ -133,7 +133,7 @@ public function replaceParentClassesInDirectory(string $directory): void foreach ($replacedClasses as $original => $replacement) { $contents = preg_replace_callback( - '/(.*)([^a-zA-Z0-9_\x7f-\xff])'. $original . '([^a-zA-Z0-9_\x7f-\xff])/U', + '/(.*)([^a-zA-Z0-9_\x7f-\xff])' . $original . '([^a-zA-Z0-9_\x7f-\xff])/U', function ($matches) use ($replacement) { if (preg_match('/(include|require)/', $matches[0])) { return $matches[0];