Writing a Simple Blog With Zend Framework and MongoDB

I’ve been using mongoDB and Zend Framework to make a simple, replicatable filesystem. As it went well, I thought that I could quickly apply what I’d done to create an ultra-simple blog system. Read on to find out all about it.

This post came about after a recent experience starting to extend a personal website of mine. It’s a simple site that I started writing in the Zend Framework some years ago and which I work on, occasionally.

With it I enjoy that complete creative freedom that often only comes with something that’s all your own. On that site, I’ve wanted to have a blog for quite some time and recently I have started learning about and working with NoSQL databases, including CouchDB and mongoDB.

What’s more, I’ve been building a simple fileserver with mongoDB and Zend Framework as a first test of putting the two together. As that project is going very well, I thought that I should apply what I’d done there to create an ultra-simple blog.

So this post will document some of the process, giving you a simple introduction into combining the two technologies. This is not going to be too detailed, just a warm up, but I’m planning to write a couple of posts building upon this one.

Post Requirements

What you’re going to need to follow along with this post is:

  • Working knowledge of the Zend Framework - version 1.1o or above - with the zf tool available
  • A working development environment with a web server, such as Apache 2
  • An installation of mongoDB
  • An open mind to try new things

Background on MongoDB

But first a quick bit of background on mongoDB. According to the official site, MongoDB is:

MongoDB bridges the gap between key-value stores (which are fast and highly scalable) and traditional RDBMS systems (which provide rich queries and deep functionality). MongoDB (from “humongous”) is a scalable, high-performance, open source, document-oriented database.

It’s written in C++ and sports the following features:

  • Document-oriented storage
  • Full index support
  • Replication and High-Availability
  • Auto-Sharding
  • Querying
  • Fast In-Place updates
  • Map/Reduce and
  • GridFS

All in all, this makes it a good system if you’re looking for an alternative from traditional RDBMS’s.

PHP Libraries

There are a number of high-quality, freely available, PHP libraries, including the PHP extension, Zend_NoSQL_Mongo and Shanty-Mongo. For this post, I’ve settled on Shanty-Mongo as it integrates very quickly with Zend Framework and is pretty feature rich. I’ll not get in to too much detail about it here, as you can find out lots more on the website.

Setting up the Base Project

As the key focus of the project is more about mongoDB rather than Zend Framework, I’ll assume a lot of prior knowledge of how to setup and manage the project component. However to assist getting everything up and running quickly, run the following commands to get the base project directory ready to go.

zf create project mini-blog
zf create config
zf enable layout
zf create module posts
zf create controller Index 1 posts
zf create controller Create 1 posts
zf create controller Delete 1 posts
zf create controller Update 1 posts
zf create controller View 1 posts

Adding MongoDB Support to Your Project

After that grab yourself a copy of Shanty-Mongo from Github. Simply run the following command:

git clone git://github.com/coen-hyde/Shanty-Mongo.git

Then add the library/shanty directory, in the uncompressed file, to the library directory of your project. Then, in your application.ini, add the library to the project’s namespace in the production section with:

autoloaderNamespaces[] = "Shanty_"

When that’s done, you’re ready to start using it. In addition to this, add autoloaderNamespaces[] = "Common_". We will need this for our classes.

Modelling with MongoDB

As we covered earlier, Mongo is a document-oriented storage system. So to use it right, you have to think in terms of documents, not *rows*, *tuples*, *tables* and *schemas* in the like of *MySQL* or *Oracle*. This makes it simpler, I believe, to work with Object-Oriented development languages such as PHP. So I’ve created a document class below that we’ll use for our posts. Have  a look at it below and then we’ll cover how it works.

<?php
// a simple class to model a post
class Post extends Shanty_Mongo_Document
{
    protected static $_db = &'forum';
    protected static $_collection = &'posts';
    protected static $_requirements = array(
    &'<span style="font-family: monospace;">author' => &'Required',</span>

    ` 'title' => 'Required',<br />
    'body' => 'Required',<br />
    'createdDate' => 'Required',<br />
    'publishedDate' => 'Required',<br />
    'status' => array('Validator:InArray' => array('draft', 'published'),<br />
    ));<br />
}

The _db property links the document to the database that it will be stored in. The collection is the name of the collection of documents that this one will be a member of. The _requirements array is the method of enforcing document validation constraints. For our post, we’re enforcing that the post has an author, title, body, created date, published dateand status. This will help us keep proper document integrity.

Setting up the Post Module

Once the document class is setup, then it’s time to flesh out the Posts controller.

Adding Posts

In the add document action after we’ve validated and processed the form, we’ll have available the details for our post. So then we’ll create a new Post document, store the information in it and save it. Sounds simple right? It is. Have a look at the code snippet below.

public function createAction()
{
    $blogPost = new Common_Blog_Post();
    $blogPost->author = $this->_request->getParam(&'author');
    $blogPost->title = $this->_request->getParam(&'title');
    $blogPost->body = $this->_request->getParam(&'body');
    $blogPost->createdDate = $this->_request->getParam(&'createDate');
    $blogPost->publishedDate = $this->_request->getParam(&'publishedDate');
    $blogPost->status = $this->_request->getParam(&'status');
    $blogPost->save();
}

Now this assumes that you’ve already setup the code to *build*, *populate* and *process* a form, which I’ll assume is based on Zend_Form along with Zend_Config components. I’m glossing over this for this post given that we’re not specifically focusing in that area of the framework. So please bear with me in that respect for now.

Updating Posts

Ok, so it’s great that we’ve saved a post, but what about updating one. Not that hard honestly. It’s not that much different from adding them. Firstly, you need to instantiate a post if you can find it in the database, which we’ll do based on it’s title, in the database. Then, once you have the document, update the properties of it as required, then save it. That’s it. So let’s have a look at some sample code.

public function updatePost() {
    // attempt to open a post if we can find it
    $blogPost = Common_Blog_Post::fetchOne(
    array(&'title' => $this->_request->getParam(&'title'))
    );
    // we found the post, so let's update the properties
    $blogPost->author = $this->_request->getParam(&'author');
    $blogPost->title = $this->_request->getParam(&'title');
    $blogPost->body = $this->_request->getParam(&'body');
    $blogPost->createdDate = $this->_request->getParam(&'createDate');
    $blogPost->publishedDate = $this->_request->getParam(&'publishedDate');
    $blogPost->status = $this->_request->getParam(&'status);
    $blogPost->save();
}

The fetchOne method, which is inherited from the base Shanty_Mongo_Document class, will return a document if it finds one. This really helps us keep this simple. There are a variety of other methods, but we’ll leave that for later posts.

Deleting Posts

Ok, so we’ve covered creating and updating posts. What about removing posts. As with the updatePost action, the deletePost action will use the findOne method to attempt to find and load an existing post, based on the post title.

If we do find it, then we run the delete method on it. It should be noted that when we take a document out of one database, any connected databases will remove the document when the next replication process occurs. We don’t need to write any extra code to make this happen. What a relief. So what’s the code?

public function deletePost() {
    // attempt to open a post if we can find it
    $blogPost = Common_Blog_Post::fetchOne(
    array(&'title' => $this->_request->getParam(&'title')));
    // we found the post, so let's delete it
    $blogPost->delete();
}

Viewing Posts

Well, not much left to go now. So let’s look at the list item - viewing a list of posts. For this, we’re going to use the &‘all&’ method. This will return a Shanty_Mongo_Iterator_Cursor object that allows us to iterate over a collection of our posts. Nice and simple. What we’ll do in our viewPosts controller is to assign the object as a view variable and then iterate over it in our view template. Have a look at the code below for a sample.

public function viewAction() {
    // attempt to open a post if we can find it
    $blogPosts = Common_Blog_Post::all();

    // assign the object as a view variable
    $this->view->posts = $blogPosts;
}

Now in the view template:

<?php foreach ($posts as $post) : ?>
<a href='/posts/<?php print $post->title; ?>'><?php print $post->title; ?></a>
<p><?php print $post->body; ?></p>
<!- print the rest of the post information ->
<?php endforeach; ?>

It really is that simple.

Winding Up

Now this article should have given you a introductory idea of just how easy it is to integrate MongoDb and the Zend Framework, specifically with the Shanty-Mongo library. I appreciate that there are a lot of things that I’ve not covered here, like the forms, proper security and more thorough validation. I’ve also not gone in to a lot of detail about the wide variety of features that are available with MongoDB, such as storing documents and exactly how replication works. But I hope that I’ve whet your appetite for learning more.

Stay tuned. In the next post, I’m going to get in to a bit more detail about storing files and some of the deeper mechanics of MongoDB and the Shanty-Mongo library. After that we’ll get in to some of the fun of GridFS.


You might also be interested in...


comments powered by Disqus

Books

Buy Mezzio Essentials. Learn the fundamentals that you need, to begin building applications with the Mezzio framework today! Buy Now

Latest YouTube Video

Learn how to write SQL queries in PhpStorm