Payum icon indicating copy to clipboard operation
Payum copied to clipboard

Payum 2.0 Roadmap. Use of process flow concept.

Open makasim opened this issue 8 years ago • 18 comments

Right now a lot of stuff is happening at runtime. The payment flow is hard to predict and follow. It is hard to say:

  1. What actions were executed?
  2. What was the order of those actions?
  3. The decisions is heavily based on the context (payment details).
  4. 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.
  5. 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

makasim avatar Apr 25 '17 14:04 makasim

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 avatar Jun 29 '17 11:06 dincho

@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.

makasim avatar Jun 29 '17 11:06 makasim

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?

Tetragramat avatar Nov 14 '17 11:11 Tetragramat

Would be all actions replaced with (Callback)Behavior?

That's the plan

makasim avatar Nov 14 '17 11:11 makasim

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.

lyrixx avatar Nov 28 '17 14:11 lyrixx

BTW, If you have some question about the workflow component, don't hesitate to ping me. I'm the maintainer of this component ;)

lyrixx avatar Nov 28 '17 14:11 lyrixx

@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:

makasim avatar Nov 29 '17 13:11 makasim

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 avatar Nov 29 '17 14:11 lyrixx

@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?

makasim avatar Nov 29 '17 14:11 makasim

Sure. You can play with this demo and it's open source

lyrixx avatar Nov 29 '17 15:11 lyrixx

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 "

makasim avatar Nov 29 '17 15:11 makasim

The line (new ProcessEngine($registry))->proceed($token); executes two behaviors\nodes, that's why it prints "foo bar ".

makasim avatar Nov 29 '17 15:11 makasim

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 avatar Nov 29 '17 16:11 lyrixx

@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.

makasim avatar Nov 29 '17 20:11 makasim

This what we use while building the formapro/pvm - https://www.techfak.uni-bielefeld.de/~mchen/BioPNML/Intro/pnfaq.html

makasim avatar Nov 29 '17 20:11 makasim

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 avatar Jan 17 '18 09:01 garak

@garak I removed them on packagist. Those are the tags of PayumBundle, they should've been here at all.

makasim avatar Jan 17 '18 10:01 makasim

Hi @makasim it seems the tags are back, I just had an awkward moment of confusion based on the same discovery in composer outdated.

mbabker avatar Feb 19 '18 17:02 mbabker