Jimbo
Jimbo

Reputation: 26624

How to Implement MVC in PHP

Introduction

The Model-View-Controller approach has been in my head since before the holidays and I really need to get it down to a tee within my web application, created in PHP.

So far, I understand the general MVC Concept and why it's done, but I need some help. This is a University project, and my project adviser is not very helpful when I ask questions about MVC.

The Application

It's a task management system, or a to-do list. The aim is a very simple interface where the user can login with their Facebook account, create, modify or remove tasks, and logout, created with Javascript and PHP.

The Facts

I have a static PHP page here containing divs like "top_div" and "main_div". The aim is for "controller.php" to be included (I haven't created this yet) to serve between the view and the model.

Important: Everything on the page uses jQuery, so the user will never see a page refresh. I have a function that fades out the content in a div, grabs the newly required content, places it in the div (hidden, because the div has faded out), then fades in the div again.

The aim is for the controller to request from the model, then send back (for example) a Facebook login button to the view. This Facebook Login button is HTML. There will be others like text and html for the content, and if the user is already logged in "Welcome " will be sent to the #main_div using PHP, jQuery and cURL.

I am using objects, so from what I understand I will need to instantiate an object to do the database connection and queries. Where do I instantiate objects? I read that they are supposed to be created in the controller, but from everything else I've read the controller is meant to be simple, telling the model what the view wants acting only as the go-between. I was under the impression (and it makes more sense to me) for the model to instantiate objects.

1) So, please explain to me how it would be incorrect to instantiate objects in the model. If this wasn't the case, that'd be great as far as my understanding of the MVC approach goes.

Lets say the user has logged in. I will be displaying their name, and their Facebook picture on the view (index.php). If you visit the site on the link above you may see a small white box on the right where this picture will go. The code for the user's picture in PHP looks like this:

<img src="https://graph.facebook.com/'.$fbid.'/picture" width="79" height="64" align="center" style="opacity:0.8;">';

2) As this HTML will be passed to the view to be displayed into a DIV using the jQuery function described above, is it okay for my controller to have this sort of information going out? My controller may have something along the lines of (pseduo code):

if(user is logged in(from checking via model)) then { send to #main_div the html above };

I may think of loads more questions along the way with this, but please can someone help me understand more about what I'm doing?

Upvotes: 3

Views: 3850

Answers (7)

Vladimir
Vladimir

Reputation: 846

Let us start with the basics. To build a decent MVC framework first you'll need a bootstrap. A procedure which will figure out what your application needs to do. After it does that it needs to pass the data to the appropriate functions (classes). A good approach would be to have some sort of a routing table built with, for example, regular expressions and some defaults to point to when the expressions are not matched. For example it can be: /module/controller/action/params. A bootstrap should take care of all the initializations, reading configs, figuring out what to pass to where. For easing the coding you can create a structure with namespaces. For example you'll need controllers in one place and models and views in others. Since PHP < 5.3 doesn't support namespaces you can easily handle that with a directory structure namespaces. What that means is that a directory is your namespace and all files in it follow some pattern. That way you can easily load classes automatically. After you have that separate your classes in their appropriate namespaces. Your library classes can go to library/, your helper classes to helper/ etc. All controllers, which will handle your actual application logic can go to a module namespace. For example frontend/ and backend/. They will all need to extend your base controller class (loaded from the library/ namespace) which will handle the view initialization.

Upvotes: 0

jamesTheProgrammer
jamesTheProgrammer

Reputation: 1777

Separation of concerns.

Put you logic that renders the html in your php view files.

Put the javascript and css in their own files and reference them externally

Put your bus. logic in DAO (data access objects) - only they talk to the db, NOT THE VIEW files.

Create your controller as a normal php page, like index.php or controller.php if you like. Each request goes through the index or controller file. The controller file would include the external references to the javascript and css files.

Each call back to the controller would include a parameter and variable that would be used to determine where to pass control to. The controller would probably have a swich-case or if-else structure that would handle the specific requests. Something like this:

<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
<script src="assets/ajax.js" type="text/javascript"></script>

<link rel="stylesheet" type="text/css" href="assets/adminApp.css" media="screen" />
<link rel="stylesheet" href="assets/print.css" type="text/css" media="print" />

<?php
  require_once('../../config.php');
  require_once('../connect_db.php');
  require_once('../custom_boces_dao.php');
  require_once('../custom_boces_gateway.php');

  if(isset($_REQUEST['action'])){
    $action = $_REQUEST['action'];  
  }else{
    $action = "viewUserAttributes";
  }

 echo "<div id='leftNav'>";
   require_once('views/global_navigation.php');
 echo "</div>";

 echo "<div id='mainArea'>";

    switch ($action) {

      case 'home':
        echo "something to say";
      break;

      case 'viewCourseAttributes':
        require_once('views/course/frmCourses.php');
      break;

      case 'editCourseAttributes':
        require_once('views/course/frmCourses.php');
        require_once('views/course/frmCourseAttributes.php');

       break;
      .
      .
      .
 }      

 echo "</div>";

?>          

Upvotes: 0

dqhendricks
dqhendricks

Reputation: 19251

controller classes should handle all incoming requests to the server, then based-on the request, perform any actions on any model objects required, then pass any data needed to a view object, which then renders the page.

there are a million ways you could set this up. the basic idea is to keep your business logic separate from your view rendering (HTML).

some tips:

in many's opinion you should not allow models to load other models themselves. instead you would use the dependency injection pattern to reduce strong coupling. this basically means inserting any required objects through constructor or method arguments.

a lot of people will use what's called a dependency injection container. this is typically a class with one public method that is used to instantiate all other classes with the exception of the Controller class. in PHP 5.3 you would use closures to help lazy load any classes requested from the di container. the dic class may also store objects for later reuse if the object is one that will be shared (like a singleton), but you would always request the class the same way from the dic regardless. the point of this is, if you ever have the need to change the way a class is instantiated, or would like to swap it with an extended class, or other class that uses the same interface, this type of modification can all be done in one place in your code instead of many. it also helps keep your controllers "light".

Upvotes: 0

Andrew
Andrew

Reputation: 239097

I would recommend looking at some other libraries that exist to make using MVC in PHP easier (at least as an example to wrap your head around how other people are doing it). A few that come to mind are:

  • Zend Framework
  • CakePHP

...then when you're ready to really improve your code ;) check out these Ruby libraries:

Upvotes: 0

Teson
Teson

Reputation: 6736

First, your static php-page doesn't include the controller. It's the other way around, your controller includes your static php-page (view).

For a KISS, add some

<!--parsableTags!-->

to your view and load corresponding models to fill those tags. Let the controller fire back the result to the calling browser.

ADDITION:

DB logic in controller or not? There are no absolute truth here, your application may speak mostly to an LDAP so why then load a db-service? What you want is probably a config, read by the controller at startup to load initial components.

Some believe only views should generate html, it's a good principle but may drive you mad at 1 o'clock.

But in the end there's so many different ways to do it.

Upvotes: 0

Jeremy Kendall
Jeremy Kendall

Reputation: 2869

1) So, please explain to me how it would be incorrect to instantiate objects in the model.

It's not incorrect at all. The goal is thin controllers and fat models, however, so I do object creation in my controllers and let the models/services do the heavy lifting.

Caveat: It's best to do object creation somewhere else, in a bootstrap, perhaps, and use dependency injection to feed those objects to your controllers. That being said, much of my object creation happens in the controller as needed.

2) As this HTML will be passed to the view to be displayed into a DIV using the jQuery function described above, is it okay for my controller to have this sort of information going out?

Yes, it is. The controller will pass data from your model to the view.

MVC framework recommendations

Unless you just want to, or have to, don't roll your own MVC. Pick a framework, do a little studying, and win.

Upvotes: 1

Derek Wright
Derek Wright

Reputation: 1492

Generally most all of your code should be object based. The "Controller" portion will operate on user requests. So lets say a person requests "www.you.com/?login", the controller should get the request to "login". The controller (sometimes refered to as a router) will instantiate the proper "Model" object to handle login. In this case it may just be creating the model (login) object with no data that tells the controller to display "view-login". The controller then goes to the view object code and give it the proper view to display and the view object returns the rendered HTML page with a login form.

Once the user submits his creds, the request would be "POST:action=login,username=blah,password=12345". The controller would then see that it needs to invoke the login object and pass parameters username/password to the login "model". The login model logic would process the parameters and then send to the controller display "view-login,success". The controller would then tell the view object to display this view with the appended parameters and the view object would render the page and output it.

This can continue to be expanded upon during your app coding. Using autoload functions you can even have your Controller scan directories for a model/view and dynamically instantiate the requested object or fallback on a default object if one does not exist. This way you dont need to modify your controller everytime you add model/view logic. Another benefit is a single entry point into your application such as all URLS will be www.you.com/?login or www.you.com/?task=2&action=delete ... so on and so forth. Do lots of reading and dont get frustrated when writing one of your own. You will probably scrap your work a couple of times before you really get a feel for how you want your MVC to behave.

Good reading: http://oreilly.com/php/archive/mvc-intro.html

Upvotes: 1

Related Questions