I'm working on a building what I'm calling a Process Wizard Builder in PHP. I'm interested in using established design patterns where applicable, but my experience architecting a system like this using design patterns is limited.

Here's the gist of the system:

There are many different process wizards that need to be built (10+). A process wizard is defined as a set of steps required to create or update an entity in the system. The number of steps for a process wizard may vary. Step order needs to be modifiable. Steps can be reused across process wizards. Step functionality needs to be able to be overridden per wizard. Steps each accomplish a specific goal: information gathering, document upload, invoice creation, etc.. Each step also may have AJAX calls to fetch additional data and each AJAX call may need to handle responses differently for each wizard.

In plain English the overarching flow would always be:

  1. Choose and start a process wizard
  2. Work through interactive steps defined for that wizard.
  3. Finally yield new tasks / data for users.

Here's some pseudo-code of what I mean by flexible design:

class ProcessA
    Runs Step1, Step3, Step4;
    $step_order = [1, 3, 4]; // Order can be anything

class ProcessB
    Runs Step1, Step2, Step3, Step5;
    $step_order = [1, 3, 2, 5]; // Order can be anything

    // Override one of the steps;
    function Step2()
        // Different step2 code.

I'm currently doing this without any establish patterns. I'm using an abstract parent class, traits, dynamic method calls keyed off of step names, and a step order array. It works, but I can't help thinking that there may be better or more expected approach. I'm wondering if there is a combination of design patterns that may be a better choice for something like this.

I feel like the answer may be some combination of Builder, Factory, and Decorator. My experience implementing design patterns is limited so thoughts from those with more experience would be great.

Additional info provided in response to a comment: Where my approach feels weak is when trying to "roll-up" data to one place. For instance, each step has it's own set of javascript functions and ajax calls. Those functions should live in their own .js file. However, as best I can tell when using a trait, you cannot do something like add data to a class property for each trait. i.e. Step1Trait wants to add Step1.js to an array, Step2Trait wants to add Step2.js, etc. but this isn't possible. The work around I could do is to have a method on the abstract class that would fetch all properties that follow a naming convention and aggregate them into an array. However, this functionality seems closer to what a Decorator Pattern would do.

Another place where my approach isn't working is around customizing each step's javascript code based on the particular process I'm using. Some processes may need additional validations or additional ajax calls beyond what the default of a Step may be. My current thought for solving this is to use a custom function caller in javascript that is aware of a naming pattern as well, similar to what I've done in the PHP code. Again, this feels like something a Decorator pattern would handle more elegantly.

  • 1
    You need to be more specific about what you don't love about your current approach, so that we can offer suggestions for improvement tailored specifically to your dislike. Note that software patterns aren't building blocks. Have you considered using an existing workflow engine? Commented Mar 2, 2017 at 17:03
  • Thanks for the comment @RobertHarvey. I'll add some of the issues with my current approach. I wasn't aware of workflow engines, but after a quick look they seem too rigid for what I'm doing. It may be my unfamiliarity with them that gives me pause though. Commented Mar 2, 2017 at 17:42
  • OK, I've read your edit. Please read What is the X Y problem and respond. I feel like your question could benefit from a concrete example (instead of a foo bar one). Have you looked at Actor models like Akka? Commented Mar 2, 2017 at 18:27
  • @RobertHarvey If this is an XY problem, I'd say that the confusion is due to the details I provided about my current solution. I'm not looking for advice on my solution, but looking for better approaches to the problem stated in paragraph two of the question; approaches that are different than using traits and dynamic method calls. Regarding the actor model, it seems like a good candidate. Commented Mar 2, 2017 at 18:59
  • @RobertHarvey Question edited to be more clear regarding the problem at hand. Thanks for your attention on this! Commented Mar 2, 2017 at 19:44

1 Answer 1

  1. I would not override anything here, since it does not help
  2. Declare every Step outside of a given Process with the same base
  3. A process is just a configuration of steps -> Which do you perform and in which order.

It's not a pattern, but just simple design following the FCoI Principle.

  • That's pretty much the route I went with. However, I'm interested to know if there is a more established approach using patterns. It may just be that the problem as described doesn't really match established patterns. Commented Mar 6, 2017 at 23:17

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.