Wizards and MVC
Moderator: General Moderators
Re: Wizards and MVC
Another way to look at it, is that a Wizard is just a paginated form.
Re: Wizards and MVC
That's only the "linear" wizard, IMHOJenk wrote:Another way to look at it, is that a Wizard is just a paginated form.
There are 10 types of people in this world, those who understand binary and those who don't
Re: Wizards and MVC
There's another type of wizard? 
- John Cartwright
- Site Admin
- Posts: 11470
- Joined: Tue Dec 23, 2003 2:10 am
- Location: Toronto
- Contact:
Re: Wizards and MVC
I imagine he is refering to "wizards" where steps are not required to be completed sequentially.Jenk wrote:There's another type of wizard?
Re: Wizards and MVC
That's even more like a paginated form than a linear wizard then! 
- Christopher
- Site Administrator
- Posts: 13596
- Joined: Wed Aug 25, 2004 7:54 pm
- Location: New York, NY, US
Re: Wizards and MVC
I think paginated forms is a simple way to view a wizard (and not a bad one necessarily) . However there are a number of cases where there are either multiple paths through a sequence or where certain steps can be skipped. I gave the checkout process as a place where I often use an Application Controller. Here are some examples of the non-linear cases I mentioned using checkout as a use case.Jenk wrote:There's another type of wizard?
A common step in the checkout process is to require the customer to either log-in or register. However, if the customer is already logged-in then this step can be skipped and they can go directly to confirming the order, their address, or whatever the next step would be. This log-in or register also shows the idea of multiple paths through the sequence.
Another example of multiple paths I have implemented is different steps for different types of customers. For example, there my be regular customers and business customers. The registration and checkout sequences may have more options or be more involved for business customers.
As Josh said, all this can be done with if()'s in your controllers. I think most people don't have Application Controller code available or perhaps don't like the more event driven style of setting up states and transitions for it require.
(#10850)
Re: Wizards and MVC
In homepage, Router checks if there is controller selected in URL. If isn't, script gets default controller from configuration file and instantiates it. If method for controller is not set, it loads $controller->index() method. If not, loads: $controller->$selected_method();VladSun wrote:How do you guys write your wizard pages in a way that fits the MVC approach? I'm not interested in passing the current model state. I'm more interested in the M-V-C relations defined.
The problem I'm facing is that the Controller doesn't know the logic flow to follow - it's in the Model.
Abstract class "Base controller", has function for loading models, and accessing them through variable objects. $this->my_model = new Model();
And controller goes and checks for data in model, and just renders it.
Controller example:
Code: Select all
class Blog // implements Controller; extends Controller
{
public function index()
{
$this->get_view('blog_index');
}
public function new_post()
{
$this->get_view('blog_new_post');
}
public function get_post($id = null)
{
if (!is_null($id))
{
$this->get_model('My_Model');
$this->my_model->get_post_by_id($id);
$this->variables['posts'] = $this->my_model->get_post_by_id($id);
/**
* View file:
*
* foreach ($this->variables as $variable => $key)
* return $key
*/
$this->get_view('blog_get_post');
}
}
}Re: Wizards and MVC
kr1pt, it's not the "wizard" I meant.
There are 10 types of people in this world, those who understand binary and those who don't
Re: Wizards and MVC
I faced two problems:
1) A "silent" stage - i.e. stage that will be executed, but its View is not rendered ever. Input data need some processing, but no user interaction needed - just jumping to the next stage. [ SOLVED ]
2) A "repeated" stage - i.e. a stage (together with substages hierarchy) that should be repeated several times (in a loop) [ STILL SOLVING IT]
1) A "silent" stage - i.e. stage that will be executed, but its View is not rendered ever. Input data need some processing, but no user interaction needed - just jumping to the next stage. [ SOLVED ]
2) A "repeated" stage - i.e. a stage (together with substages hierarchy) that should be repeated several times (in a loop) [ STILL SOLVING IT]
There are 10 types of people in this world, those who understand binary and those who don't
- Christopher
- Site Administrator
- Posts: 13596
- Joined: Wed Aug 25, 2004 7:54 pm
- Location: New York, NY, US
Re: Wizards and MVC
Again, the point of an Application Controller is that the "stages" do not need to know any of this -- the rules/conditions manage the program flow. So silent or repeated are irrelevant.
(#10850)
Re: Wizards and MVC
What I have by now is:
(it's JS, remember? And it has some AJAX calls in it, so it's all asynchronous)
Application.js
Every stage object extends the Ext.ex.Wizard.Stage.Component:
Stages notify listeners (i.e. the wizard) about their state. The Wizard makes decision what to do.
After all stages report "stageInitialized" Wizard gets the first available stage object from the Router and initialize it.
On "stageReady" Wizard checks whether the stage "requests" to be executed or not. If not, the next stage object is requested from the router.
On stageProcess the stage is executed. On stageCompleted Wizard gets the next stage from the Router. Etc.
So, on every step my stages decide whether their are needed or not. It's done by passing the current configurator/model state.
An absolutely centralized logic model would be too complicated to define and implement (sounds like a God object IMHO).
I just define the routes, but the stage object itself decides whether it should be executed or not.
(it's JS, remember? And it has some AJAX calls in it, so it's all asynchronous)
Application.js
Code: Select all
this.configurator = new Ext.App.Model.Configurator();
this.wizard = new Ext.ex.Wizard.Panel(
{
configurator : this.configurator,
router : new Ext.ex.Wizard.Router(
{
map :
[
{
object : new Ext.App.Component.Wizard.Stage.FileUpload(),
stages :
[
{
object : new Ext.App.Component.Wizard.Stage.SchemaInfo()
},
{
object : new Ext.App.Component.Wizard.Stage.TablesPicker()
},
{
object : new Ext.App.Component.Wizard.Stage.RelationsEditor()
}
]
}
]
})
});Code: Select all
Ext.ex.Wizard.Stage.Component = function(config)
{
Ext.apply(this, config);
Ext.ex.Wizard.Stage.Component.superclass.constructor.call(this, config || {});
this.addEvents(
{
stageInitialized : true,
stagePrepared : true,
stageCancelled : true,
stageCompleted : true,
stageFailed : true,
stageReady : true
});
}
Ext.extend(Ext.ex.Wizard.Stage.Component, Ext.Panel,
{
model : null,
init : function (model)
{
this.model = model;
this.fireEvent('stageInitialized', true, this);
},
prepare : function ()
{
this.fireEvent('stagePrepared', true, this);
},
redraw : function ()
{
},
process : function ()
{
this.fireEvent('stageCompleted', true, this);
},
cancel : function ()
{
this.reset();
this.fireEvent('stageCancelled', true, this);
},
reset : function ()
{
}
});After all stages report "stageInitialized" Wizard gets the first available stage object from the Router and initialize it.
On "stageReady" Wizard checks whether the stage "requests" to be executed or not. If not, the next stage object is requested from the router.
On stageProcess the stage is executed. On stageCompleted Wizard gets the next stage from the Router. Etc.
So, on every step my stages decide whether their are needed or not. It's done by passing the current configurator/model state.
An absolutely centralized logic model would be too complicated to define and implement (sounds like a God object IMHO).
I just define the routes, but the stage object itself decides whether it should be executed or not.
Last edited by VladSun on Fri Feb 04, 2011 7:15 am, edited 1 time in total.
There are 10 types of people in this world, those who understand binary and those who don't
Re: Wizards and MVC
Maybe the JS example is too complicated because of its AJAX nature. In PHP that would be something like this:
An example of usage:
Code: Select all
interface IStage
{
function setModel($model);
function preWizardInit(); // check for some preconditions met before the Wizard starts. Run at Wizard init.
function didPreWizardInitSucceeded(); // shell we run the Wizard at all?
function preProcess(); // check for some condtions (together with $model current data). Run "before" stage.
function didPreProcessSucceeded(); // Stage has errors? If yes Wizard stops - Next not available, Prev available
function isStageSilent(); // Does Stage need a View or it may process silently then jumping to the next stage
function isStageRequired(); // Is Stage required at all, if not all substages are not required either.
function process(); // If isStageRequired == true, execute this method
function didProcessSucceeded(); // Stage has Errors?
}Code: Select all
class Router
{
public function setMap($map);
public function setStateManager($stateManager);
public function getNextStage(); // returns IStage
}Code: Select all
class Wizard extends ActionController
{
public function __construct($router, $stateManager);
public function nextStage();
public function finish();
}Code: Select all
class MyWizard extends Wizard
{
public function __construct()
(
parent::__construct
(
new Router
(
array
(
array
(
'stage' => new Stage1(),
'substages' => array
(
array
(
'stage' => new Stage1_1(),
'substages' => null
),
array
(
'stage' => new Stage1_2(),
'substages' => array
(
'stage' => new Stage1_2_1(),
'substages' => null
),
),
)
),
array
(
'stage' => new Stage2(),
'substages' => null
),
)
),
new StateManager()
);
)
}There are 10 types of people in this world, those who understand binary and those who don't