3

In my PHP web page (index.php), I have a simple script that calls a "page" class, and then builds the page from it.

Index.php executes methods within an instance of the 'page' class, such as "add_to_body("bla bla bla")". It can then call a "build()" method, where the page class will return a string with the user input and some other HTML elements pre-added in, that index.php can echo. Essentially the page class is a template of sorts.

I'm trying to have some kind of MVC hierarchy here (I'm a student learning about programming 'best practices' in my own time), my question is: would 'index.php' be a view? Or, would the instance of the page class be the view (as it constructs the page, but it doesn't actually show it, it returns a string), or: would the 'page' class be a controller?

Also, is a view 'allowed' to talk to (eg: get data from) a controller (for example: by calling a method that controller owns)?

Many thanks for your help!

3

generally the idea with a "View" is that its as 'dumb' as possible. it has the bare minimum of code to display the page. the "Model" is typically the methods talking to a database, validating data, creating and returning data structures - object, array, etc. the "Controller" is in the middle of the View and the Model.

so like if you have a contact form - the controller tells a model to validate the form data and add it to a database. if the model comes back with "validation failed" - the controller says - show this form again - and passes relevant data to relevant view. or if the model says "new contact added" - the controller says - show the thank you page.

when you are comfortable i would suggest taking a look at a basic php framework like codeigniter. it can make it easier to see how the MVC parts relate to each other.


response: the view should be separate file, and there should be separate view files for different needs. remove as much logic as possible from view files. this means you will end up having more files, but otherwise your view file "Knows" too much about your application. classic example is having some kind of check in a view file if the person looking at it has admin privileges. the view file should not know this. just make separate files.

in a small application you can combine controller and model in same file. and that is a good way to start - build out your application, and then as the methods become clear, you refactor the methods from the controller - into your models.

i would hasten to add that you should learn a php framework like codeigniter, even if just to see examples of MVC. the framework gives you a good starting place and you can also look at other peoples applications.

  • So in a PHP application, would the view, model and controller all ideally be different files? IE: View is the form, controller is the form's "action" attribute, and model is the class that the controller uses to connect to a SQL database? – BnMcG May 11 '13 at 7:29
  • responded above – cartalot May 13 '13 at 0:37
2

There are different approaches to MVC. An MVC architecture always consists of at least four parts.

  1. Dispatcher. Decides which controller is used.
  2. Controller. Makes decisions about models and views.
  3. Model. Does the data handling.
  4. View. Generates the output.

The two main approaches to MVC differ in the place, where the business logic comes in. One puts it into the model (Thin Controller / Fat Model), the other into the controller (Fat Controller / Thin Model).

In your current implementation, index.php is the Dispatcher, and seems to contain the Controller, too. The Page class is the View. From your description I cannot tell, where the Model is; it should be in index.php, but likely there are parts of it in the Page class. It takes some experience to create a proper separation.

  • by Dispatcher - do you mean Routes? or? – cartalot May 13 '13 at 17:29
  • Yes, that's pretty much the same in this context. – nibra May 13 '13 at 20:07
0

Also, is a view 'allowed' to talk to (eg: get data from) a controller (for example: by calling a method that controller owns)?

Best practice is no, but a controller is allowed to pass a data to the view. Check out templating engines like Mustache.

I'm trying to have some kind of MVC hierarchy here (I'm a student learning about programming 'best practices' in my own time), my question is: would 'index.php' be a view? Or, would the instance of the page class be the view (as it constructs the page, but it doesn't actually show it, it returns a string), or: would the 'page' class be a controller?

Usually index.php become the front controller, or the bootstrap.

You create some folders: library, controllers, models, and views, then you load all them from the index.php.

Then you make a Route class in your libraries folder, that should be able parse the PHP REQUEST_URI into a controller class name, method name, and an array of parameters.

In your index.php, you could instantiate a new Route with the PHP REQUEST_URI to it, then you call the Route::build method, that should be able instiate a controller then call it's method that correspond to the parsed PHP REQUEST_URI. (Learn about call_user_func_array).

The controller's method will returns a string (from a view file, or whatever), then you could just print it to the browser.

Here i'll just give you a minimum example of MVC in PHP:

core.php

<?php

class Route
{
  protected $class;

  protected $method;
  protected $params = array();

  /**
   * Parse the given URI, if the URI is "site/article/10", then "site" will be
   * the controller class, "article" will be the method, and "10" will be 
   * the parameter.
   */
  function __construct($uri)
  {
    $segments = explode('/', $uri);

    foreach ($segments as $segment)
    {
      if ($this->class === NULL)
      {
        $this->class = ucfirst($segment);
      }
      else if ($this->method === NULL)
      {
        $this->method = $segment;
      }
      else
      {
        $this->params[] = $segment;
      }
    }
  }

  /**
   * Instantiate a controller class then execute the method with the parameters from 
   * the parsed REQUEST_URI.
   */
  function call(Database $database)
  {
    $controller = new $this->class($database);

    $response = call_user_func_array(array($controller, $this->method), $this->params);

    return $response;
  }
}

class Controller
{
  function __construct(Database $database)
  {
    $this->database = $database;
  }

  /**
   * Instantiate a model
   */
  function model($name)
  {
    $model = new $name($this->database);

    return $model;
  }
}

class View
{
  protected $data = array();
  protected $path;

  function __construct($path, array $data = array())
  {
    $this->path = $path;
    $this->data = $data;
  }

  function render()
  {
    // Extract the data so you can access all the variables in
    // the "data" array inside your included view files
    ob_start(); extract($this->data);

    try
    {
      include $this->path;
    }
    catch(\Exception $e)
    {
      ob_end_clean(); throw $e;
    }

    return ob_get_clean();
  }

  /**
   * Make it able for you to write a code like this: echo new View("home.php")
   */
  function __toString()
  {
    return $this->render();
  }
}

class Model
{
  protected $database;

  function __construct(Database $database)
  {
    $this->database = $database;
  }
}

class Database
{
  function __construct()
  {
    // Connect to the database, for example: mysql_connect($host, $user, $pass, $data)
  }

  function query($sql)
  {
    // Do some database query like usual, for example: mysql_query($sql)
  }
}

index.php:

<?php

require "core.php"

class Article extends Model
{
  function find($id)
  {
    // You execute query through $this->db->query("SELECT..."), but i'll just use an array
    // to simplify things.
    return array("title" => "Article", "body" => "Lorem Ipsum");
  }
}

class Site extends Controller
{
  function article($id)
  {
    $article_model = $this->model("Article");

    // This is how you use the view class!
    $view = new View("article.php", array("article" => $article_model->find($id)));

    return $view;
  }
}

// This is where everything starts
$route = new Route("site/article/10");
echo $route->call(new Database());

article.php:

<h1><?php echo $article['title'] ?></h1>
<p><?php echo $article['body'] ?></p>

Put article.php, index.php, and core.php in one folder then run the index.php from your browser.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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