64x64 icon dark hosting
Choose a hosting plan here and get a free year's subscription to Tuts+ (worth $180).
Advertisement

HMVC: an Introduction and Application

by
Gift

Start a hosting plan from $3.92/mo and get a free year on Tuts+ (normally $180)

This tutorial is an introduction to the Hierarchical Model View Controller(HMVC) pattern, and how it applies to web application development. For this tutorial, I will use examples provided from the CodeIgniter from Scratch series and demonstrate how HMVC can be a valuable modification to your development process. This introduction assumes you have an understanding of the Model View Controller (MVC) pattern. We suggest you read our introduction to MVC to get acquainted with the topic before tackling this tutorial.

What is HMVC?

HMVC is an evolution of the MVC pattern used for most web applications today. It came about as an answer to the salability problems apparent within applications which used MVC. The solution presented in the JavaWorld web site, July 2000, proposed that the standard Model, View, and Controller triad become layered into a "hierarchy of parent-child MCV layers". The image below illustrates how this works:

Each triad functions independently from one another. A triad can request access to another triad via their controllers. Both of these points allow the application to be distributed over multiple locations, if needed. In addition, the layering of MVC triads allows for a more in depth and robust application development. This leads to several advantages which brings us to our next point.

Why should I use HMVC?

Key advantages to implementing the HMVC pattern in your development cycle:

  • Modularization: Reduction of dependencies between the disparate parts of the application.
  • Organization: Having a folder for each of the relevant triads makes for a lighter work load.
  • Reusability: By nature of the design it is easy to reuse nearly every piece of code.
  • Extendibility: Makes the application more extensible without sacrificing ease of maintenance.

These advantages will allow you to get M.O.R.E out of your application with less headaches.

Setting up HMVC in CodeIgniter

To add extra depth to the CodeIgniter from Scratch series, we will be viewing today's examples in CodeIgniter. I will lead us though the steps needed to get CodeIgniter working with HMVC. Once we're done with that, I'll provide a couple of examples. Let's begin!

Preface

To run web applications, you need a web server on your computer if you are not working remotely. Here are recommendations with links to installation instructions:

Step 1. Download and Install CodeIgniter

Go to codeigniter.com and click the "Download CodeIgniter" link. If you know how to install it and want to skip past this step click here

Extract the contents of the zip file to your web server's document root.

Rename the "CodeIgniter_1.7.2" folder to "hmvcExample".

Move the "hmvcExample/system/application" folder to "hmvcExample/application". This is common practice with CodeIgniter. The purpose of doing this is to separate the application from the core of the framework. We should now have a directory that looks like the image below:

Open "hmvcExample/application/config/config.php" in your editor of choice.

Edit the site base url to match the location of your install. In my case I would change

into

Save your changes and close "hmvcExample/application/config/config.php"

Test that we have a working version of CodeIgniter. Open your browser and check your "http://yourhost/hmvcExample/".
You should be greeted with the "Welcome to CodeIgniter" screen below:

That's it! You have successfully downloaded and installed CodeIgniter. Now we will move on to making it work with the HMVC extension.

Step 2. Download and Install HMVC Extension

Download version 5.2 of the modular extension from the CodeIgniter Wiki.

In the contents of the zip file are three php files:

Move these three files into the "hmvcExample/application/libraries/" folder.

Recheck your browser. You should still see the Welcome to CodeIgniter screen.

It's time to add the modules. Create the following directory structure "application/modules/welcome/controllers/".

Move the "application/controllers/welcome.php" to "application/modules/welcome/controllers/welcome.php".

Recheck your browser. You should still see the Welcome to CodeIgniter screen.

Create the folder "application/modules/welcome/views/"

Move the "application/views/welcome_message.php" to "application/modules/welcome/views/welcome_message.php".

Do a final check on your browser. You should still see the Welcome to CodeIgniter screen.

That's it! Modular Extensions is installed correctly.

Login Module Example

Now that we have our HMVC enabled instance of CodeIgniter, I will demonstrate some short examples. For our first example I will show how you can apply user access restrictions to pages or entire modules.

Download and unzip CodeIgniter from Scratch Day 6 source files into your web server. You should end up with a folder called "ci_day6/" alongside our "hmvcExample/"

Create the "login" module in our "hmvcExample/application" directory. It should end up looking like this

Create the "site" module in our "hmvcExample/application" directory. It should end up looking like this

TIP: When working with modules I keep a folder named RENAME with the three empty folders controllers, models and views. This saves me a little bit of time anytime I wish to create a new model.

Now we copy over the login module files from "ci_day6/" to our "hmvcExample/".

Copy/Move each of the above files over as listed below

Next we copy over the site module files from "ci_day6/" to our "hmvcExample/".

Copy/Move each of the above files over as listed below

The last files to copy over are the global views and CSS and image files. The asterisk (*) denotes folder and all its contents including sub folders

Copy each of the above folders and all their content over as listed below

Open "hmvcExample/application/config/autoload.php" and edit it to look like the this:

If you have not already done so from step one, open "hmvcExample/application/config/config.php" and edit it so that the base url is set to your appropriate location.

Open "hmvcExample/application/config/database.php" and add the appropriate links to your database.

Open your browser to test that the login page displays "http://localhost/hmvcExample/index.php/login"

Now to make this login function, we need to create the membership database table. For this, we need to create a table in your PHPMyAdmin.

Select or create your "ci_series" database.

In the sQL tab, paste the code below into the textarea and click go

With the membership table created, we click on the create account link on the login page and add a user to the database.

Login in as the user and confirm that you are now in the "site/members_area" of the site. It should look similar to the image below:

Click "logoff" link and try to manually go back to the members area. you will see that you no longer have permission to do so.

So we have our triads grouped, but we are still not quite in HMVC mode yet. In the site controller we find a function called is_logged_in().

This is a login related function. In MVC mode, this is required because site cannot access login. With HMVC we can fix this.

Cut the is_logged_in() function out of "applications/modules/site/controllers/site.php"

Save site.php without the is_logged_in() function.

Open "applications/modules/login/controllers/login.php".

Paste the is_logged_in() function into the class.

Save login.php

Open "applications/modules/site/controllers/site.php".

In the __Construct() function, we make the HMVC call to login's is_logged_in() function, as seen below:

MVC 101 Complete

There you have it! We have successfully altered day six code into HMVC format. The site module now requests the login check instead of having to use its own. While outwardly we observe no difference, the site design has fundamentally been changed. All login functions are now where they belong: inside the login triad. This may seem like a lot of work with small reward but it is not so. Any login changes can be made once. The internal structure of the triad can be edited without having to change the entire application in response. Code replication for other controllers is no longer required. Last but not least, all the related code is in one handy location. This tiny step may not WOW you but when we delve deeper into bigger, complex applications, the M.O.R.E. apparent it will become how effective the HMVC pattern is.

Members Section Example

We are now going to uncover more of HMVC's power. We just demonstrated how to call a module from a controller. There are other places you can do that as well. HMVC was build with the User Interface (UI) in mind. We get to call modules from our views as a result. This is where the power of HMVC can really shine.

When calling HMVC from a view you will use the same modules::run(). There is only one requirement when doing this. The resulting output from the call must be a html snippet and not a complete view. This is because we are already inside a view at the time we call the run function. We will see this in action down the page as we edit the site module views.

Step 1. Edit Login Controller

We are going to create a block which appears on the top of every page with our user's name, important links, and logout option. Widgets like this are commonplace on sites today. The image below illustrates the end result.

Open "applications/modules/login/controllers/login.php".

Paste/Write the code above into the login controller.

cp() receives information from the membership_model function, get_member_details(), which we create in the next step. If a user is found we will display the view snippet detailed in step three. From there we should get the desired block illustrated above.

Save the changes you made to login.php

Step 2. Edit Membership Model

You will notice that we called a get_member_details() from the membership_model. This function gets our user information from the database and will be accessed from a few different sources. We are going to work on that now.

Open "applications/modules/login/models/membership_model.php".

Comment your code! It's a best practice and will help others understand what you wrote.

Line 01: The function call has a default variable $id. This allows us an option of finding a user by ID rather than by username. This made optional by setting it to false in the declaration.

The rest of the function is straight forward and well commented. We query the membership table for a user via username or ID. The result is saved to the $data array and returned. All other outcomes return false.

Save the changes you made to membership_model.php

Step 3. Create User Widget View

The third and final piece to the widget we are creating is the xhtml snippet, which we can put into any other view. This is called by the login controller's cp() function which we just wrote.

Open "applications/modules/login/views/user_widget.php".

Note: It is not a good practice to use inline styling. I opted to put this one instance of inline style for the sake of remaining on topic.

This styled code block takes the information passed from the cp() function. We generate the links using CodeIgniter's URL helper's anchor() function. More information about the user guide can be found on codeigniter.com.

After working on those three files we will test the "login/cp" page. We should see something like the image below. Note: You need to be logged int to see it. Be sure to do so before checking the page or you will see nothing.

Step 4. Edit Site Controller

The links in the snippet to profile and messages will return an error for the moment. This is ok because we have not created those functions yet. Lets do that now.

Open "applications/modules/site/controllers/site.php".

__construct()
For the purpose of this example we shall remove the...

...from the function so that we can make specific parts private and have other parts public.

members_area()
We want only logged in users to access the members dashboard area. So we will use the modules:run HMVC function and call the is_logged_in check from the login controller. We then load the logged_in_area view file which will be edited further down the page.

messages()
Like members_area(), we only want logged in users so we have included the is_logged_in check. We have already written the code on how to get user details from the database so we will load the login model, membership_model. This will allow us to get the user information via the get_member_details() function. The third URI segment being passed into that function is an id for the user we wish to get messages for. For example, if the url was:

Then our function get_member_details() would be receiving "43" as an input variable. Depending on the result of get_member_details(), we are either shown the view: member_messages or we get nothing (as a result of a failed query).

profile()
Just like any social network; we want the profile pages to be public. So we have not included the is_logged_in check. Just like messages, we call the login triad's membership_model and query the database for our desired user. In this case, if no user is found, we quit a bit more gracefully. We also notify the visitor that an id needs to be specified. With a successful result, we see the member's profile.

Step 5 Edit Logged In Area View

Open "applications/modules/site/views/logged_in_area.php".

Overwrite the contents of the file with the code above.

Line 08: HMVC is put into action here. Our view calls the "login/cp" function, and echoes out the html snippet exactly where we tell it. Notice how we didn't have to prepare anything ourselves? It's all handled internally by login for us. Handy isn't it?

Save the changes you made to logged_in_area.php. Your finished page should display like:

Step 6. Create Member Messages View

Create a new view: "applications/modules/site/views/member_messages.php".

Write or paste the code above into the newly created file.

This view is pretty much just a clone of the members area to test that login holds on multiple pages. There is one difference: we fished some information from the login module's membership_model. This is shown as the $first_name variable.

The point of getting user information here would be to pass it on to a module which would return a snippet with the user's messages.

Save the changes you made to member_messages.php. Your finished page should display like:

Step 7. Create Member Profile View

Create a new view: "applications/modules/site/views/member_profile.php".

Write or paste the code above into the newly created file.

We have an if statement which detects whether a user was found or not. If not, we get brought to an error page stating we need an ID to view a profile.

Again, we retrieve the user information. Just like messages we would use this to retrieve the user's friend list, latest blog entry, and activity feed, etc.

Save the changes you made to member_profile.php. Your finished page should display like:

What Happens When We Logoff?

Because we want the profile pages to be public, it should still display. Minus the user widget of course.

When logged in, and we go to profile without a third uri segment we see our own profile. Logded off, we will be shown the error below.

We should not be able to view the message or dashboard. When we check the messages page we are greeted with this:

We're Done

That's it! We have added more depth to our initial example and demonstrated the different ways to use HMVC.

  • Call modules::run() from a controller.
  • Echo modules::run() from a view to display a HTML snippet.
  • Load a model from another module.

I hope this has been an enlightening experience. HMVC is an extraordinary pattern which makes applications more robust. It is well worth the investment. Give it a try. I promise you won't ever want to go back to vanilla MVC!

Advertisement