Short notation for flow components

Flow components that have been described in the previous pages can also be written in a callback registration pattern. This is very useful short notation to reduce boilerplate code that is only needed to "wire" the API connecting services to the flow components. To learn more about the decisions behind this feature have a look at the related ADR.

How to use

For this feature a plain php file within the folder src/Resources/flow-component/ is expected:

<portal-dir>
├── composer.json
└── src
    └── Resources
        └── flow-component
            └── foobar.php

foobar.php will be loaded and uses a newly introduced FlowComponent building utility. Every callback that is given into that builder can make use of every dependency injection feature. As the callbacks are executed by a wrapper based on the object-oriented notation, there is $this available pointing to the wrapping flow component instance. With this at hand, you can call other methods like supports or run from within a callback. The following section will show how to use each flow component with a file accessing scenario.

Explorer

Click here to see the object-oriented notation.

<?php

use Heptacom\HeptaConnect\Playground\Dataset\Bottle;
use Heptacom\HeptaConnect\Portal\Base\Builder\FlowComponent;
use Heptacom\HeptaConnect\Portal\Base\File\Filesystem\Contract\FilesystemInterface;

FlowComponent::explorer(Bottle::class)->run(
    fn (FilesystemInterface $fs): iterable => scandir($fs->toStoragePath('/'))
);

FlowComponent::explorer(Bottle::class)->isAllowed(
    fn (FilesystemInterface $fs, string $id): bool => filesize($id) > 0
);

Emitter

Click here to see the object-oriented notation.

<?php

use FooBar\Packer\BottlePacker;
use Heptacom\HeptaConnect\Playground\Dataset\Bottle;
use Heptacom\HeptaConnect\Playground\Dataset\Volume;
use Heptacom\HeptaConnect\Portal\Base\Builder\FlowComponent;
use Heptacom\HeptaConnect\Portal\Base\File\Filesystem\Contract\FilesystemInterface;

FlowComponent::emitter(Bottle::class)->run(
    fn (FilesystemInterface $fs, BottlePacker $packer, string $id): ?Bottle => $packer->pack(
        file_get_contents($fs->toStoragePath($id)) ?: null
    )
);

FlowComponent::emitter(Bottle::class)->batch(
    fn (FilesystemInterface $fs, BottlePacker $packer, iterable $externalIds): iterable => \iterable_map(
        $externalIds,
        fn (string $id) => $packer->pack(file_get_contents($fs->toStoragePath($id)) ?: null)        
    ) 
);

FlowComponent::emitter(Bottle::class)->extend(
    fn (FilesystemInterface $fs, Bottle $bottle): ?Bottle => $bottle->setCapacity(
        (new Volume())
            ->setAmount(filesize($fs->toStoragePath($bottle->getPrimaryKey())))
            ->setUnit('byte')
    )
);

Receiver

Click here to see the object-oriented notation.

<?php

use Heptacom\HeptaConnect\Dataset\Base\TypedDatasetEntityCollection;
use FooBar\Unpacker\BottleUnpacker;
use Heptacom\HeptaConnect\Playground\Dataset\Bottle;
use Heptacom\HeptaConnect\Portal\Base\Builder\FlowComponent;
use Heptacom\HeptaConnect\Portal\Base\File\Filesystem\Contract\FilesystemInterface;

FlowComponent::receiver(Bottle::class)->run(
    function (FilesystemInterface $fs, BottleUnpacker $unpacker, Bottle $bottle): void {    
        ['id' => $id, 'payload' => $payload] = $unpacker->unpack($bottle);
        file_put_contents($fs->toStoragePath($id), $payload);
    }
);

FlowComponent::receiver(Bottle::class)->batch(
    function (FilesystemInterface $fs, BottleUnpacker $unpacker, TypedDatasetEntityCollection $bottles): void {
        $bottleData = array_column(iterable_to_array($bottles->map([$unpacker, 'unpack'])), 'payload', 'id');

        foreach ($bottleData as $id => $bottle) {
            file_put_contents($fs->toStoragePath($id), $bottle);
        }
    }
);

Status reporter

Click here to see the object-oriented notation.

<?php

use Heptacom\HeptaConnect\Portal\Base\Builder\FlowComponent;
use Heptacom\HeptaConnect\Portal\Base\File\Filesystem\Contract\FilesystemInterface;

FlowComponent::statusReporter('health')->run(
    fn (FilesystemInterface $fs): bool => scandir($fs->toStoragePath('/')) !== false
);

FlowComponent::statusReporter('info')->run(
    fn (FilesystemInterface $fs): array => [
        'count' => count(scandir($fs->toStoragePath('/'))),
    ]
);