Controllers and Actions in MVC

if it’s truly a “static page” then why are you going via PHP to load it? The answer, of course, is that you want to do something with that HTML such as nest it inside another view.

HTML is just data, a simple string (usually) loaded from a file. The HTML is the data in this scenario and the contract between the model and the view is that the model will return a string (or a string of HTML), which the view can then use to do something with. Loading a file is certainly the responsibility of a model and not a view. The views job is to format the data from the model. If the format of the data is already that which the model provides it, well, it doesn’t need to do anything.

When I first mentioned ‘static page’ in this thread I meant a page where all data is hardcoded in the view therefore no model is necessary.

Later TomB expanded on the static page implementation so that the page’s content could be loaded from somewhere like a db. Then the model becomes necessary. Such a page is not as static as the one in the previous case because the content is loaded dynamically from somewhere. We may use the term ‘static’ to mean different things here.

Out of curiosity, if the HTML “data” could only be retrieved by rendering a template (which is an extremely common scenario), then is that still the responsibility of the model? If loading a file is “certainly” the responsibility of a model and not a view, then is it the model’s job to load templates?

Actually, nevermind. I’ll butt out. Sorry for turning this thread debate-ish. I’ll stop injecting myself into the conversation.

Actually, nevermind. I’ll butt out. Sorry for turning this thread debate-ish. I’ll stop injecting myself into the conversation.

It’s a good question so I’ll answer it anyway! Debates are good, there isn’t a right/wrong answer with anything at this level. Some answers are better than others, but it’s how you define “better” that makes a rather large difference and that’s certainly up for debate.

The view shouldn’t be concerned with how its template was constructed (Standard dependency injection arguments apply).

Ideally your view would look like this:


class TemplateView {
	public function __construct(Template $template, Model $model) {		
	}
}

And, for what its worth, the template shouldn’t be concerned with loading files either:


//A basic factory for constructing template objects from files
class TemplateFileLoader {
	public function loadTemplate($file) {
		return new Template(file_get_contets($file));
	}
}

class Template {
	public function __construct($html) {
		$this->html = $html;
	}
}

The view would then do any processing/variable assignment to the template. Where that template comes from is not a concern of the view. The implementation details of how views actually work is beyond MVC but loading a template is definitely a different responsibility to rendering/processing it. The view could load the file, but it does limit flexibility quite severely as the logic contained within the view is only usable with that one template.

So a view which displayed static templates, would take a template, no model, and simply render it without any additional logic.

One option is to have the view ask the model for the template file location but then the template must be loaded from the filesystem in a very specific manner by the view. Alternatively you could have the view ask the model for the fully constructed template object. This works, but itself limits flexibility because then the model is supplying both the template and the data that’s going to be used in the template. Of course, the model is then exposed to implementation details of the view (it knows the view will use templates), breaking encapsulation. As with most of these things, the simplest, and purest solution in OOP terms is the best. Pass the fully constructed template as a dependency to the view as in my example above.

I agree that injecting a templating library/component is definitely the best option. Though, I expect the view would still need to decide for itself which template to render, because the template may need to vary depending on the user input (a result from the controller). For instance, if user input doesn’t validate, then the view may need to render a form with errors. Or if the input does validate, then the view may need to render a success message or perhaps a redirect response. Though, I definitely don’t think the model should be involved with the templates in any way, shape or form. The model is supposed to be about domain logic, and templates are about presentation.

For what it’s with worth(not much) I find these discussions interesting but no MVC framework that I’ve come across is even a close contender to the elegant simplicity of Rails.
So, if I were using PHP I would try to implement the conventions and methods of Rails because I think they make a lot of sense.

I’d try to implement code that looked something like this… lots of psedo code and I haven’t written php in years.

I would set up routes somewhere which map HTTP to a controller and action

routes


method url                 controller#action  helper_method
GET    /users              users#index        users_path
POST   /users              users#create       users_path
GET    /users/new          users#new          new_user_path
GET    /users/:id/edit     users#edit         edit_user_path(user)
GET    /users/:id          users#show         user_path(user)
POST   /users/:id          users#update       user_path(user)
POST   /users/:id/delete   users#delete       delete_user_path(user)

The model should contain the validations

models/user.php


class User extends ApplicationModel {
  public $name = ''
  public $email = ''
  
  public function validate() {
    $errors = [];
    if ($this->name == '') {
      $errors['name'] = 'Name cannot be blank';
    }
    if (!filter_var($this->$email, FILTER_VALIDATE_EMAIL)) {
      $errors['email'] = 'Email is invalid';
    }
    return $errors
  }
}

The controller should expose methods to the view to consume data as well as handling params to the actions and deciding what to do

controllers/users_controller.php


class UsersController extends ApplicationController {
    
    // expose an api to the views
    public function users {
      return User.all()
    }
    
    public function user {
      if (params('id')) {
        return User.find(params('id'))
      }
      else {
        $user = new User
        if (params('user')) {
          $user.attributes(params('user'))
        }
        return $user
      }
    }
    
    // actions
    public function create() {
      if (user().save()) {
        flash('success', 'User created!');
        redirect_to(users_path());
      }
      else {
        flash('error', 'Errors');
        render('new');
      }
    }

    public function update() {
      if (user().save()) {
        flash('success', 'User created!');
        redirect_to(users_path());
      }
      else {
        flash('error', 'Errors');
        render('new');
      }
    }
    
    public function delete() {
      user().delete()
      flash('success', 'User deleted!');
      redirect_to(users_path());
    }
}

The view should have access to the exposed methods of the controller and helper methods like named routes and flash

views/users/index.php


<h1>Users</h1>
<ul>
<?php foreach (users() as $user) { ?>
  <li><?php echo $user.name ?></li>
<?php } ?>
</ul>

views/users/show.php


<h1><?php echo user().name ?></h1>
<p>Email: <?php echo user().email ?></p>

views/users/new.php


<h1>New User</h1>
<form action="<?php echo users_path() ?>" method="post">
  <?php render('form') ?>
  <input type="submit" value="Create">
</form>

views/users/edit.php


<h1>Edit User</h1>
<form action="<?php echo user_path(user()) ?>" method="post">
  <?php render('form') ?>
  <input type="submit" value="Update">
</form>

views/users/_form.php


<div>
  <label for="user_name">Name</label>
  <input id="user_name" name="user[name]" value="<?php params('user[name]') ?>">
</div>
<div>
  <label for="user_email">Email</label>
  <input id="user_email" name="user[email]" value="<?php params('user[email]') ?>">
</div>

I’d have an application layout which renders the views

views/layouts/application.php


<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>untitled</title>
</head>
<body>
<?php if (flash('error')) {
  <div id="error"><?php echo flash('error') ?></div>
<?php } ?>
<?php if (flash('success')) {
  <div id="success"><?php echo flash('success') ?></div>
<?php } ?>
<div id="content">
  <?php render_view() ?>
</div>
</body>
</html>

I’d abstract everything that you want to be able to reuse across your models controllers and views into a separate part of the app.

framework/application_model.php


class ApplicationModel {
  
  public static function all() {
    // select * from <pluralised lowercased __CLASS__>;
  }
  
  public static function find($id) {
    // select * from table where id=$id;
  }
  
  public function save() {
    $errors = $this->validate()
    if ($errors.length == 0) {
      // UPDATE table where id=$id
    }
    else {
      return false;
    }
  }

  public function delete() {
      // DELETE FROM table where id=$id
  }
  
  public function attributes($attributes) {
    foreach($attributes as $attr => $value) {
      $this->$attr = $value
    }
  }
  
}

framework/application_controller.php


class ApplicationController {
  public function params($key) {
    // map nested params ?user[name]=mark&user[email]=markbrown4@gmail.com
    // params('user') == { name: 'mark', email: 'markbrown4@gmail.com' }
    // params('user[email]') == 'markbrown4@gmail.com'
  }
  
  public function redirect_to($url, $flash) {}
  
  public function flash($key, $value) {
    // set a short lived variable in session
  }
  
  public function render($view) {
    // render a view from a controller
  }
  
  // 7 rest actions
  public function index() {}
  public function show() {}
  public function new() {}
  public function edit() {}
  public function create() {}
  public function update() {}
  public function delete() {}
}

framework/application_view.php


class ApplicationView {
  public function flash($key) {
    
  }
  public function render($partial) {
    // render '_$partial.php'
  }

  public function render_view() {
  }
}

I just thought this may give you some ideas to play with.

I was going to say… it looks like you just provided pseudo code for replicating a rails like interface in PHP. Not that it’s a bad thing…

Bingo, we can debate all day that rails is not true MVC but the fact of the matter is the web based derivation of MVC exists because it works very well in a none persistent environment using http.

I would recommend the op use Symfony 2 instead re-inventing this wheel. Not to mention Symfony 2 goes way beyond MVC providing strategies for managing dependencies to promoting package management (similar to gems) using composer. Though if the op really has an itch to reinvent the wheel more power to them I guess…

Aye, I’m not familiar with any of the PHP MVC frameworks out there, I’d heard Cake was Rails inspired but I haven’t explored it.
You’re right, those frameworks should be a heck of a lot better than something you can write from scratch - It sounded like the OP was wanting to try to do that though, “what is a good way to implement MVC in PHP?”

What is the least and most expressive code you can write to get the task done?

I think it depends on what you wish to accomplish here. Reinventing the wheel is not recommended for working on a project with a strict timeline, especially for commercial project. However, if your primary goal is to learn the basics behind MVC and true OOP, building your own framework will help you a lot.

Yes, I’m experimenting with the concept to understand how it works in detail and if it proves to be worthwhile I’ll start implementing it in my projects. That’s why I’m starting from scratch. The other reason is that it’s hard to find a ready-made framework that would be pure MVC - and because I have already worked with frameworks that are MVC-like to a greater or lesser extent (including my own that works very well for commercial projects) I have no intention dabbling with them. It’s not that I find them bad, I just want to see how MVC plays out in its purest possible implementation and possibly simplest as well. Most frameworks are huge, I want something simple but good and add to it over time as my requirements grow.

You will learn a lot doing that, I’d encourage you to focus on the API and DRY, how much code can you get away with not writing.
I’m curious why you’re interested in a ‘pure’ implementation. Surely it’s more valuable to have the best implementation :wink:

You may be interested in Fowler’s (non-PHP) article on MVC, as well as the (I believe) [URL=“http://st-www.cs.illinois.edu/users/smarch/st-docs/mvc.html”]original implementation in Smalltalk. Personally, what strikes me is just how little is actually applicable to server-side Web applications. So at the very least, it should be interesting to see what you come up with.

Yeah, in this case Id strongly recommend you to create your own framework since you’re better off improving your skills this way.

It is one thing to create your own framework for learning purposes. It is a whole other thing to deploy that code for production us where there are several other more robust, documented and maintained solutions.

Partly because there are people who seem to realise value of proper MVC in terms of flexibility and reusability so I’d like to test it out. It looks to me that the original principles of MVC are good in encouraging separation of concerns - and that is where I’m intending to improve my skills now. And I think as a side effect of creating the framework I will be able to apply the rules also for code that is framework agnostic.

Thanks, I’ll definitely read it. I realise that the pattern needs to be adapted to web applications. I’m also curious what I’ll come up with eventually :). But it’s not that fast - currently, I have real work to do for clients and have other priorities so I’m taking it slowly in my spare time.