[EXTENSION] simpleWorkflow

Hi Salsero,

oups … I’m using PHP 5.3 and the domxml extension was installed on my dev platform, so I used it. Maybe that’s no the better choice. What is your advice ? What php extension should I use to parse and xpath XML ?

Unfortunatly, right now, there’s not much you can do about it, apart installing domxml. Then depending on my free time, I can rewrite the yEd with a more familiar parser extension.

ciao

8)

Raoul, Salsero,

I found that problem and I fixed commenting the lines


//		if(!extension_loaded('domxml')){

//			throw new SWException('extension domxml not loaded : yEd converter requires domxml extension to process');

//		}

at file SWyEdConverter.php at method convert($file) in lines 63 to 65 (in my file :D).

If you have the common dom library for xml process (you can check it in phpinfo(), DOM/XML set as enabled) it will works fine. I think I didn’t do any other change.

Kike

Kike, i have try your solution and seems OK ;) thank’s for your solution!

Raoul,

I have the common dom library for xml process (I checked it in phpinfo(), DOM/XML set as enabled)

I would be grateful if you would put the rewrite of yEd with DOM/XML parser in your TODO list ;D

Thank’s for this very useful extension!

…maybe if I just remove the “extension_loaded” test it will be ok ;) … and save me a rewrite of the yEd parser :rolleyes:

Thanks for your feedback guys, I’ll see what I can do …

ciao

B)

i hope this ;)

sorry by i’m very dummy :(, can you post a simple example code for intercept event as onBeforeTransition??

where i have to put my code??

tnx a lot!!! CIAO!!! :D

Hi Salsero,

deal then : I will remove the extension_loaded test ! (anyway I currently have no time to rewrite the code with another parser ;) )

Now regarding your question on how to handle events with simpleWorkflow, here is what you should do :

  • first of all, your model must extends from SWActiveRecord instead of CActiveRecord (or whateever base class your model may extend). If you take a look at the SWActiveRecord source code, you’ll see that this class declares all events that come with simpleWorkflow

  • then it’s time for you to write some code in order to handle simpleWorkflow events. To do so, you have 2 options[list=1]

  • directly add the event handler method in your model class. For instance, if you want your model to handle the enterWorkflow event, create a method with the following signature : enterWorkflow($event)

…or…

  • you may also want to group all your event handlers into a CActiveRecord behavior. In this case, create a new class that extends SWActiveRecordBehavior and implement the handlers for the events you’re intrested in. Here is an example of such behavior class (from the unit test classes). Of course, once done, you just have to attache your new behavior to your model, instead of attaching the default SWActiveRecordBehavior class.

[/list]At last, please note that all event raised by the simpleWorkflow extension are SWEvent objects. They give you access to both the source and destination status (and to the sender instance, of course).

That’s it ! … if you encounter any problem (yes yes, that’s possible ;) ) do not hesitate to ask and be sure that I’ll do my best to help.

ciao

8)

thank you for your explanation! I hope not to have problems, I feel comfortable for your support ;) Ciao!

i opted for this solution and works ;) i did also read that i can initialize the behavior with transitionBeforeSave to FALSE… how??? where i have to put this inizialization??

Tnx for your support Raoul

Bye

Hi Salsero,

you can initialize this feature when you attach the simpleWorkflow behavior to the ActiveRecord class. Typically this is done in the behaviors() method. For instance :




public function behaviors()

{

    return array(

      'swBehavior' => array(

           'class'   => 'application.extensions.simpleWorkflow.SWActiveRecordBehavior',

    		'transitionBeforeSave'   => false, // here we go !

    	)

    );

}

Hope this helps …

ciao

B)

Yes… as always ;) thanks awfully!!!

Raoul sorry, another question:

you have explained very well how validate a transition as


array('status',  'SWValidator','enableSwValidation'=>true,'match'=>true),

// all models leaving the 'Correction' status, must have a category

array('category','required','on'=>'sw:/Correction_.*/'),

if i want validate a jump to a status of another workflow??

for example: from status a of workflow A and status b of workflow B

how can i do it?

array(‘category’,‘required’,??????????

thank’s ;)

hi Salsero,

let’s say you have defined a transition between workflowA/status1 to workflowB/status2, and you want to validate that when the AR performs this transition, its ‘category’ attribute is ‘required’.

Here is how you should define the validation rule :




...

   array('status','SWValidator','enableSwValidation'=>true,'match'=>true),

   array('category','required','on'=> 'sw:/workflowA\/1_workflowB\/2/'),

...



As you can see, the important stuff here is the value of the ‘on’ parameter. : “sw:/workflowA\/1_workflowB\/2/

How does it work ?

Well, when the SWValidator is enabled, it is called when a transition is done and validates the ‘status’ attribute … but that’s not all ! It will also creates a scenario name and apply all validations rules defined for this scenario.

The scenario name created by SWValidator is built by concatenating, the start status, the underscore character , and the target status. In this case, the scenario will be : "[color="#0000FF"]workflowA/1_workflowB/2[/color]"

… so why not use this scenario name instead of this strange string with backslashes and stuff ?

Well, this is because you have decided to set the match parameter to true. In this case, SWValidator will consider the value of the ‘on’ parameter as a regular expression, and it will try to match the scenario name it creates for the transition, with this regular expression.

(Note that the "sw:" prefix is only here to prevent scenario collision)

So for the example above we would have :

  • my record goes from workflowA/1 to workflowB/2
  • the SWValidator is invoked and creates the scenario name "workflowA/1_workflowB/2"
  • SWValidator will check each validation rule with a ‘on’ attribute and a scenario name starting with “sw:”
  • for each one found, it will test if it matches "workflowA/1_workflowB/2" and if yes, it apply the validation rule

To create a regular expression that matches the string “workflowA/1_workflowB/2” you must escape the slash character … that’s why a backslash is needed (this is a nice page to tests regular expression ;) ).

One last word : if you don’t need the match feature, you could have wrote your rules like this :




...

   array('status','SWValidator','enableSwValidation'=>true,'match'=>false),

   array('category','required','on'=> 'sw:workflowA/1_workflowB/2'),

...



Ok, after all this writting I hope didn’t lost you ;)

Do not hesitate to ask if things don’t work like they should (I mean … I’m only refering to the simpleWorkflow extension right ? ;) )

ciao

B)

Hi Raoul,

let me say thanks for your answer… i have really appreciate it!!!

my problem was this ;)

I have a few problems with regular expressions so I say thanks for the “nice page” :D:D:D

so thanks thanks thanks!!! :D

Ciao!!!

sorry Raoul,

another question:

[list=1]

[*]i have a model in Status A

[*]user update model (by a form) and set Status B

[*]in afterTransition i have this:

[/list]




 public function afterTransition($event) {

            parent::afterTransition($event);

          

            switch ($event->destination) {

                case 'B': 

                        $this->status = C;

                        $this->save();

                       } break;



that is I want that automatically status go in C if destination status is B but the problem is that $event don’t change and go in loop… because $event->destination result always B!!! :( is normal this situation??? what is wrong?

i hope my question is clear and you have an answare ;)

thank you so much!!!

Hi Salsero,

I thought that sooner or later, such a question was going to be asked …and you are the winner !! :D

I understand what you are trying to do : automatically change the status from within a transition, and unfortunatly this is not possible … by design.

The reason is that even if you’re changing the status to C afterTransition, you are still in the process of completing the transition, and starting another transition at this point would indeed result in a loop (however I thought I wrote something to prevent infinite recusive loop for such situation … I’ll take a look).

Anyway, if you want to implement such behavior, you should set status to C form outside any simpleWorkflow function. Maybe you could try to do it in afterSave … that’s something to try (with no warranty).

Sorry for the inconvenience. I hope you’ll find a way to bypass this limitation.

ciao

8)

Hello!!!

ok no problem… I have bypassed the problem in this way and seems to work:

i’m using another flowchart (second);

when the first flowchart go in status B, it change status in the second flowchart;

after transition of second flowchart; this last set the status "C" in the first;

i don’t know if it will be a solution because i’m finishing to implement it ;)

but in theory should go ;)

thank’s a lot for your answer… GOOD LIFE!!

CIAO!!

Hi there,

I’m using simpleWorkflow and very happy to have installed it. It does the job I need without much head-scratching.

Thanks.

Now, I’m looking for an advice here. I have my workflow set and I want to keep a single view action in my controller (clean and reusable).

But, based on the current status, I’d like to render a different partial.

To do this, I’ve added a method to my model that returns the needed partial for each status, like this:


public function views()	{		

 return array(

  'created'=>'pubview',

  'requested'=>'pubwait',

 );

}

Now, how do I get a status’ view from my controller?

I’ve tried to use a get method, like this:




	public function getStatusView($forStatus='created')

	{

		return $this->views($forStatus);

	}



…but obviously doesn’t work and I’m stuck.

What am I doing wrong? And is there a better way of manage such situation within simpleWorkflow?

Thanks for any suggestion or idea!

EDIT: never mind… solved… my geStatusView code was far from being correct. The working version is like this:


	public function decideStatusView($forStatus='created')

	{

		$statuss = $this->views();

		

		if (isset($statuss[$forStatus])) 

			return $statuss[$forStatus];

		else 

			return $statuss['created'];

	}

	



Then in my controller I can call




$nextView = $model->decideStatusView($model->swGetStatus()->getId());



…and simply pass $nextView to the render call.

Thanks anyway!


Cheers,

rash*

Hi rashmani,

Hopefully you could find a solution … I’ would have been glad to help, but I’m leaving for holidays just now ;)

c u in 4 weeks !!!

B)

Hi Raoul,

I have installed and tested your simple workflow with the default blog app and it was successful. Any specific changes required or not if i want to integrate it with YiiBoilerplate? I have tried to configure your extension and so far i have no clue why i cannot call static function from SWHelper? I suspected the behavior was not loaded thus any function in SWActiveRecordBehavior cannot be called. Please shed some light…

Sorry, just realize you on vacation … Hope u can reply when u come back…

Hi noorfamy,

I’m not familiar with the YiiBoilerplate app template but I guess that at some point, the SWHelper is not imported into your app. Did you fix this issue or are you still struggling ?

8)