Skip to content

Commit 26c4f31

Browse files
authored
Merge pull request #111 from php-etl/feature/custom-action
Integration of custom actions
2 parents fe53fd3 + 436885f commit 26c4f31

File tree

23 files changed

+818
-18
lines changed

23 files changed

+818
-18
lines changed

.github/workflows/phpstan-5.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name: PHPStan level 5
22
on: push
33
jobs:
4-
phpstan:
4+
phpstan5:
55
runs-on: ubuntu-latest
66
steps:
77
- uses: actions/checkout@v3

.github/workflows/phpstan-6.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name: PHPStan level 6
22
on: push
33
jobs:
4-
phpstan:
4+
phpstan6:
55
runs-on: ubuntu-latest
66
steps:
77
- uses: actions/checkout@v3

.github/workflows/phpstan-7.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name: PHPStan level 7
22
on: push
33
jobs:
4-
phpstan:
4+
phpstan7:
55
runs-on: ubuntu-latest
66
steps:
77
- uses: actions/checkout@v3

.github/workflows/phpstan-8.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name: PHPStan level 8
22
on: push
33
jobs:
4-
phpstan:
4+
phpstan8:
55
runs-on: ubuntu-latest
66
steps:
77
- uses: actions/checkout@v3

composer.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,10 @@
111111
"Kiboko\\Component\\Satellite\\Plugin\\FTP\\Service",
112112
"Kiboko\\Component\\Satellite\\Plugin\\Batching\\Service",
113113
"Kiboko\\Component\\Satellite\\Plugin\\Filtering\\Service"
114+
],
115+
"actions": [
116+
"Kiboko\\Component\\Satellite\\Action\\SFTP\\Service",
117+
"Kiboko\\Component\\Satellite\\Action\\Custom\\Service"
114118
]
115119
}
116120
},
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Kiboko\Component\Satellite\Action\Custom\Builder;
6+
7+
use Kiboko\Component\Satellite\Action\SFTP\Builder\ActionBuilderInterface;
8+
use PhpParser\Node;
9+
10+
final class Action implements ActionBuilderInterface
11+
{
12+
private ?Node\Expr $logger = null;
13+
private ?Node\Expr $state = null;
14+
15+
public function __construct(private readonly Node\Expr $service, private readonly string $containerNamespace)
16+
{
17+
}
18+
19+
public function withLogger(Node\Expr $logger): self
20+
{
21+
$this->logger = $logger;
22+
23+
return $this;
24+
}
25+
26+
public function withState(Node\Expr $state): self
27+
{
28+
$this->state = $state;
29+
30+
return $this;
31+
}
32+
33+
public function getNode(): Node
34+
{
35+
return new Node\Expr\MethodCall(
36+
var: new Node\Expr\New_(
37+
class: new Node\Name\FullyQualified($this->containerNamespace)
38+
),
39+
name: new Node\Identifier('get'),
40+
args: [
41+
new Node\Arg(
42+
$this->service
43+
),
44+
]
45+
);
46+
}
47+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Kiboko\Component\Satellite\Action\Custom;
6+
7+
use Kiboko\Component\Satellite\DependencyInjection\Configuration\ServicesConfiguration;
8+
use Kiboko\Contract\Configurator\ActionConfigurationInterface;
9+
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
10+
11+
use function Kiboko\Component\SatelliteToolbox\Configuration\asExpression;
12+
use function Kiboko\Component\SatelliteToolbox\Configuration\isExpression;
13+
14+
final class Configuration implements ActionConfigurationInterface
15+
{
16+
public function getConfigTreeBuilder(): TreeBuilder
17+
{
18+
$builder = new TreeBuilder('custom');
19+
/* @phpstan-ignore-next-line */
20+
$builder->getRootNode()
21+
->children()
22+
->arrayNode('expression_language')
23+
->scalarPrototype()->end()
24+
->end()
25+
->append((new ServicesConfiguration())->getConfigTreeBuilder()->getRootNode())
26+
->scalarNode('use')
27+
->isRequired()
28+
->end()
29+
->arrayNode('parameters')
30+
->useAttributeAsKey('keyparam')
31+
->scalarPrototype()
32+
->cannotBeEmpty()
33+
->validate()
34+
->ifTrue(isExpression())
35+
->then(asExpression())
36+
->end()
37+
->end()
38+
->end()
39+
->end()
40+
;
41+
42+
return $builder;
43+
}
44+
}
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Kiboko\Component\Satellite\Action\Custom\Factory;
6+
7+
use Kiboko\Component\Packaging;
8+
use Kiboko\Component\Satellite\Action\Custom;
9+
use Kiboko\Component\Satellite\Action\Custom\Configuration;
10+
use Kiboko\Component\Satellite\DependencyInjection\SatelliteDependencyInjection;
11+
use Kiboko\Component\Satellite\ExpressionLanguage as Satellite;
12+
use Kiboko\Contract\Configurator;
13+
use Symfony\Component\Config\Definition\ConfigurationInterface;
14+
use Symfony\Component\Config\Definition\Exception as Symfony;
15+
use Symfony\Component\Config\Definition\Processor;
16+
use Symfony\Component\DependencyInjection\Dumper\PhpDumper;
17+
use Symfony\Component\ExpressionLanguage\ExpressionLanguage;
18+
use Symfony\Component\String\ByteString;
19+
20+
use function Kiboko\Component\SatelliteToolbox\Configuration\compileValueWhenExpression;
21+
22+
class Action implements Configurator\FactoryInterface
23+
{
24+
private readonly Processor $processor;
25+
private readonly ConfigurationInterface $configuration;
26+
27+
public function __construct(
28+
private readonly ExpressionLanguage $interpreter = new Satellite\ExpressionLanguage(),
29+
private readonly array $providers = [],
30+
) {
31+
$this->processor = new Processor();
32+
$this->configuration = new Configuration();
33+
}
34+
35+
public function configuration(): ConfigurationInterface
36+
{
37+
return $this->configuration;
38+
}
39+
40+
/**
41+
* @throws Configurator\ConfigurationExceptionInterface
42+
*/
43+
public function normalize(array $config): array
44+
{
45+
try {
46+
return $this->processor->processConfiguration($this->configuration, $config);
47+
} catch (Symfony\InvalidTypeException|Symfony\InvalidConfigurationException $exception) {
48+
throw new Configurator\InvalidConfigurationException($exception->getMessage(), 0, $exception);
49+
}
50+
}
51+
52+
public function validate(array $config): bool
53+
{
54+
try {
55+
$this->processor->processConfiguration($this->configuration, $config);
56+
57+
return true;
58+
} catch (Symfony\InvalidTypeException|Symfony\InvalidConfigurationException) {
59+
return false;
60+
}
61+
}
62+
63+
/**
64+
* @throws Configurator\ConfigurationExceptionInterface
65+
*/
66+
public function compile(array $config): Repository\Action
67+
{
68+
$containerName = sprintf('ProjectServiceContainer%s', ByteString::fromRandom(8)->toString());
69+
70+
$builder = new Custom\Builder\Action(
71+
compileValueWhenExpression($this->interpreter, $config['use']),
72+
sprintf('GyroscopsGenerated\\%s', $containerName),
73+
);
74+
75+
$container = (new SatelliteDependencyInjection(...$this->providers))($config);
76+
77+
$repository = new Repository\Action($builder);
78+
79+
$dumper = new PhpDumper($container);
80+
$repository->addFiles(
81+
new Packaging\File(
82+
sprintf('%s.php', $containerName),
83+
new Packaging\Asset\InMemory(
84+
$dumper->dump(['class' => $containerName, 'namespace' => 'GyroscopsGenerated'])
85+
)
86+
),
87+
);
88+
89+
return $repository;
90+
}
91+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Kiboko\Component\Satellite\Action\Custom\Factory\Repository;
6+
7+
use Kiboko\Component\Satellite\Action\Custom;
8+
use Kiboko\Contract\Configurator;
9+
10+
final class Action implements Configurator\RepositoryInterface
11+
{
12+
use RepositoryTrait;
13+
14+
public function __construct(private readonly Custom\Builder\Action $builder)
15+
{
16+
$this->files = [];
17+
$this->packages = [];
18+
}
19+
20+
public function getBuilder(): Custom\Builder\Action
21+
{
22+
return $this->builder;
23+
}
24+
25+
public function merge(Configurator\RepositoryInterface $friend): self
26+
{
27+
array_push($this->files, ...$friend->getFiles());
28+
array_push($this->packages, ...$friend->getPackages());
29+
30+
return $this;
31+
}
32+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Kiboko\Component\Satellite\Action\Custom\Factory\Repository;
6+
7+
use Kiboko\Contract\Configurator;
8+
use Kiboko\Contract\Packaging;
9+
10+
trait RepositoryTrait
11+
{
12+
/** @var array<Packaging\FileInterface|Packaging\DirectoryInterface> */
13+
private array $files;
14+
/** @var string[] */
15+
private array $packages;
16+
17+
public function addFiles(Packaging\FileInterface|Packaging\DirectoryInterface ...$files): Configurator\RepositoryInterface
18+
{
19+
array_push($this->files, ...$files);
20+
21+
return $this;
22+
}
23+
24+
/** @return iterable<Packaging\FileInterface|Packaging\DirectoryInterface> */
25+
public function getFiles(): iterable
26+
{
27+
return $this->files;
28+
}
29+
30+
public function addPackages(string ...$packages): Configurator\RepositoryInterface
31+
{
32+
array_push($this->packages, ...$packages);
33+
34+
return $this;
35+
}
36+
37+
/** @return iterable<string> */
38+
public function getPackages(): iterable
39+
{
40+
return $this->packages;
41+
}
42+
}

0 commit comments

Comments
 (0)