Installation:
composer require phpflo/phpflo-bundle --dev
Ensure minimum-stability: dev is set in your composer.json root.
Enable the Bundle:
Add to config/bundles.php:
PhpFlo\PhpFloBundle\PhpFloBundle::class => ['all' => true],
First Component:
Create a basic component (e.g., src/Component/HelloWorld.php):
namespace App\Component;
use PhpFlo\Component;
class HelloWorld extends Component {
public function __construct() {
$this->outPorts()->add('greeting', ['type' => 'string']);
$this->inPorts()->on('data', [$this, 'greet']);
}
public function greet($data) {
$this->outPorts()->greeting->send("Hello, {$data}!");
}
}
Register the Component:
Add to config/services.yaml:
services:
app.hello_world:
class: App\Component\HelloWorld
tags:
- { name: phpflo.component, alias: hello_world }
Define a Graph:
Create config/hello_graph.json:
{
"processes": {
"HelloWorld": { "component": "hello_world" }
},
"connections": []
}
Run the Flow: In a controller or command:
$network = $this->get('phpflo.network')->fromFile('hello_graph.json');
$network->getGraph()->addInitial('hello_graph', 'HelloWorld', 'data', 'Alice');
$network->run();
Component Design:
PhpFlo\Component or implement PhpFlo\ComponentInterface.inPorts() and outPorts() for input/output channels.on() to bind events (e.g., data) to methods.Graph Construction:
config/pipeline.json).
{
"processes": {
"Parser": { "component": "app.parser" },
"Validator": { "component": "app.validator" },
"Logger": { "component": "app.logger" }
},
"connections": [
{ "src": { "process": "Parser", "port": "out" }, "tgt": { "process": "Validator", "port": "in" } }
]
}
$graph = $network->getGraph();
$graph->addProcess('Parser', 'app.parser');
$graph->connect('Parser', 'out', 'Validator', 'in');
Execution:
phpflo.network (components registered once per request).
$network = $this->get('phpflo.network')->fromFile('pipeline.json');
$network->getGraph()->addInitial('pipeline', 'Parser', 'input', $data);
$network->run();
phpflo.network_di (fresh components per run).
$network = $this->get('phpflo.network_di')->fromFile('pipeline.json');
Error Handling:
error ports:
{
"connections": [
{ "src": { "process": "Parser", "port": "error" }, "tgt": { "process": "Logger", "port": "in" } }
]
}
Reusability:
phpflo.component for reuse across graphs.class MyComponent extends Component {
public function __construct(MyService $service) {
$this->service = $service;
}
}
Register in services.yaml:
app.my_component:
arguments: ['@my_service']
tags: [{ name: phpflo.component, alias: my_component }]
Symfony Events:
Trigger flows from Symfony events (e.g., kernel.request):
$eventDispatcher->addListener('kernel.request', function () {
$network = $this->get('phpflo.network')->fromFile('auth_graph.json');
$network->getGraph()->addInitial('auth_graph', 'Auth', 'input', $request);
$network->run();
});
Messenger Integration: Use flows to process messages:
$messageBus->dispatch(new MyMessage($data));
$network = $this->get('phpflo.network')->fromFile('message_graph.json');
$network->getGraph()->addInitial('message_graph', 'Handler', 'message', $message);
Configuration: Load graphs dynamically from config:
# config/packages/phpflo.yaml
phpflo:
default_graph: 'app/config/%kernel.environment%_graph.json'
Access via:
$graphPath = $this->getParameter('phpflo.default_graph');
Testing: Mock components for unit tests:
$mockComponent = $this->createMock(ComponentInterface::class);
$network = new Network([$mockComponent]);
Component Registration:
Issue: Components not found in the graph.
phpflo.component tag is set with a unique alias.var/cache/dev/container.yml) for tagged components.Issue: Duplicate components in phpflo.network.
phpflo.network_di for dynamic instantiation or ensure shared: false in services.yaml.Port Mismatches:
$this->inPorts()->add('input', ['type' => 'array']);
$this->outPorts()->add('output', ['type' => 'string']);
Circular Dependencies:
PhpFlo\Network::validate().Stability Warnings:
dev stability.
minimum-stability: dev in composer.json or use:
composer require phpflo/phpflo-bundle --dev --ignore-platform-reqs
Cache Invalidation:
php bin/console cache:clear
Log Port Activity: Add logging to component methods:
public function greet($data) {
$this->logger->info("Greeting: {$data}");
$this->outPorts()->greeting->send("Hello, {$data}!");
}
Graph Visualization:
Use PhpFlo\Network::toDot() to generate a graphviz diagram:
$dot = $network->getGraph()->toDot();
file_put_contents('graph.dot', $dot);
Component Introspection: Dump component ports during runtime:
$component = $network->getGraph()->getProcess('HelloWorld')->getComponent();
var_dump($component->inPorts(), $component->outPorts());
Custom Component Registry: Override the default registry to filter or transform components:
$registry = new ComponentRegistry();
$registry->addFilter(function ($component) {
return $component instanceof MyCustomComponent;
});
$network = new Network($registry);
Dynamic Graph Loading: Load graphs from databases or APIs:
$graphData = $this->fetchGraphFromDatabase();
$network = $this->get('phpflo.network')->fromArray($graphData);
Port Validation:
Extend PhpFlo\Port to add custom validation:
class ValidatedPort extends Port {
public function send($data) {
if (!is_array($data)) {
throw new \InvalidArgumentException('Expected array');
}
parent::send($data);
}
}
**Event
How can I help you explore Laravel packages today?