Payum
Payum copied to clipboard
Payum 2.0 Roadmap. Use of process flow concept.
Right now a lot of stuff is happening at runtime. The payment flow is hard to predict and follow. It is hard to say:
- What actions were executed?
- What was the order of those actions?
- The decisions is heavily based on the context (payment details).
- There is no a visual representation of the process. Do we need a redirect, or should we show a form. We do not know until we start executing the request.
- Right now Payum support only one process and it is the purchase. Some gateways also support recurring payment but the implementation is not that good. The process flow could improve it.
Recently we've been playing with process virtual machines and I realized that it could be a good fit for Payum.
So I did a proof of concept. It shows how Paypal ExpressCheckout may look like. The code is here: https://github.com/formapro/pvm-demo/blob/master/src/AppBundle/Controller/PaypalController.php and the demo is here: https://pvm-demo.forma-pro.com/paypal-express-checkout
Recently we've been playing with process virtual machines and I realized that it could be a good fit for Payum.
Isn't this the same as Symfony Workflow Component ?
@dincho Nope. They are both a sub sets of Petri Net but with different restrictions.
The Symfony's component is not a workflow but a state machine where what I am think about is ACTIVITY workflow not state.
I like that it is much easier to understand how it works. While time to understand current payum took me a while, this one was question of few minutes. Would be all actions replaced with (Callback)Behavior?
Would be all actions replaced with (Callback)Behavior?
That's the plan
Hello there.
Actually, The Symfony Worklfow component is not only a state machine component. It's also a an implementation of workflow net (a subset of petri net).
Then, you can trigger some action when a transition is fired thanks to the events.
Cheers.
BTW, If you have some question about the workflow component, don't hesitate to ping me. I'm the maintainer of this component ;)
@lyrixx The most important difference that pvm walks through the graph itself, where symfony/workflow delegate this responsibility to a developer.
Something more about formapro/pvm. With pvm you can create a process (It is basically a representation of a graph). Then, you can pass it to the process engine which walks through the graph executing the code bound to nodes (behaviors). The engine allows you to do cycles, forks, joins, delaying as well as parallel execution on one computer or spread across several ones.
The walk through the process can be paused. It is very useful when you have to ask a user for some info (show a page with a form).
The process does not define any states\stages, it just walks through it.
It could be used at runtime without any persisted storages (obviously with some limitations).
Or, It can be stored in a database as a template and then copy pasted and executed millions of times. A change in the template does not affect in-progress processes.
The process can store some user data.
The process does not require any other domain entites\models. Could be used as is.
Pvm could be used to build real BPMN processes.
It works great with concurrency.
Some examples:
Sure ;) You can do the same things with Symfony/Workflow also ;)
Except the part "The process does not require any other domain entites\models" where the workflow need a least one object to store the current state.
@lyrixx I've not found any example of walking through the graph (without any additional control from my side). Could you share it with me, please?
Sure. You can play with this demo and it's open source
This is the difference. You control the flow, where pvm ProcessEngine does it internally. You built the process and pass it to the process engine.
<?php
namespace Acme;
use Formapro\Pvm\DefaultBehaviorRegistry;
use Formapro\Pvm\CallbackBehavior;
use Formapro\Pvm\ProcessEngine;
use Formapro\Pvm\Process;
use Formapro\Pvm\Token;
$registry = new DefaultBehaviorRegistry();
$registry->register('print_label', new CallbackBehavior(function(Token $token) {
echo $token->getTransition()->getTo()->getLabel().' ';
}));
$process = Process::create();
$fooNode = $process->createNode();
$fooNode->setLabel('foo');
$fooNode->setBehavior('print_label');
$barNode = $process->createNode();
$barNode->setLabel('bar');
$barNode->setBehavior('print_label');
$process->createTransition($fooNode, $barNode);
$transition = $process->createTransition(null, $fooNode);
$token = $process->createToken($transition);
(new ProcessEngine($registry))->proceed($token);
// Prints "foo bar "
The line (new ProcessEngine($registry))->proceed($token); executes two behaviors\nodes, that's why it prints "foo bar ".
Yes, I already looked at your exemple you gave me. But you can already do the same with symfony. Here is the minimal code you need to mimic the $fooNode->setBehavior('print_label'); behavior:
<?php
require __DIR__.'/vendor/autoload.php';
use Symfony\Component\EventDispatcher\EventDispatcher;
use Symfony\Component\Workflow\DefinitionBuilder;
use Symfony\Component\Workflow\Event\Event;
use Symfony\Component\Workflow\Transition;
use Symfony\Component\Workflow\Workflow;
$workflowName = 'my_workflow';
$transitionName = 'a_to_b';
$definition = (new DefinitionBuilder())
->addPlace('a')
->addPlace('b')
->addTransition(new Transition($transitionName, 'a', 'b'))
->build()
;
$eventDispatcher = new EventDispatcher();
$eventDispatcher->addListener("workflow.$workflowName.transition", function(Event $event) {
echo 'Transition Name: '.$event->getTransition()->getName()."\n";
echo 'Will be in the following place(s): '.implode(', ', $event->getTransition()->getTos())."\n";
});
$workflow = new Workflow($definition, null, $eventDispatcher, $workflowName);
$subject = new \stdClass();
$subject->marking = null;
$workflow->apply($subject, $transitionName);
Note: to run this example, you need the following composer.json:
{
"require": {
"symfony/workflow": "^3.3",
"symfony/event-dispatcher": "^3.3"
}
}
Then, it looks like your implementation automatically apply a transition if this one is enabled. This is something we don't want in symfony because it does not follow the petrinet specs. But you can implement it like following:
$workflowName = 'my_workflow';
$transitionName = 'a_to_b';
$definition = (new DefinitionBuilder())
->addPlace('a')
->addPlace('b')
->addPlace('c')
->addTransition(new Transition($transitionName, 'a', 'b'))
->addTransition(new Transition('b_to_c', 'b', 'c'))
->build()
;
$eventDispatcher = new EventDispatcher();
$workflow = new Workflow($definition, null, $eventDispatcher, $workflowName);
$eventDispatcher->addListener("workflow.$workflowName.transition", function(Event $event) {
echo 'Transition Name: '.$event->getTransition()->getName()."\n";
echo 'Will be in the following place(s): '.implode(', ', $event->getTransition()->getTos())."\n";
});
$eventDispatcher->addListener("workflow.$workflowName.announce.b_to_c", function(Event $event) use ($workflow) {
$workflow->apply($event->getSubject(), 'b_to_c');
});
$subject = new \stdClass();
$subject->marking = null;
$workflow->apply($subject, $transitionName);
@lyrixx sorry but I feel I am still missing something.
Actually, I have to manage all transitions in a listener my self. If I change the process graph I have to revise all listeners and adjust them (cuz transition name is hardcoded there). There is no way to do a real async walk through the graph execution.
Honestly, I don't want to start an argument but I do see a state machine which could be used as a workflow if an additional effort is made.
This what we use while building the formapro/pvm - https://www.techfak.uni-bielefeld.de/~mchen/BioPNML/Intro/pnfaq.html
Today, after performing a composer outdated, I discovered that there's a version 2.1 (and a 2.0 too) of payum/payum.
It looks like is not updated (last update on Sep 2016) and it's requiring strange things (like Symfony framework). The README on this repository is titled "PayumBundle".
What's that?
@garak I removed them on packagist. Those are the tags of PayumBundle, they should've been here at all.
Hi @makasim it seems the tags are back, I just had an awkward moment of confusion based on the same discovery in composer outdated.