Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ Latest
* [#190](https://github.com/cleverage/process-bundle/issues/190) Update quality stack: use Rector `withComposerBased()` sets (removed `SYMFONY_64` / `PHPUNIT_100` sets), declare used Symfony packages and PHPUnit range in composer.json, apply quality tools fixes
* [#145](https://github.com/cleverage/process-bundle/issues/145) Add missing documentations: reference pages for every Task & Transformer, ConditionTrait & GenericTransformer, complete guides and cookbooks. Harmonize and fix existing documentation.
* [#229](https://github.com/cleverage/process-bundle/issues/229) StatCounterTask and AdvancedStatCounterTask pass their input to their output on every execution (they used to output `null`, and AdvancedStatCounterTask was skipped when not logging), so they can be placed anywhere in a branch. Update documentation, add tests.
* [#236](https://github.com/cleverage/process-bundle/issues/236) TransformerTrait: document that any non-empty `#suffix` is accepted on transformer codes (`callback#1`, `callback#reverse`), and anchor the matching regex (an empty suffix is no longer accepted). Update documentation, add tests.

## Fixes
* [#192](https://github.com/cleverage/process-bundle/issues/192) Fix CommandRunnerTask: only pass the `options` option to `Process::setOptions()`, support string `commandline` through `Process::fromShellCommandline()`, validate option types. Update documentation, add tests.
Expand Down
7 changes: 4 additions & 3 deletions docs/reference/traits/transformer_trait.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,15 @@ Allow to hold a list of sub-transformers, configure their options at initializat
- any error thrown by a transformer is wrapped in a `TransformerException` ("Transformation '<code>' have failed:
<original message>"), the original exception being available as previous exception
- as YAML keys must be unique, a suffix starting with `#` can be added to the code to use the same transformer
several times. The convention is `#` followed by digits; the part before the first `#` is used as the transformer
code if it is registered. Example:
several times. Any non-empty suffix is accepted: digits (`callback#1`) or a name describing the step
(`callback#reverse`). The part before the first `#` is used as the transformer code if it is registered (otherwise
the whole code is looked up, and a `MissingTransformerException` is thrown if it is unknown). Example:

```yaml
transformers:
callback#1:
callback: array_filter
callback#2:
callback#reverse:
callback: array_reverse
```

Expand Down
7 changes: 5 additions & 2 deletions src/Transformer/TransformerTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -72,16 +72,19 @@ protected function applyTransformers(array $transformers, mixed $value): mixed
* keys This way you can chain multiple times the same transformer. Without this, it would silently call only the
* 1st one.
*
* Any non-empty suffix starting with "#" is accepted (digits, or a name describing the step): the part before the
* first "#" is used as the transformer code if it is registered.
*
* @example
* transformers:
* callback#1:
* callback: array_filter
* callback#2:
* callback#reverse:
* callback: array_reverse
*/
protected function getCleanedTransfomerCode(string $transformerCode): string
{
$match = preg_match('/([^#]+)(#[\d]+)?/', $transformerCode, $parts);
$match = preg_match('/^([^#]+)#.+$/', $transformerCode, $parts);

if (1 === $match && $this->transformerRegistry->hasTransformer($parts[1])) {
return $parts[1];
Expand Down
110 changes: 110 additions & 0 deletions tests/Transformer/TransformerTraitTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
<?php

declare(strict_types=1);

/*
* This file is part of the CleverAge/ProcessBundle package.
*
* Copyright (c) Clever-Age
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace CleverAge\ProcessBundle\Tests\Transformer;

use CleverAge\ProcessBundle\Exception\MissingTransformerException;
use CleverAge\ProcessBundle\Registry\TransformerRegistry;
use CleverAge\ProcessBundle\Transformer\CallbackTransformer;
use CleverAge\ProcessBundle\Transformer\TransformerTrait;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\TestCase;
use Symfony\Component\OptionsResolver\OptionsResolver;

#[\PHPUnit\Framework\Attributes\CoversTrait(TransformerTrait::class)]
#[\PHPUnit\Framework\Attributes\UsesClass(TransformerRegistry::class)]
#[\PHPUnit\Framework\Attributes\UsesClass(CallbackTransformer::class)]
#[\PHPUnit\Framework\Attributes\UsesClass(MissingTransformerException::class)]
class TransformerTraitTest extends TestCase
{
/**
* @return iterable<string, array{string, string}>
*/
public static function transformerCodeProvider(): iterable
{
yield 'no suffix' => ['callback', 'callback'];
yield 'numeric suffix' => ['callback#1', 'callback'];
yield 'named suffix' => ['callback#reverse', 'callback'];
yield 'suffix containing #' => ['callback#a#b', 'callback'];
yield 'unknown transformer' => ['unknown#1', 'unknown#1'];
yield 'empty suffix' => ['callback#', 'callback#'];
yield 'suffix only' => ['#1', '#1'];
}

#[DataProvider('transformerCodeProvider')]
public function testCleanedTransformerCode(string $code, string $expected): void
{
self::assertSame($expected, $this->createHolder()->cleanCode($code));
}

public function testSameTransformerCanBeChainedWithSuffixes(): void
{
$holder = $this->createHolder();

$transformers = $holder->resolve([
'callback#upper' => ['callback' => 'strtoupper'],
'callback#reverse' => ['callback' => 'strrev'],
'callback#1' => ['callback' => 'trim'],
]);

self::assertSame('CBA', $holder->apply($transformers, ' abc'));
}

public function testEmptySuffixIsAnUnknownTransformer(): void
{
$this->expectException(MissingTransformerException::class);

$this->createHolder()->resolve(['callback#' => ['callback' => 'trim']]);
}

private function createHolder(): object
{
$registry = new TransformerRegistry();
$registry->addTransformer(new CallbackTransformer());

return new class($registry) {
use TransformerTrait;

public function __construct(TransformerRegistry $transformerRegistry)
{
$this->transformerRegistry = $transformerRegistry;
}

public function cleanCode(string $code): string
{
return $this->getCleanedTransfomerCode($code);
}

/**
* @param array<string, mixed> $transformers
*
* @return array<string, \Closure>
*/
public function resolve(array $transformers): array
{
$resolver = new OptionsResolver();
$this->configureTransformersOptions($resolver);

return $resolver->resolve(['transformers' => $transformers])['transformers'];
}

/**
* @param array<string, \Closure> $transformers
*/
public function apply(array $transformers, mixed $value): mixed
{
return $this->applyTransformers($transformers, $value);
}
};
}
}
Loading