contact subscribe

Mojavi - an MVC framework for PHP

Mojavi is a fantastically lightweight, simple, and easy-to-use MVC framework for PHP. I have investigated most MVC frameworks out there, and most of them (Phrame, for one) suffer from the Java-wanna-be complex, which makes for a bloated and inefficient environment for a run-time scripting language like PHP. This tutorial assumes you have discovered Mojavi, downloaded the distribution for Mojavi 2.0 (still beta, but very stable), and looked around long enough to discover that good documentation is sorely lacking. This, of course, does not imply that what follows is "good documentation." Indeed, right now it is very much a rough draft. But I figure something is better than nothing. So here goes.

First, find or get your mojavi 2.0 installation. It should look something like this:

mojavi/
    index.php
    lib/
    mojavi-all-classes.php
    opt/
    webapp/

index.php is an example of the file you would put somewhere in your web folder. webapp/ is a sample Mojavi application, that, as of this writing, probably does not work out of the box, since development on Mojavi has continued to move very fast since the example application was created. Don't worry about that. Forgive the developers and move on. This webapp/ folder will give you a sense of what a Mojavi application will look like, and especially what the folder structure should be. If you have not done so, look at these aforementioned files, as it will help you understand the rest of this tutorial.

Update: I have created an example application with Mojavi-2.0b2 that should work out-of-the-box with only minor path adjustments The current example does not work seamlessly with the Mojavi 2.0 release due to some vagaries regarding error_reporting() levels. See the comments at the end of this article.

If you are like me, you generally cannot adopt any PHP code without first looking at the source code and understanding, on some level, the internals of what is going on, starting from A and ending with Z. So, if you want to look through the code, (and I highly recommend you do), start with the following list

  1. index.php loads webapp/config.php and then creates a $controller which then calls
  2. $controller->dispatch (see lib/Controller.class.php) which, after some boring details, calls
  3. $controller->forward() (see lib/Controller.class.php) whose primary function is to load and call
  4. ExecutionFilter::execute() (see lib/filters/ExecutionFilter.class.php) which is where most of the fun stuff happens.

The rest of this article is (hopefully) a somewhat illuminating article on how it all happens, in chronological order. For a visual diagram of Mojavi, that is really only useful once you "get it", go here. So, without further ado, let us start with what happens in the index.php file as found in the Mojavi 2.0 distribution.

The Controller is instantiated.

The controller in an MVC framework determines what gets executed when. In Mojavi, the controller passes on its control to actions which, after communicating with the model, tells what view should handle rendering. When the controller is instantiated, a couple of important things happen.

  1. A request object is created.
  2. A user object is created.

These three objects (the $controller, $request, and $user) are central to Mojavi and are seen quite often throughout all your code.

A $request object is created.

This object is very important and used often. It is the "bin" for any objects, renderers, models, etc. that you create that need to be "passed" from your Filters to Actions to Views, etc. A few examples of its usage:

/** Somewhere in your code, like YourFilter::execute() **/
$renderer =& new Renderer; //this is my page renderer instance
$request->setAttributeByRef('Renderer',$renderer);//now save a reference in $request so we can find and use this later...

/** Somewhere else in your code, like YourView::execute() **/
$r =& $request->getAttribute('Renderer'); // get the ref you saved previously...
$r->setAttribute('my_var','my_val');

In addition to the get/set Attribute methods, the same methods exist for parameters, which are Mojavi's name for user input (from a form or GET string, for example). A simple example:

if( $request->hasParameter('user_id') ) {
    //since the user_id is set
    //get user data from model
    //et.c
}

//you can also get/set parameters.
$user_id = $request->getParameter('user_id');//getting paramaters is used often, esp. in View

$unique_id = 'adsfj423432434';
$request->setParameter('unique_id', $unique_id);

//you can also set a param by ref
$request->setParameterByRef('big_object', $big_object);

A $user object is created

The $user object is necessary for authentication and is the container for all session management in Mojavi. If sessions are enabled in PHP, then $user will have the following capability:

$user->setAttribute('name', $name);//set 'name' in session.

$name =& $user->getAttribute('name');

To learn more about $user, look at lib/User.php and /opt/user/PrivilegeUser.php for explanation of the different methods available.

Controller is dispatched and forwards to a specified Action

Before continuing, it is important to understand that the building blocks for your Mojavi application are actions. Anything that you want to "do" in your application is encapsulated in your own Action object that extends the base Action class. Additionally, actions are grouped into modules.

How Mojavi maps a request

Now, all MVC frameworks require some sort of "mapping" so that the Front Controller knows which Actions to load to handle the request from the user. Mojavi's "mapping" is found in a strict but simple set of naming conventions. The easiest way to understand this is to look at the webapp/ directory inside your mojavi installation for a simple example, and to memorize the naming conventions.

Mojavi's $controller generally functions as a Front Controller, meaning that the command to be executed is determined by input to the program either through GET, POST, or PATH_INFO. So the $controller first determines the Action to be executed from the request, and then attempts to load in the Action located in:

BASE_DIR . 'modules/' . $moduleName . 'actions' . $actionName

If it cannot find and load that action successfully, it will then re-route to a PageNotFound module/action that you set in your config.php file. So, assuming all goes well

Controller forwards to the Action

Once Mojavi forwards to the correct action, a chain of "filters" are created. One of these filters (the last one) is Mojavi-specific; the rest can be created by you on both a global (all-modules) and module-specific level. Search Mojavi's forum for real-world examples of filters.

Global and Module Filters

Mojavi then creates an instance of a $filterChain object. Your filters are added to this chain in $filterChain and then a final filter (ExecutionFilter, found in filters/ExecutionFilter.class.php) is tacked on last at the end of the stack. Once this stack of filters has been created, $filterChain->execute() is called, which executes the first filter in the stack. Each filter then executes some code (perhaps setting up a DB connection, instantiating a template engine, etc.) and then calls the $filterChain->execute() method to send execution on to the next filter in the stack. Once this $filterChain has executed your custom filters, it then executes Mojavi's ExecutionFilter last. This is where everything "actually happens". A visual representation of this is found here.

Execution Filter

One of the best ways to understand how the logic in your MyAction class is executed, and how a corresponding view is created, is to analyze the ExecutionFilter::execute() method found in filters/ExecutionFilter.class.phpin the Mojavi 2.0 distribution. A visual representation of that method exists, but nothing compares to actually looking at the code.

Essentially, the ExecutionFilter asks your instantiated "MyAction" object a series of questions. Depending on the answers, certain methods of your MyAction object are called, like MyAction::execute(). This can be easily seen by looking at the ExecutionFilter::execute() code itself.

At this point, it might be a good idea to consult the diagram mentioned earlier for a visual idea of what is happening.

For example, the ExecutionFilter (EF) asks the question $myAction->isSecure(). Depending on the answer, an authentication routine is started (more on that some other day). If you don't specify that method in your extended MyAction class, then it will do as expected and return FALSE. The EF will also ask what request methods that your MyAction class serves with MyAction::getRequestMethods(). This can be none, get, or post (as specified in the constants REQNONE, REQGET, and REQ_POST, respectively). See the source code documentation for more details on the Action::getRequestMethods() function.

getRequestMethods

Now here's a sticky point that often confuses people. getRequestMethods() is an important method in your action because it specifies whether or not your Action should even attempt to execute. If getRequestMethods() does not return a value that matches the request's actual method (for example, if getRequestMethods() returns REQ_POST when the actual request method is REQ_GET) then your Action will not execute()! EF will call the Action::getDefaultView() method instead, and just render the view. What this basically means in layman terms, is that if, for example, you want to go to a "login" page, you first want to just see the form (i.e. the default view). You don't want to actually attempt to login (i.e. execute the LoginAction). You want to do that when the form is posted. So in this case, LoginAction::getRequestMethods() would look like:

function getRequestMethods() {
    return REQ_POST;//only call LoginAction::execute() if we are posting to this action.
}

function getDefaultView() {
    return VIEW_INPUT;//we want to send the request on to views/LoginView_input.class.php
}

Thus, LoginAction would first display the input view (with the form) and then when it was actually posted, LoginAction would then execute the requisite logic to "login."

Confused yet? I'm not surprised. Again, all of this sounds difficult, but it's actually not. Just start playing with some examples and within a few hours you'll be up and running.

Once the ExecutionFilter (EF) determines if the Action serves the right request method, it first validates the request. Your action has two methods related to this, registerValidators() and validate(). To learn how to validate a request, search the mojavi forum for topics on validate.

And then, finally, if the Action validates, your Action::execute() method is called. Here is where you would save user input to a database, for example. Once you have executed the business logic of your application, you need to tell the ExecutionFilter which view to render. So you return either a VIEW constant (see below), or a "string". This "string" follows the naming conventions mentioned earlier. Views have the following naming scheme: TheActionNameView_thestring.class.php. So, for example, if your Action::execute() method looks like this:

function execute(&$controller, &$request, &$user) {
    //store to a DB and then display the 'success' view

    return "saved";
}

The EF would then attempt to load the view called views/MyActionView_saved.class.php. Mojavi has created several constants that handle most possible views you would want to display. See lib/User.class.php for the complete list. Here are the most common:

  • VIEW_INPUT -- literally "input"
  • VIEW_SUCCESS -- literally "success"
  • VIEW_ERROR
  • VIEW_INDEX

Once the ExecutionFilter knows which view you want to initialize, it loads in the view and executes it (e.g. MyView::execute()). This execute() method returns a valid Renderer object (an interface class to customize to your template of choice), and then executes that Renderer object, which (finally) prints to STDOUT.

Whew! If you're confused still, don't fret. Just download an example of Mojavi, look around, spend five minutes debugging it until you get your include paths right, and you'll be surprised how quickly it begins to make a surprising amount of sense. It is by far the easiest MVC framework to implement and learn that I have come across.

Trent,

That’s quite the tutorial. So do you do most of your work in PHP these days? I’m able to poke my way around the code and see what’s going on, but it’s nice to have a tutorial on the MVC for php for when I really want to dive in.

Posted by: Dan Cramer at June 3, 2004 09:25 AM

Hi

This is a cute article for Mojavi. For the new commers this could be a stepping stone. Keep it up. Hope to see further such enlightment articles from you.

Keep it up.

Posted by: ullas at June 4, 2004 02:25 AM

agreed - good job :)

lets hope the new wiki takes off and we can all start sharing modules and other goodies!

Posted by: derek at June 6, 2004 12:13 AM

Trent - I downloaded your tutorial, but when I post, it fails and says:

The requested URL /test/index.php/exec/Default/cmd/Display was not found on this server.

Any idea why it does this? What do I need to change?

Thanks muchly.

Posted by: derek at June 6, 2004 01:19 PM

Whoops. I found it. Line 52 of exampleapp/config.php needed to be changed from:

define(‘SCRIPT_PATH’, ‘/test/index.php’);

to:

define(‘SCRIPT_PATH’, ‘/mojavi/index.php’);

For what it’s worth, the only other line that needs to be changed in order for your exampleapp to work is line 15 of index.php It should be changed from:

require_once(”);

to:

require_once(‘exampleapp/config.php’);

Posted by: derek at June 6, 2004 01:22 PM

This kind of tutorial need us to understand deeply MOJAVI. Greate job! Thank’s in name of every beginner!

Posted by: hattila at June 7, 2004 04:59 AM

What can i do?????

error:

FATAL [/var/www/html/frameworks/mojavi-2.0.0/exampleapp/modules/Default/templates/index.php:11] Undefined index: name

Posted by: josx at June 14, 2004 02:12 PM

josx,

This problem is occurring because your PHP installation does not, for some reason, like that we are trying to get the value of $template[‘name’] which does not exist when this script is first run. Without more specifics on your installation (IIS or Apache, for instance) I can’t debug more. I would first try tweaking your errorreporting() level from EALL to something like EALL & ~ENOTICE. I hope that helps.

Posted by: Trenton Davies at June 14, 2004 02:29 PM

Re your reply to josx, ‘name’ isn’t set because the app isn’t setting it. The default action is Index; IndexAction::getDefaultView = VIEWINPUT; ViewInput::execute sets title and action but not name or phone. They should be initialised surely?

Conversely, DisplayView_success sets name and phone from user input but doesn’t set title, so that doesn’t work either!

In addition, config has URL_FORMAT = 2. AFAICS this will only work if the webserver is configured to handle it. OOTB it won’t be.

And just to confuse people even more, config has MODULEACCESSOR and ACTIONACCESSOR set differently from the mojavi default, so the url must be entered differently.

Ok, so your exampleapp is just for illustration, but it would surely be better if it worked. :-)

Would be good if the tutorial went through a couple of examples: “if you enter this url, this is what happens” sort of thing.

hth

Posted by: Peter Robins at June 16, 2004 11:23 AM

Thanks for the tutorial, it was quite enlightening. I actually had never heard of Mojavi before, but from this initial impression it seems I will be using it a whole lot in the future. Again, thanks.

Posted by: Tomas at June 28, 2004 04:27 PM

I’m still trying to figure Mojavi out, but this is really helpful. Thank you!

The links to http://dev.mojavi.org/images/diagrams/2.0/actionsequence.png don’t work, but http://mojavi.org/images/diagrams/2.0/actionsequence.png seems to work. I guess mojavi.org was reorganized with the release of 2.0.

Posted by: Jan Söderback at July 5, 2004 12:33 AM

Is there any real-world examples of a working application made with the Mojavi framework around? Would be interesting to understand how a CMS could be built around it. If it is treated as a module in the application or as a separate application?

Posted by: David Thunman at July 13, 2004 05:02 AM

Justr trying to use the default app, and I get the following: WARNING [/srv/www/vhosts/otherdevdot214/auth/webapp/mojavi-all-classes.php:842] A template has not been specified

but I have function & execute (&$controller, &$request, &$user) {

$renderer =& new Renderer($controller, ‘default_index.php’);

$renderer->setAttribute(‘examples_lib’, $controller->getModuleDir() . ‘lib/examples.inc’); $renderer->setAttribute(‘title’, ‘Index’);

return $renderer;

}

when i look at class renderer, i tried this

function execute (&$controller, &$request, &$user) { die(print_r($this));

and sure enough there is no template.

Posted by: aaron at July 28, 2004 10:02 AM

Mojavi may be the most value MVC framework for PHP as your declaration but it is missing any kind of samples, installation scripts and any kind of documentation. So it is rubbish for most of PHP programmers.

Posted by: Safecode at October 10, 2004 08:03 AM

Fortunately, most php programmers are crap. The real php programmers will use this, and they don’t need samples, installation scripts, or any crummy cms like php-nuke to box them into some kind of retarded concept. They will be the ones creating really huge projects based on php and mojavi, and will make good money while enjoying their work, knowing they are using a real framework, and not a spaghetti salad of code.

Skaag

Posted by: Skaag at November 9, 2004 11:59 AM

Who can help me,how use Mojavi,what config?

thanks,

Posted by: Tran Loi at November 1, 2005 12:47 AM

This tutorial is pretty clear by any beginner. Thanx to ad.hominem.org for giving us this. Hope this keep up.

Roberto Gandara Colombia

Posted by: rcgandara at December 29, 2005 08:13 AM

s—-, your comment script sucks, if i forget my name, in the error page my complete comment is lost…. better learn programming, I’m not gonna write the comment again here…

Posted by: h at January 23, 2006 07:38 AM

From a tutorial, I expect that somebody leads me through a process, explaining the underlying technology on the way. You only explain the framework (what I could do myself by looking at the code, as you already say) but give no hints at all what to do to get started quickly. So, I think, your tutorial is not very useful, because it is no tutorial and no howto, just an explanantion of mojavi’s sourcecode.

I don’t think examples are only needed by idiots, everybody understands better when having an explained example. Here is none unforunately.

Maybe this is a better/real tutorial: http://www.peterrobins.co.uk/it/mojavi/tutorial1.htm#mozTocId923783

So, if you’d call this here not tutorial, I’d like it :)

Posted by: bla at January 23, 2006 07:42 AM

This is really interesting is mojavi picking up many users? I’m wondering whether is would be a good platform to use. Does it integrate with smarty?

Posted by: Training at March 13, 2006 11:46 AM

You can try another MVC framework for PHP (PHP5) with many features, like: - actions - action-chains - wt-calls (call to web.template templates – on CVS version) - pre- and post- actions- with excaprions for same actions/action-chains - views – ass class (or template - CVS) - server-side validators - client-side validators (JavaScript) - AJAX – simple in use implementation of AJAX - support for DB configuration in framework configuration - support for DB connections (PDO, ADOdb or web.db) - support for template systems - by default for Smart and web.template (web.template required if you want to use wt-call block - CVS) - a router for making URLs nice-looking - tokens (for example for protect your form from resend by refreshing page) …

http://webframework.sourceforge.net/

Posted by: Marcin at March 23, 2006 03:59 PM

To my understanding, mojavi supports only Server-Side validation while Client-side (JavaScript) validations aren’t part of the framework.

Is this correct? If so, where and how would you recommend to implement such validations? (for example, as PHP code inside the templates which generates JS).

Eyal

Posted by: Eyal Carmi at April 16, 2006 08:22 AM

Mojavi only supports serverside validations.

If you wish to add client sided validation in conjunction with serverside validation built into Mojavi, all you need do is set up the javascript validation in your templates, with the lib.js (the javascript code which you will be using for validation )being in the root directory of mojavi

eg the mojavi dir will hold

index.php js/lib.js

So the templates will have a include to your javascript library.

I hope thats clear.

And Trenton, a very good article, was very useful when i was first trying to get my head around mojavi last year. cheers

Del

Posted by: Derrick at April 21, 2006 04:52 AM

who could tell me how to destroy the note which the system write to database by itself when a member login in! I use the PgSQLSessionHandler.class.php.But I don’t know to destroy the not.

Posted by: juan at May 8, 2006 05:52 PM

who could tell me how to destroy the note which the system write to database by itself when a member login in! I use the PgSQLSessionHandler.class.php.But I don’t know to destroy the not.

Posted by: juan at May 8, 2006 05:53 PM

Post Your Comment




Remember Me?