File reference with public URLs
This pattern shows how to:
- Let two portals transfer a file via file references
- Add configuration to a portal to toggle behaviour
- Separate API usage from entity processing
Portal A
src/Resources/flow-component/media-emit.php
<?php
declare(strict_types=1);
use Heptacom\HeptaConnect\Dataset\Ecommerce\Media\Media;
use Heptacom\HeptaConnect\Portal\Base\Builder\FlowComponent;
use Heptacom\HeptaConnect\Portal\Base\File\FileReferenceFactoryContract;
FlowComponent::explorer(Media::class)
->run(static fn (): iterable => [
'https://picsum.photos/seed/php/300/300',
'https://picsum.photos/seed/is/300/300',
'https://picsum.photos/seed/nice/300/300',
]);
FlowComponent::emitter(Media::class)
->run(static function (string $externalId, FileReferenceFactoryContract $fileReferenceFactory): Media {
$result = new Media();
$result->setPrimaryKey($externalId);
// externalId is a URL as used in the explorer a few lines above
$result->setFile($fileReferenceFactory->fromPublicUrl($externalId));
return $result;
});
Portal B
src/Resources/flow-component/media-receive.php
<?php
declare(strict_types=1);
use Heptacom\HeptaConnect\Documentation\PortalB\Api\Client;
use Heptacom\HeptaConnect\Dataset\Base\File\FileReferenceContract;
use Heptacom\HeptaConnect\Dataset\Ecommerce\Media\Media;
use Heptacom\HeptaConnect\Portal\Base\Builder\FlowComponent;
use Heptacom\HeptaConnect\Portal\Base\File\FileReferenceResolverContract;
FlowComponent::receiver(Media::class)
->run(static function (Media $entity, FileReferenceResolverContract $fileReferenceResolver, Client $client, bool $configUpload): void {
$resolvedFile = $fileReferenceResolver->resolve($entity->getFile());
if ($configUpload) {
$mediaLocation = $client->uploadBlob($resolvedFile);
} else {
$mediaLocation = $client->importBlob($resolvedFile);
}
$entity->setPrimaryKey($mediaLocation);
});
src/Portal.php
<?php
declare(strict_types=1);
namespace Heptacom\HeptaConnect\Documentation\PortalB;
use Heptacom\HeptaConnect\Portal\Base\Portal\Contract\PortalContract;
use Symfony\Component\OptionsResolver\OptionsResolver;
class Portal extends PortalContract
{
public function getConfigurationTemplate(): OptionsResolver
{
return parent::getConfigurationTemplate()
->addAllowedTypes('upload', 'bool')
->setDefault('upload', false);
}
}
src/Api/Client.php
<?php
declare(strict_types=1);
namespace Heptacom\HeptaConnect\Documentation\PortalB\Api;
use Heptacom\HeptaConnect\Dataset\Base\File\FileReferenceContract;
use Heptacom\HeptaConnect\Portal\Base\Builder\FlowComponent;
use Heptacom\HeptaConnect\Portal\Base\File\FileReferenceResolverContract;
use Heptacom\HeptaConnect\Portal\Base\Web\Http\Contract\HttpClientContract;
use Psr\Http\Client\ClientInterface;
use Psr\Http\Message\RequestFactoryInterface;
use Psr\Http\Message\StreamFactoryInterface;
class Client
{
private ClientInterface $client;
private RequestFactoryInterface $requestFactory;
private StreamFactoryInterface $streamFactory;
public function __construct(
HttpClientContract $client,
RequestFactoryInterface $requestFactory,
StreamFactoryInterface $streamFactory
) {
$this->client = $client;
$this->requestFactory = $requestFactory;
$this->streamFactory = $streamFactory;
}
public function uploadBlob(FileReferenceContract $file): string
{
$request = $this->requestFactory->createRequest('POST', 'https://onlineshop.test/api/media/upload');
$request = $request->withHeader('Content-Type', 'application/octet-stream');
$request = $request->withBody($this->streamFactory->createStream(
$file->getContents()
));
$response = $this->client->sendRequest($request);
return $response->getHeaderLine('Location');
}
public function importBlob(FileReferenceContract $file): string
{
$request = $this->requestFactory->createRequest('POST', 'https://onlineshop.test/api/media/import');
$request = $request->withHeader('Content-Type', 'application/json');
$request = $request->withBody($this->streamFactory->createStream(\json_encode([
'url' => $file->getPublicUrl(),
])));
$response = $this->client->sendRequest($request);
return $response->getHeaderLine('Location');
}
}