MVC and PHP

Not for 'how-to' coding questions but PHP theory instead, this forum is here for those of us who wish to learn about design aspects of programming with PHP.

Moderator: General Moderators

Post Reply
timclaason
Forum Commoner
Posts: 77
Joined: Tue Dec 16, 2003 9:06 am
Location: WI

MVC and PHP

Post by timclaason »

In the past, when I've had big database applications in PHP, I've put pages together like this (kind of a crude example):

form1.php

Code: Select all

<FORM METHOD='POST' ACTION='somepage.php'>
<TABLE>
<TR>
<TD>Field 1</TD>
<TD><INPUT TYPE='TEXT' NAME='whatevername'></TD>
</TR>
</TABLE>
<INPUT TYPE='SUBMIT' VALUE='Submit'>
</FORM>
somepage.php

Code: Select all

$post1 = $_POST['whatevername'];
$obj->doSomethingWithPostVariables($post1);
However, if I have a form with a bunch of fields, any changes result in a lot of work.

If I'm understanding MVC concepts correctly (and I'm not claiming that I am), I would think a better way to build applications would be to:
1. Have a database table that links each page with what fields a particular page's form should have
2. On the form page, populate the form with data from table in step 1.
3. On the post page, have the page determine the referrer (or perhaps pass it through as a querystring
4. Then have a method for the post page to extract the fields the referring page should have posted
5. Then the post page can do what it needs to with the posted variables

If it were done like this, it seems like it would be a good way to separate view components, and be more MVC-compliant.

Am I understanding MVC correctly, here? Does doing it this way make sense?
Begby
Forum Regular
Posts: 575
Joined: Wed Dec 13, 2006 10:28 am

Post by Begby »

No, thats not really MVC.

MVC is about separation of concerns and splitting up what happens on pages.

The view is only concerned about displaying data. You pass the view some data, and it displays it with no logic involved. (although often a bit of logic is required).

The controller takes input, grabs your model and sends it data, gets data from the model based on the input, passes data to a view, then sends the view to the client to see.

The model is where the business or domain logic goes. This is usually a set of classes that interface with a database and has logic to filter the data, get the data, save data, etc.


If your site is written using MVC well, then the model and the view can function completely independently. You should be able to create a view and send it some data without calling your model, and you should be able to write a command line script that uses nothing but your model to retrieve and save data.


Anyways, read more about it or post back here with further questions.
User avatar
kyberfabrikken
Forum Commoner
Posts: 84
Joined: Tue Jul 20, 2004 10:27 am

Post by kyberfabrikken »

Begby wrote: The controller (...) gets data from the model based on the input, passes data to a view, then sends the view to the client to see.
In MVC, the controller shouldn't tell the view, which model to use. The controller isn't a mediator between model and view. Think of controller as write-interface to model, and view as read-interface to model.

I'm nitpicking here, but this is a very common misconception, so I can't help my self.
Begby
Forum Regular
Posts: 575
Joined: Wed Dec 13, 2006 10:28 am

Post by Begby »

In my code though I don't tell the view which model to use or anything like that. Instead the controller takes the input, like maybe an ID, then passes it to the model. The model uses that ID to look up some data and then return it to the controller. The controller then takes that data and passes it to the view.

Is this correct?
alex.barylski
DevNet Evangelist
Posts: 6267
Joined: Tue Dec 21, 2004 5:00 pm
Location: Winnipeg

Post by alex.barylski »

kyberfabrikken wrote:
Begby wrote: The controller (...) gets data from the model based on the input, passes data to a view, then sends the view to the client to see.
In MVC, the controller shouldn't tell the view, which model to use. The controller isn't a mediator between model and view. Think of controller as write-interface to model, and view as read-interface to model.

I'm nitpicking here, but this is a very common misconception, so I can't help my self.
How then is the View supposed to be aware of which data to use?
timclaason
Forum Commoner
Posts: 77
Joined: Tue Dec 16, 2003 9:06 am
Location: WI

Post by timclaason »

Consider the following crude example:

page1.php

Code: Select all

$id = $_SESSION['id'];
$name = $obj->getName($id); //getName() returns a value from a db
$address = $obj->getAddress($id);
$city = $obj->getCity($id);

Code: Select all

<FORM METHOD='POST' ACTION='page2.php'>
<TABLE>
<TR>
<TD>Name</TD><TD><INPUT TYPE='TEXT' NAME='uname' VALUE='[syntax=php]$name
'></TD>
</TR>
<TR>
<TD>Address</TD><TD><INPUT TYPE='TEXT' NAME='uaddress' VALUE='

Code: Select all

$address
'></TD>
</TR>
<TR>
<TD>City</TD><TD><INPUT TYPE='TEXT' NAME='ucity' VALUE='

Code: Select all

$city
'></TD>
</TR>
</TABLE>
<INPUT TYPE='HIDDEN' NAME='id' VALUE='

Code: Select all

$id
'>
<INPUT TYPE='SUBMIT' VALUE='SUBMIT'>
</FORM>
[/syntax]

page2.php

Code: Select all

$id = $_POST['id'];
$name = $_POST['name'];
$address = $_POST['address'];
$city = $_POST['city'];

if(isset($id, $name, $address, $city)) {
   $obj->setName($id, $name); //Update DB, set name=posted name
   $obj->setAddress($id, $address);
   $obj->setCity($id, $city);
}
else {
   print("Input error.   All fields are required.  <a href='page1.php'>Click Here</A> to try again");
}
All in all, I interpret each as the following:
View: page1.php: The form (including variable values), the print() from the "else" statement from page2.php
Controller: page1.php: getName(), getAddress(), getCity(); page2.php: setName(), setAddress() setCity()
Model: page2.php: if, else

Am I wrong in this interpretation
Begby
Forum Regular
Posts: 575
Joined: Wed Dec 13, 2006 10:28 am

Post by Begby »

Here is an example from a Zend Controller that I am working on right now, the URL for this is something like

https://mysite.com/users/edit/id/10

Code: Select all

// This object is the controller, it handles requests from the client to do stuff.  In this case the user asked to edit a user, so the controller
// will call the edit action.

class UsersController extends zFCP_Controller_Action
{

	public function editAction() 
	{
		$id = $this->params()->requireInt('id') ;   // Get input
		
		$model = new FCP_User_Mapper($this->db()) ;  // Get the model
		
		$user = $model->findByID($id) ;  // Use the model to fetch some data
		
		if ($user === false)  // Do a bit of error checking
		{
			throw new FCP_Exception('Invalid ID param specified') ;
		}
		
                // Pass the view some data, then render it using a template
		$this->view->user = $user ;
		$this->view->actionURL = $this->url()->get('update') ;
		$this->view->render('default/users/edit_form.phtml') ;

	}
}

Here is the view script

Code: Select all

<form name="user" method="POST" action="<?= $this->actionURL ?>">
	<fieldset>
		<legend>Edit User</legend>
		<label for="username"><em>*</em>Username:</label>
			<input type="text" name="username" id="username" value="<?= $user->getUsername() ?>" /><br />
		<label for="password">Password:<br /></label>
			<input type="password" name="password" id="password" /><br />
			<sub>Only enter a password if you would like to change the existing one</sub><br />
		<label for="password_match">Retype Password:</label>
			<input type="password" name="password_match" id="password" /><br />
	</fieldset>
	<input type="submit" value="Save" />
</form>
Here is the method in the model that fetches a user

Code: Select all

public function findByID($id)
	{
		$sql = "SELECT
					authID, authUsername
				FROM
					tblAuth
				WHERE
					authID = ?" ;
		
		$row = $this->db()->fetchRow($sql, array($id)) ;
		
		if (!$row) return false ;

		$user = new FCP_User() ;
		$user->setID($array['authID']);
		$user->setUsername($array['authUsername']);

		return $user
	}
Last edited by Begby on Tue Jul 24, 2007 9:15 pm, edited 1 time in total.
Begby
Forum Regular
Posts: 575
Joined: Wed Dec 13, 2006 10:28 am

Post by Begby »

Here is another example of a very simple MVC that doesn't completely adhere to the pattern nor has any security whatsoever. The url might look like

https://mysite.com/users.php?action=edit&id=10


users.php

Code: Select all

switch ($_GET['action']) 
{
  case 'edit' :
    include('user_edit.php') ;
    break ;

  case 'delete' :
    include('user_delete.php') ;
    break ;
}

user_edit.php

Code: Select all

$sql = "SELECT * FROM users WHERE userID = $_GET['id']" ;
// run my query and fetch the results into $rows


foreach ($rows as $row)
{
  echo $row['username'] . '<br />' ;
}

In this case users.php is the controller. It looks at the user request and loads the corresponding action script, in this case edit. The model here is the database which is accessed directly from the script, and the view is also in the same script which is the foreach.

Moving towards true MVC takes the above and breaks it up even more so that it is separated further into classes and functions. The above works ok because it is simple, but more complex code will begin to become a disaster if you have a ton of logic all over in the script and then have HTML mixed in everywhere.
Begby
Forum Regular
Posts: 575
Joined: Wed Dec 13, 2006 10:28 am

Post by Begby »

So in conclusion, you should dive in and start using an MVC framework. That will give you an idea of how it works.

A good one to start with is probably codeignitor. It has a lot of really good documentation and you can start out with just SQL right in the controller as your model until you get used to the whole controller/view thing.
User avatar
kyberfabrikken
Forum Commoner
Posts: 84
Joined: Tue Jul 20, 2004 10:27 am

Post by kyberfabrikken »

Hockey wrote: How then is the View supposed to be aware of which data to use?
You program it that way.
Begby wrote: In my code though I don't tell the view which model to use or anything like that. Instead the controller takes the input, like maybe an ID, then passes it to the model. The model uses that ID to look up some data and then return it to the controller. The controller then takes that data and passes it to the view.

Is this correct?
I'd rather not use the terms correct and wrong. MVC is often overkill, and you may be better off with a harder coupled V+C. A lot of self-proclaimed MVC-based frameworks/applications do in fact have a tightly coupled C+V (presentation layer). So they are more correctly explained as model-presentation than model-view-controller. (Eg. view and controller have merged into one entity)
timclaason wrote: Consider the following crude example:
(...)
All in all, I interpret each as the following:
View: page1.php: The form (including variable values), the print() from the "else" statement from page2.php
Controller: page1.php: getName(), getAddress(), getCity(); page2.php: setName(), setAddress() setCity()
Model: page2.php: if, else

Am I wrong in this interpretation
The model is represented by $_SESSION, as well as $obj (Which it isn't clear where comes from).
page1.php is clearly part of the view. You use a template view pattern, so presumably the HTML is a template, and thus also part of the view.
page2.php is mostly controller code, although you have a bit of view code in there (The print statement), so it's not a completely clear-cut case.
thinsoldier
Forum Contributor
Posts: 367
Joined: Fri Jul 20, 2007 11:29 am
Contact:

Post by thinsoldier »

Begby wrote:Moving towards true MVC takes the above and breaks it up even more so that it is separated further into classes and functions. The above works ok because it is simple, but more complex code will begin to become a disaster if you have a ton of logic all over in the script and then have HTML mixed in everywhere.

What if stuff in my classes determines whether or not certain parts of the html get displayed or not (or have different classnames)?
that's why I still haven't used any of the templating systems. It just seems like an unnecessary layer that adds the unnecessary limitation of not allowing php to be used to make the markup react to certain things in the data.
User avatar
Christopher
Site Administrator
Posts: 13596
Joined: Wed Aug 25, 2004 7:54 pm
Location: New York, NY, US

Post by Christopher »

Using PHP as a templating language is fine and sometimes the best choice. Using non-PHP templates can have the benefit of allowing non-programmers to modify the templates without the security or error creation risks.
(#10850)
Post Reply