Skip to content

Commit

Permalink
new cli alchemy:rendition-factory:config to generate doc or validat…
Browse files Browse the repository at this point in the history
…e configuration file.

mandatory documentation for all modules.
refacto.
  • Loading branch information
jygaulier committed Dec 5, 2024
1 parent 4f417f8 commit 82ea1d5
Show file tree
Hide file tree
Showing 32 changed files with 604 additions and 449 deletions.
50 changes: 25 additions & 25 deletions lib/php/rendition-factory-bundle/Resources/config/services.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -45,54 +45,54 @@ services:
tags:
- { name: !php/const Alchemy\RenditionFactory\Transformer\TransformerModuleInterface::TAG }

# FFMpeg "formats"
Alchemy\RenditionFactory\Transformer\Video\FFMpeg\Format\JpegFormat:
# Output "formats"
Alchemy\RenditionFactory\Format\JpegFormat:
tags:
- { name: !php/const Alchemy\RenditionFactory\Transformer\Video\FFMpeg\Format\FormatInterface::TAG }
- { name: !php/const Alchemy\RenditionFactory\Format\FormatInterface::TAG }

Alchemy\RenditionFactory\Transformer\Video\FFMpeg\Format\MkvFormat:
Alchemy\RenditionFactory\Format\MkvFormat:
tags:
- { name: !php/const Alchemy\RenditionFactory\Transformer\Video\FFMpeg\Format\FormatInterface::TAG }
- { name: !php/const Alchemy\RenditionFactory\Format\FormatInterface::TAG }

Alchemy\RenditionFactory\Transformer\Video\FFMpeg\Format\Mpeg4Format:
Alchemy\RenditionFactory\Format\Mpeg4Format:
tags:
- { name: !php/const Alchemy\RenditionFactory\Transformer\Video\FFMpeg\Format\FormatInterface::TAG }
- { name: !php/const Alchemy\RenditionFactory\Format\FormatInterface::TAG }

Alchemy\RenditionFactory\Transformer\Video\FFMpeg\Format\MpegFormat:
Alchemy\RenditionFactory\Format\MpegFormat:
tags:
- { name: !php/const Alchemy\RenditionFactory\Transformer\Video\FFMpeg\Format\FormatInterface::TAG }
- { name: !php/const Alchemy\RenditionFactory\Format\FormatInterface::TAG }

Alchemy\RenditionFactory\Transformer\Video\FFMpeg\Format\QuicktimeFormat:
Alchemy\RenditionFactory\Format\QuicktimeFormat:
tags:
- { name: !php/const Alchemy\RenditionFactory\Transformer\Video\FFMpeg\Format\FormatInterface::TAG }
- { name: !php/const Alchemy\RenditionFactory\Format\FormatInterface::TAG }

Alchemy\RenditionFactory\Transformer\Video\FFMpeg\Format\WebmFormat:
Alchemy\RenditionFactory\Format\WebmFormat:
tags:
- { name: !php/const Alchemy\RenditionFactory\Transformer\Video\FFMpeg\Format\FormatInterface::TAG }
- { name: !php/const Alchemy\RenditionFactory\Format\FormatInterface::TAG }

Alchemy\RenditionFactory\Transformer\Video\FFMpeg\Format\AnimatedGifFormat:
Alchemy\RenditionFactory\Format\AnimatedGifFormat:
tags:
- { name: !php/const Alchemy\RenditionFactory\Transformer\Video\FFMpeg\Format\FormatInterface::TAG }
- { name: !php/const Alchemy\RenditionFactory\Format\FormatInterface::TAG }

Alchemy\RenditionFactory\Transformer\Video\FFMpeg\Format\AnimatedPngFormat:
Alchemy\RenditionFactory\Format\AnimatedPngFormat:
tags:
- { name: !php/const Alchemy\RenditionFactory\Transformer\Video\FFMpeg\Format\FormatInterface::TAG }
- { name: !php/const Alchemy\RenditionFactory\Format\FormatInterface::TAG }

Alchemy\RenditionFactory\Transformer\Video\FFMpeg\Format\AnimatedWebpFormat:
Alchemy\RenditionFactory\Format\AnimatedWebpFormat:
tags:
- { name: !php/const Alchemy\RenditionFactory\Transformer\Video\FFMpeg\Format\FormatInterface::TAG }
- { name: !php/const Alchemy\RenditionFactory\Format\FormatInterface::TAG }

Alchemy\RenditionFactory\Transformer\Video\FFMpeg\Format\WavFormat:
Alchemy\RenditionFactory\Format\WavFormat:
tags:
- { name: !php/const Alchemy\RenditionFactory\Transformer\Video\FFMpeg\Format\FormatInterface::TAG }
- { name: !php/const Alchemy\RenditionFactory\Format\FormatInterface::TAG }

Alchemy\RenditionFactory\Transformer\Video\FFMpeg\Format\AacFormat:
Alchemy\RenditionFactory\Format\AacFormat:
tags:
- { name: !php/const Alchemy\RenditionFactory\Transformer\Video\FFMpeg\Format\FormatInterface::TAG }
- { name: !php/const Alchemy\RenditionFactory\Format\FormatInterface::TAG }

Alchemy\RenditionFactory\Transformer\Video\FFMpeg\Format\Mp3Format:
Alchemy\RenditionFactory\Format\Mp3Format:
tags:
- { name: !php/const Alchemy\RenditionFactory\Transformer\Video\FFMpeg\Format\FormatInterface::TAG }
- { name: !php/const Alchemy\RenditionFactory\Format\FormatInterface::TAG }


Imagine\Imagick\Imagine: ~
Expand Down
117 changes: 38 additions & 79 deletions lib/php/rendition-factory/src/Command/ConfigCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,15 @@

use Alchemy\RenditionFactory\Config\YamlLoader;
use Alchemy\RenditionFactory\DTO\FamilyEnum;
use Alchemy\RenditionFactory\Transformer\DocumentationTree;
use Alchemy\RenditionFactory\Transformer\Documentation;
use Alchemy\RenditionFactory\Transformer\TransformerModuleInterface;
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
use Symfony\Component\Config\Definition\Dumper\YamlReferenceDumper;
use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
use Symfony\Component\Config\Definition\Processor;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\DependencyInjection\Attribute\TaggedLocator;
use Symfony\Component\DependencyInjection\ServiceLocator;
Expand All @@ -35,130 +34,90 @@ protected function configure(): void
{
parent::configure();

$this->addArgument('build-config', InputArgument::OPTIONAL, 'A build config YAML file to validate')
->addOption('module', 'm', InputOption::VALUE_REQUIRED, 'Display optiond for a specific module')
->setHelp('Display the options for a module, or validate a build-config YAML file.')
$this->addArgument('config', InputArgument::OPTIONAL, 'A build config YAML file to validate')
->setHelp('Display rendition modules documentation, or validate a config file.')
;
}

protected function execute(InputInterface $input, OutputInterface $output): int
{
if ($transformerName = $input->getOption('module')) {
/** @var TransformerModuleInterface $transformer */
$transformer = $this->transformers->get($transformerName);
$output->writeln($this->getTransformerDocumentation($transformerName, $transformer));
}

if ($buildConfigPath = $input->getArgument('build-config')) {
$buildConfig = $this->yamlLoader->load($buildConfigPath);
if (null !== ($configPath = $input->getArgument('config'))) {
$config = $this->yamlLoader->load($configPath);

foreach (FamilyEnum::cases() as $family) {
$familyConfig = $buildConfig->getFamily($family);
$familyConfig = $config->getFamily($family);
if (null === $familyConfig) {
continue;
}

$output->writeln(sprintf('# Family `%s`:', $family->name));
foreach ($familyConfig->getTransformations() as $transformation) {
$transformerName = $transformation->getModule();
// $output->writeln(sprintf(' - %s', $transformerName));

/** @var TransformerModuleInterface $transformer */
$transformer = $this->transformers->get($transformerName);
$output->writeln($this->getTransformerDocumentation($transformerName, $transformer));

$this->checkTransformerConfiguration($transformerName, $transformer, $transformation->getOptions());
try {
$this->checkTransformerConfiguration($transformerName, $transformer, $transformation->asArray());
} catch (\Throwable $e) {
$msg = sprintf("Error in module \"%s\"\n%s", $transformerName, $e->getMessage());
throw new InvalidConfigurationException($msg);
}
}
}
$output->writeln('Configuration is valid.');
} else {
foreach ($this->transformers->getProvidedServices() as $transformerName => $transformerFqcn) {

/** @var TransformerModuleInterface $transformer */
$transformer = $this->transformers->get($transformerName);
$output->writeln($this->getTransformerDocumentation($transformerName, $transformer));
}
}

return 0;
}

private function getTransformerDocumentation(string $transformerName, TransformerModuleInterface $transformer): string
{
$docToText = function(DocumentationTree $documentation, int $depth=0) use (&$docToText): string {
$docToText = function (Documentation $documentation, int $depth = 0) use (&$docToText): string {

$text = '';
if($t = $documentation->getHeader()) {
$text .= $t . "\n";
if ($t = $documentation->getHeader()) {
$text .= $t."\n";
}

$treeBuilder = $documentation->getTreeBuilder();
$node = $treeBuilder->buildTree();
$dumper = new YamlReferenceDumper();

$t = $dumper->dumpNode($node);
$t = preg_replace("#^root:(\n( {4})?|\s+\[])#", "-\n", (string) $t);
$t = str_replace("\n\n", "\n", $t);
$t = str_replace("\n", "\n ", $t);
$t = preg_replace("#^root:($|(\s+)\[]$)#m", "-\n", (string) $t);
$t = preg_replace("#\n+#", "\n", $t);
$t = trim($t);

$text .= "```yaml\n" . $t . "\n```\n";
$text .= "```yaml\n".$t."\n```\n";

foreach ($documentation->getChildren() as $child) {
$text .= $docToText($child, $depth+1);
if ($t = $documentation->getFooter()) {
$text .= $t."\n";
}

if($t = $documentation->getFooter()) {
$text .= $t . "\n";
foreach ($documentation->getChildren() as $child) {
$text .= $docToText($child, $depth + 1);
}

return $text;
};

$documentation = $transformer->getDocumentation();

$doc = "\n\n## $transformerName transformer module\n";
if (method_exists($transformer, 'getDocumentation')) {
$documentation = $transformer->getDocumentation();
$doc .= $docToText($documentation);
}

return $doc;
return "## `$transformerName` transformer module\n".$docToText($documentation);
}

private function checkTransformerConfiguration(string $transformerName, TransformerModuleInterface $transformer, array $options): void
{
if (method_exists($transformer, 'getDocumentation')) {
$documentation = $transformer->getDocumentation();
$treeBuilder = $documentation->getTreeBuilder();

$processor = new Processor();
$processor->process($treeBuilder->buildTree(), ['root' => $options]);
}
}

private function no_getTransformerDocumentation(string $fqcn, string $transformerName, TransformerModuleInterface $transformer): string
{
$doc = "\n\n## $transformerName\n";

$reflectionClass = new \ReflectionClass($fqcn);
if ($reflectionClass->hasMethod('getDocumentationHeader') && $reflectionClass->getMethod('getDocumentationHeader')->class == $fqcn) {
$doc .= $transformer->getDocumentationHeader()."\n";
}

if (method_exists($transformer, 'buildConfiguration')) {
$treeBuilder = new TreeBuilder('root');
$transformer->buildConfiguration($treeBuilder->getRootNode()->children());

$node = $treeBuilder->buildTree();
$dumper = new YamlReferenceDumper();

$t = $dumper->dumpNode($node);
$t = preg_replace("#^root:(\n( {4})?|\s+\[])#", "-\n", (string) $t);
$t = str_replace("\n\n", "\n", $t);
$t = str_replace("\n", "\n ", $t);
// $t = preg_replace("#^root:(\n( {4})?|\s+\[])#", '', (string)$t);
// $t = preg_replace("#\n {4}#", "\n", $t);
// $t = preg_replace("#\n\n#", "\n", $t);
// $t = trim(preg_replace("#^\n+#", '', $t));

$doc .= "```yaml\n".$t."```\n";
}

if ($reflectionClass->hasMethod('getDocumentationFooter') && $reflectionClass->getMethod('getDocumentationFooter')->class == $fqcn) {
$doc .= $transformer->getDocumentationFooter()."\n";
}
$documentation = $transformer->getDocumentation();
$treeBuilder = $documentation->getTreeBuilder();

return $doc;
$processor = new Processor();
$processor->process($treeBuilder->buildTree(), ['root' => $options]);
}
}
5 changes: 2 additions & 3 deletions lib/php/rendition-factory/src/Config/YamlLoader.php
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,7 @@ private function parseFamilyConfig(array $data): FamilyBuildConfig

$transformations = [];
foreach ($data['transformations'] as $transformation) {
if ($transformation['enabled'] ?? true) {
$transformations[] = $this->parseTransformation($transformation);
}
$transformations[] = $this->parseTransformation($transformation);
}

return new FamilyBuildConfig($transformations, $data['normalization'] ?? []);
Expand All @@ -72,6 +70,7 @@ private function parseTransformation(array $transformation): Transformation
{
return new Transformation(
$transformation['module'],
$transformation['enabled'] ?? true,
$transformation['options'] ?? [],
$transformation['description'] ?? null
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,13 @@ public function getTransformations(): array
return $this->transformations;
}

public function getEnabledTransformations(): array
{
return array_filter($this->transformations, function (Transformation $transformation) {
return $transformation->isEnabled();
});
}

public function getNormalization(): array
{
return $this->normalization;
Expand Down
16 changes: 16 additions & 0 deletions lib/php/rendition-factory/src/DTO/BuildConfig/Transformation.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
{
public function __construct(
private string $module,
private bool $enabled,
private array $options,
private ?string $description,
) {
Expand All @@ -25,4 +26,19 @@ public function getOptions(): array
{
return $this->options;
}

public function isEnabled(): bool
{
return $this->enabled;
}

public function asArray(): array
{
return [
'module' => $this->module,
'enabled' => $this->enabled,
'options' => $this->options,
'description' => $this->description,
];
}
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
<?php

namespace Alchemy\RenditionFactory\Transformer\Video\FFMpeg\Format;
namespace Alchemy\RenditionFactory\Format;

use Alchemy\RenditionFactory\DTO\FamilyEnum;
use Alchemy\RenditionFactory\Transformer\Video\FFMpeg\Format\Audio\Aac;
use Alchemy\RenditionFactory\Format\Audio\Aac;

class AacFormat implements FormatInterface
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?php

namespace Alchemy\RenditionFactory\Transformer\Video\FFMpeg\Format;
namespace Alchemy\RenditionFactory\Format;

use Alchemy\RenditionFactory\DTO\FamilyEnum;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?php

namespace Alchemy\RenditionFactory\Transformer\Video\FFMpeg\Format;
namespace Alchemy\RenditionFactory\Format;

use Alchemy\RenditionFactory\DTO\FamilyEnum;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?php

namespace Alchemy\RenditionFactory\Transformer\Video\FFMpeg\Format;
namespace Alchemy\RenditionFactory\Format;

use Alchemy\RenditionFactory\DTO\FamilyEnum;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* This file replaces FFMpeg\Format\Audio\aac because alpine lacks libfdk
*/

namespace Alchemy\RenditionFactory\Transformer\Video\FFMpeg\Format\Audio;
namespace Alchemy\RenditionFactory\Format\Audio;

use FFMpeg\Format\Audio\DefaultAudio;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?php

namespace Alchemy\RenditionFactory\Transformer\Video\FFMpeg\Format;
namespace Alchemy\RenditionFactory\Format;

use Alchemy\RenditionFactory\DTO\FamilyEnum;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?php

namespace Alchemy\RenditionFactory\Transformer\Video\FFMpeg\Format;
namespace Alchemy\RenditionFactory\Format;

use Alchemy\RenditionFactory\DTO\FamilyEnum;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?php

namespace Alchemy\RenditionFactory\Transformer\Video\FFMpeg\Format;
namespace Alchemy\RenditionFactory\Format;

use Alchemy\RenditionFactory\DTO\FamilyEnum;
use FFMpeg\Format\Video\X264;
Expand Down
Loading

0 comments on commit 82ea1d5

Please sign in to comment.