MVC Without a Framework
Published Friday, July 17, 2009 in Unfinished Articles
MVC is a programming design pattern that encourages separation of data, presentation and logic. Many frameworks are built on MVC but you don't necesarily need a framework to structure your code in an MVC manner.
This tutorial will try to explain how you can start using MVC today, with nothing but standard PHP. We will build a very simple blog/article publishing system. I will not cover comments or tags but after this article you should be able to easily add it yourself.
First I thought I'd try to, in a very basic way, explain each letter in the acronym. There's definitely more to it than this and I recommend you pick up a book on the area if you're really interested.
M
M in MVC stands for "model" and is supposed to be a model of your data. This could be anything from a database table to a set of files you treat equally. Basically, what we want to use the model for is anything that has to do with our data.
In the case of our blog we'll have one model called "Articles" which will handle everything that has to do with articles. Any time you want to edit, fetch, insert or delete articles you will use the model. There should be no (in this case) SQL-queries outside the model.
V
V stands for "view" and is a visual representation of your data. In the case of our articles this will be a list of the latest 5 or so articles in summary on the front-page and the whole article on each article page.
When doing web development most of your views will be HTML, but we'll create an RSS-feed as well and that will obivously be just that; RSS.
C
C stands for "controller" and its job is to either fetch, insert or delete data using the model, and then pass it on to the view so it can be displayed.
Depending on different user input the controller can do different things. For example, most blogs allow comments and the comments controller can display either the form for posting comments, or, after a comment has been posted, it might display a "Thank you"-text or similar.
The controller should handle all the logic behind a certain part of your application. The view should be nothing but presentation that is based on what the controller decides.
Modular Design
Many frameworks that use MVC treat one controller as one page on the site. Personally I prefer to structure my code in a more modular manner where each and every unique part of the page has one view and one controller. That way it can be moved around or deleted with a breeze.
Directory Structure
We'll put all our views and models in directories named the same. Each view will contain both the PHP logic and the HTML. This is a bit unorthodox but we'll still separate the logic from the presentation. In some cases the view won't even need any logic though, and in most cases only a few lines of model-calling is required. I've done it this way for simplicity but you could pretty easily separate the view and controller completely by providing a class or separate file with all the logic for each view.
For every different page on the site we'll create a very simple PHP-file in the root-directory that does nothing but include views. We'll only need 3 pages for our super-simple blog: home-page (displays the latest 5 articles), articles-page (displays all articles), article-page (displays one article).
Here's a list of all the dirs and files we'll create:
- models
- articles.php # the articles model - handles all communication with the articles table in the database
- views
- header.php # the header - contains all the stuff that's common to all page's heads
- footer.php # the footer - contains all the stuff that's common to all page's foots
- articles.php # the articles view - displays more than one article
- article.php # the article view - displays one article
- articles-rss.php # the articles RSS feed
- index.php # the home-page
- article.php # each article-page
- articles.php # list of all articles
The Articles Database Table
....
The Articles Model
We'll wrap the articles model in a class called Articles. We'll create a bunch of static functions for everything we ever want to do with articles. We don't have to come up with everything now, it's OK to go back and fill this with functions as you need them. I've seen models that are several thousand lines of code :)
class Articles {
/**
* getArticles
*
* Retrieves articles based on params
*
* @param $sort String - which column-name to sort the results by
* @param $order String - in which order to sort them ('ASC' or 'DESC')
* @param $start Int - where to start fetching articles from
* @param $limit Int - how many articles to fetch
* @returns $articles Array || false - an array of all articles or false if no articles matched the criteria
**/
public static function getArticles ($sort = '1', $order = 'ASC', $start = 0, $limit = 1000000000) {
$articles = array();
$qry = '
SELECT
*
FROM
articles
ORDER BY
' . mysql_real_escape_string($sort) . ' ' . mysql_real_escape_string($order) . '
LIMIT
' . mysql_real_escape_string($start) . ' ' . mysql_real_escape_string($limit) . '
';
$res = mysql_query($qry) or die(mysql_error() . $qry);
if (mysql_num_rows($res)) {
while ($row = mysql_fetch_assoc($res)) {
$articles[] = $row;
}
return $articles;
}
else {
return false;
}
}
/**
* getArticleBySlug
*
* Retrieves one article based on slug (URL)
*
* @param $slug String - the article's slug
* @returns $article Array || false - article array or false if no article existed
**/
public static function getArticleBySlug ($slug) {
$qry = '
SELECT
*
FROM
articles
WHERE
slug = "' . mysql_real_escape_string($slug) . '"
LIMIT 1
';
$res = mysql_query($qry) or die(mysql_error() . $qry);
if (mysql_num_rows($res)) {
return mysql_fetch_assoc($res);
}
else {
return false;
}
}
/**
* deleteArticle
*
* Deletes an article based on ID
*
* @param $id Int - the article's ID
**/
public static function deleteArticle ($id) {
mysql_query('DELETE FROM articles WHERE articles_id = ' . mysql_real_escape_string($id));
}
/**
* updateArticle
*
* Updates an article based on ID
*
* @param $id Int - the article's ID
**/
public static function updateArticle ($id) {
# Homework :)
}
/**
* insertArticle
*
* Inserts a new article
*
* @param $article Array - An article array
**/
public static function updateArticle ($article) {
# Homework :)
}
}
As you can see, with this class in our hands we can do everything we need to do with our articles. If we want the latest 5 articles we'll simply go Articles::getArticles('pub_date', 'DESC', 0, 5); and if we want the article on /test-article/ we'll simply go Articles::getArticlesBySlug('test-article');
Like I said, you can add more functions to this class any time you need to do something new with articles (like getArticlesByTagSlug() or getMostCommentedArticles() etc etc).
The Views
Like I mentioned before most of our views will be pure HTML but they'll also contain the necesary logic required to display their contents.
Header & Footer
These will contain the HTML that will be displayed on each and every page. Typically the html, head and body elements but also our logo and copyright-information.
Header
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
<meta http-equiv="Content-Style-Type" content="text/css" />
<meta name="author" content="You" />
<meta name="copyright" content="Copyright (c) 2010 You" />
<link rel="alternate" type="application/rss+xml" title="articles" href="views/articles-rss.php" />
<link rel="stylesheet" type="text/css" media="screen,projection" href="css/style.css" />
<title>My Blog</title>
</head>
<body>
<div id="wrapper">
<div id="header">
<h1><a href="/">MyBlog.com</a></h1>
<p>Just another MVC blog</p>
</div>
Footer
<div id="footer">
<p>Copyright © 2010 You</p>
<ul>
<li><a href="#" title="Top of Page">Top</a></li>
<li><a href="#" title="Get Firefox!">Firefox</a></li>
<li><a href="#" title="Valid XHTML">XHTML</a></li>
<li><a href="#" title="Valid CSS">CSS</a></li>
</ul>
</div>
</div>
</body>
</html>
These two files will be included first and last on every page. As you can see they're nothing but pure HTML. No PHP logic needed here.
The Articles View
The articles view will however require some logic. Like I mentioned before we'll still separate the PHP and HTML. If you like you could move all the PHP in the top to its own file in a new directory called controllers/ and include that instead of having it in the same file like me.
<?php
# The controller...
if ($homePage) {
$articles = Articles::getArticles('pub_date', 'DESC', 0, 5);
$title = 'The Latest Articles';
}
else {
$articles = Articles::getArticles('pub_date', 'DESC');
$title = 'All Articles';
}
# The view...
?>
<?php if (count($articles)) { ?>
<h2><?php echo $title; ?></h2>
<ul>
<?php foreach ($articles as $article) { ?>
<li>
<h3>
<a href="article.php?slug=<?php echo $article['slug']; ?>">
<?php echo $article['title']; ?>
</a>
</h3>
<p><small><?php echo $article['pub_date']; ?></small></p>
<p><?php echo substr($article['content'], 0, 200); ?></p>
</li>
<?php } ?>
</ul>
<?php } else { ?>
<h2>No Articles/h2>
<p>Sorry no articles were found.</p>
<?php } ?>
The Article View
<?php
# Make sure ?slug= is set
if (isset($_GET['slug'])) {
$article = Articles::getArticleBySlug($_GET['slug']);
# If it's not a valid slug - die
if (!$article) {
die('FAIL');
}
}
# Else die
else {
die('FAIL');
}
?>
<h2><?php echo $article['title']; ?></h2>
<p><small><?php echo $article['pub_date']; ?></small></p>
<p><?php echo $article['content']; ?></p>
The Articles RSS View
...
The Different Pages
The different pages (or files in root) will simply include the views they need to display the page.
The Home Page
<?php
include 'views/header.php';
$homePage = true;
include 'views/articles.php';
include 'views/footer.php';
?>
The Articles Page
<?php
include 'views/header.php';
include 'views/articles.php';
include 'views/footer.php';
?>
The Article Page
<?php
include 'views/header.php';
include 'views/article.php';
include 'views/footer.php';
?>






Comments
6 comments so far, why don't you post one too?
Wednesday, December 28, 2011 | View all comments by HarrellFrancine29
This is hard a little bit to finish best essay writing just about this topic! Find the superior writing services to have an academic benefit or buy custom essay papers here!
Thursday, December 29, 2011 | View all comments by essay writing service
You interested me in your nice theme. Thus, I will try to notice the experienced essay writing service to buy the essays for sale connected with your issue.
Thursday, December 29, 2011 | View all comments by professional writing service
Are willing your research papers to be referenced by specialists? It's not a problem at all! The research paper services will cope with all you want easily. Thence, why not do it?
Saturday, December 31, 2011 | View all comments by buy custom essay papers
People will buy custom essay papers and the written essay just about this good post. Good text! Thank you for that!
Sunday, January 01, 2012 | View all comments by article submission
That requires a long time to add your good facts like this post hand-operated. Hence, submit article service and journal article submission exist for you and we could use it.
Saturday, January 07, 2012 | View all comments by custom essay
The essay writing about this good topic, students would see at the writing service. Purchase the pre written essay and custom essay just about this good post.