Skip to content

Commit 28f0bda

Browse files
committed
refactor: DocsCommand
1 parent 1d21347 commit 28f0bda

5 files changed

Lines changed: 201 additions & 170 deletions

File tree

docs/api/commands.rst

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,9 @@ resolution, configuration fallback, PSR-4 lookup, and child-command dispatch.
4949
- ``dev-tools:sync``
5050
- Synchronizes consumer-facing scripts, automation assets, and packaged
5151
skills.
52-
* - ``FastForward\DevTools\Console\Command\GitIgnoreCommand``
53-
- ``gitignore``
54-
- Merges and synchronizes .gitignore files.
55-
* - ``FastForward\DevTools\Console\Command\LicenseCommand``
56-
- ``license``
57-
- Generates a LICENSE file from composer.json license information.
52+
* - ``FastForward\DevTools\Console\Command\GitIgnoreCommand``
53+
- ``gitignore``
54+
- Merges and synchronizes .gitignore files.
55+
* - ``FastForward\DevTools\Console\Command\LicenseCommand``
56+
- ``license``
57+
- Generates a LICENSE file from composer.json license information.

docs/api/phpunit-support.rst

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -19,18 +19,18 @@ The packaged test configuration includes a small integration layer under
1919
* - ``FastForward\DevTools\PhpUnit\Event\TestSuite\ByPassfinalsStartedSubscriber``
2020
- Enables ``DG\BypassFinals``
2121
- Allows tests to work with final constructs.
22-
* - ``FastForward\DevTools\PhpUnit\Event\TestSuite\JoliNotifExecutionFinishedSubscriber``
23-
- Sends desktop notifications
24-
- Summarizes pass, failure, error, runtime, and memory data.
25-
* - ``FastForward\DevTools\PhpUnit\Coverage\CoverageSummaryLoaderInterface``
26-
- Loads PHPUnit coverage reports
27-
- Contract for loading serialized PHP coverage data.
28-
* - ``FastForward\DevTools\PhpUnit\Coverage\CoverageSummaryLoader``
29-
- Loads PHPUnit coverage reports
30-
- Implementation that reads ``coverage-php`` output.
31-
* - ``FastForward\DevTools\PhpUnit\Coverage\CoverageSummary``
32-
- Represents line coverage metrics
33-
- Provides executed lines, total executable lines, and percentage calculations.
22+
* - ``FastForward\DevTools\PhpUnit\Event\TestSuite\JoliNotifExecutionFinishedSubscriber``
23+
- Sends desktop notifications
24+
- Summarizes pass, failure, error, runtime, and memory data.
25+
* - ``FastForward\DevTools\PhpUnit\Coverage\CoverageSummaryLoaderInterface``
26+
- Loads PHPUnit coverage reports
27+
- Contract for loading serialized PHP coverage data.
28+
* - ``FastForward\DevTools\PhpUnit\Coverage\CoverageSummaryLoader``
29+
- Loads PHPUnit coverage reports
30+
- Implementation that reads ``coverage-php`` output.
31+
* - ``FastForward\DevTools\PhpUnit\Coverage\CoverageSummary``
32+
- Represents line coverage metrics
33+
- Provides executed lines, total executable lines, and percentage calculations.
3434

3535
Coverage Report Loading
3636
-----------------------

resources/phpdocumentor.xml

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,20 @@
55
xmlns="https://www.phpdoc.org"
66
xsi:noNamespaceSchemaLocation="https://raw.githubusercontent.com/phpDocumentor/phpDocumentor/master/data/xsd/phpdoc.xsd"
77
>
8-
<title>%%TITLE%%</title>
9-
<template name="%%TEMPLATE%%" />
8+
<title>{{ title }}</title>
9+
<template name="{{ template }}" />
1010

1111
<paths>
12-
<output>%%TARGET%%</output>
13-
<cache>%%WORKING_DIRECTORY%%/tmp/cache/phpdoc</cache>
12+
<output>{{ target }}</output>
13+
<cache>{{ cacheDir }}</cache>
1414
</paths>
1515

1616
<version number="latest">
1717
<api>
18-
<source dsn="%%WORKING_DIRECTORY%%">
19-
%%PATHS%%
18+
<source dsn="{{ workingDirectory }}">
19+
{% for path in paths %}
20+
<path>{{ path }}</path>
21+
{% endfor %}
2022
</source>
2123
<ignore hidden="true" symlinks="true">
2224
<path>tests/**/*</path>
@@ -27,11 +29,11 @@
2729
<extensions>
2830
<extension>php</extension>
2931
</extensions>
30-
<default-package-name>%%DEFAULT_PACKAGE_NAME%%</default-package-name>
32+
<default-package-name>{{ defaultPackageName }}</default-package-name>
3133
</api>
3234
<guide>
33-
<source dsn="%%WORKING_DIRECTORY%%">
34-
<path>%%GUIDE_PATH%%</path>
35+
<source dsn="{{ workingDirectory }}">
36+
<path>{{ guidePath }}</path>
3537
</source>
3638
<output>guide</output>
3739
</guide>

src/Console/Command/DocsCommand.php

Lines changed: 69 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -18,16 +18,21 @@
1818

1919
namespace FastForward\DevTools\Console\Command;
2020

21+
use FastForward\DevTools\Composer\Json\ComposerJsonInterface;
22+
use Random\Engine;
23+
use Twig\Environment;
24+
use function Safe\getcwd;
25+
use Composer\Command\BaseCommand;
2126
use FastForward\DevTools\Composer\Json\ComposerJson;
27+
use FastForward\DevTools\Filesystem\FilesystemInterface;
28+
use FastForward\DevTools\Process\ProcessBuilderInterface;
29+
use FastForward\DevTools\Process\ProcessQueueInterface;
30+
use FastForward\DevTools\Template\EngineInterface;
2231
use Symfony\Component\Console\Attribute\AsCommand;
2332
use Symfony\Component\Console\Input\InputInterface;
2433
use Symfony\Component\Console\Input\InputOption;
2534
use Symfony\Component\Console\Output\OutputInterface;
26-
use Symfony\Component\Filesystem\Filesystem;
27-
use Symfony\Component\Filesystem\Path;
28-
use Symfony\Component\Process\Process;
2935

30-
use function Safe\file_get_contents;
3136
use function array_map;
3237
use function implode;
3338
use function ltrim;
@@ -42,17 +47,25 @@
4247
description: 'Generates API documentation.',
4348
help: 'This command generates API documentation using phpDocumentor.',
4449
)]
45-
final class DocsCommand extends AbstractCommand
50+
final class DocsCommand extends BaseCommand
4651
{
4752
/**
48-
* @param ComposerJson $composerJson
49-
* @param Filesystem $filesystem
53+
* Creates a new DocsCommand instance.
54+
*
55+
* @param ProcessBuilderInterface $processBuilder the process builder for executing phpDocumentor
56+
* @param ProcessQueueInterface $processQueue the process queue for managing execution
57+
* @param Environment $renderer
58+
* @param FilesystemInterface $filesystem the filesystem for handling file operations
59+
* @param ComposerJsonInterface $composerJson the composer.json handler for accessing project metadata
5060
*/
5161
public function __construct(
52-
private readonly ComposerJson $composerJson,
53-
Filesystem $filesystem
62+
private readonly ProcessBuilderInterface $processBuilder,
63+
private readonly ProcessQueueInterface $processQueue,
64+
private readonly Environment $renderer,
65+
private readonly FilesystemInterface $filesystem,
66+
private readonly ComposerJsonInterface $composerJson,
5467
) {
55-
return parent::__construct($filesystem);
68+
parent::__construct();
5669
}
5770

5871
/**
@@ -85,6 +98,12 @@ protected function configure(): void
8598
mode: InputOption::VALUE_OPTIONAL,
8699
description: 'Path to the template directory for the generated HTML documentation.',
87100
default: 'vendor/fast-forward/phpdoc-bootstrap-template',
101+
)
102+
->addOption(
103+
name: 'cache-dir',
104+
mode: InputOption::VALUE_OPTIONAL,
105+
description: 'Path to the cache directory for phpDocumentor.',
106+
default: 'tmp/cache/phpdoc',
88107
);
89108
}
90109

@@ -103,28 +122,34 @@ protected function execute(InputInterface $input, OutputInterface $output): int
103122
{
104123
$output->writeln('<info>Generating API documentation...</info>');
105124

106-
$source = $this->getAbsolutePath($input->getOption('source'));
125+
$source = $this->filesystem->getAbsolutePath($input->getOption('source'));
107126

108127
if (! $this->filesystem->exists($source)) {
109128
$output->writeln(\sprintf('<error>Source directory not found: %s</error>', $source));
110129

111130
return self::FAILURE;
112131
}
113132

114-
$target = $this->getAbsolutePath($input->getOption('target'));
115-
$template = $input->getOption('template');
133+
$target = $this->filesystem->getAbsolutePath($input->getOption('target'));
134+
$cacheDir = $this->filesystem->getAbsolutePath($input->getOption('cache-dir'));
116135

117-
$htmlConfig = $this->createPhpDocumentorConfig(source: $source, target: $target, template: $template);
136+
$config = $this->createPhpDocumentorConfig(
137+
source: $source,
138+
target: $target,
139+
template: $input->getOption('template'),
140+
cacheDir: $cacheDir
141+
);
118142

119-
$command = new Process([
120-
$this->getAbsolutePath('vendor/bin/phpdoc'),
121-
'--config',
122-
$htmlConfig,
123-
'--markers',
124-
'TODO,FIXME,BUG,HACK',
125-
]);
143+
$phpdoc = $this->processBuilder
144+
->withArgument('--config', $config)
145+
->withArgument('--ansi')
146+
->withArgument('--no-progress')
147+
->withArgument('--markers', 'TODO,FIXME,BUG,HACK')
148+
->build('vendor/bin/phpdoc');
149+
150+
$this->processQueue->add($phpdoc);
126151

127-
return parent::runProcess($command, $output);
152+
return $this->processQueue->run($output);
128153
}
129154

130155
/**
@@ -133,46 +158,34 @@ protected function execute(InputInterface $input, OutputInterface $output): int
133158
* @param string $source the source directory for the generated documentation
134159
* @param string $target the output directory for the generated documentation
135160
* @param string $template the phpDocumentor template name or path
161+
* @param string $cacheDir the cache directory for phpDocumentor
136162
*
137163
* @return string the absolute path to the generated configuration
138164
*/
139-
private function createPhpDocumentorConfig(string $source, string $target, string $template): string
165+
private function createPhpDocumentorConfig(string $source, string $target, string $template, string $cacheDir): string
140166
{
141-
$workingDirectory = $this->getCurrentWorkingDirectory();
142-
143-
$templateFile = parent::getDevToolsFile('resources/phpdocumentor.xml');
144-
145-
$configDirectory = $this->getAbsolutePath('tmp/cache/phpdoc');
146-
$configFile = $configDirectory . '/phpdocumentor.xml';
147-
148-
if (! $this->filesystem->exists($configDirectory)) {
149-
$this->filesystem->mkdir($configDirectory);
150-
}
151-
167+
$workingDirectory = \getcwd();
152168
$psr4Namespaces = $this->composerJson->getAutoload();
153-
$paths = implode("\n", array_map(
154-
fn(string $path): string => \sprintf(
155-
'<path>%s</path>',
156-
ltrim(str_replace($workingDirectory, '', $path), '/')
157-
),
158-
$psr4Namespaces,
159-
));
169+
$guidePath = $this->filesystem->makePathRelative($source);
170+
$defaultPackageName = array_key_first($psr4Namespaces) ?: '';
160171

161-
$guidePath = Path::makeRelative($source, $workingDirectory);
172+
$content = $this->renderer->render('phpdocumentor.xml', [
173+
'title' => $this->composerJson->getPackageName(),
174+
'template' => $template,
175+
'target' => $target,
176+
'cacheDir' => $cacheDir,
177+
'workingDirectory' => $workingDirectory,
178+
'paths' => $psr4Namespaces,
179+
'guidePath' => $guidePath,
180+
'defaultPackageName' => rtrim($defaultPackageName, '\\'),
181+
]);
162182

163-
$defaultPackageName = array_key_first($psr4Namespaces) ?: '';
164-
$templateContents = file_get_contents($templateFile);
165-
166-
$this->filesystem->dumpFile($configFile, strtr($templateContents, [
167-
'%%TITLE%%' => $this->composerJson->getPackageDescription(),
168-
'%%TEMPLATE%%' => $template,
169-
'%%TARGET%%' => $target,
170-
'%%WORKING_DIRECTORY%%' => $workingDirectory,
171-
'%%PATHS%%' => $paths,
172-
'%%GUIDE_PATH%%' => $guidePath,
173-
'%%DEFAULT_PACKAGE_NAME%%' => $defaultPackageName,
174-
]));
175-
176-
return $configFile;
183+
$this->filesystem->dumpFile(
184+
filename: 'phpdocumentor.xml',
185+
content: $content,
186+
path: $cacheDir,
187+
);
188+
189+
return $this->filesystem->getAbsolutePath('phpdocumentor.xml', $cacheDir);
177190
}
178191
}

0 commit comments

Comments
 (0)