Writing a simple blog with Zend Framework and mongoDB

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.

What’s Mongo? If you need a great introduction to Mongo? Grab a copy of the Little MongoDB Book by Karl Seguin.

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 Mongo

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 Mongo 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 Mongo

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.

// 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' =&gt; 'Required',</span>
<div>::CODECOLORER_BLOCK_1::</div>
The <strong>_db</strong> property links the document to the <strong>database</strong> that it will be stored in. The <strong>collection</strong> is the name of the collection of documents that this one will be a member of. The <strong>_requirements</strong> array is the method of enforcing document validation constraints. For our post, we're enforcing that the post has an <strong>author</strong>, <strong>title</strong>, <strong>body</strong>, <strong>created date</strong>, <strong>published date</strong>and <strong>status</strong>. This will help us keep proper document integrity.
<h2>Setting up the Post Module</h2>
Once the document class is setup, then it's time to flesh out the Posts controller.
<h3>Adding Posts</h3>
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 <strong>Post</strong> document, store the information in it and save it. Sounds simple right? It is. Have a look at the code snippet below.
[php]
public function createAction()
{
$blogPost = new Common_Blog_Post();
$blogPost-&gt;author = $this-&gt;_request-&gt;getParam('author');
$blogPost-&gt;title = $this-&gt;_request-&gt;getParam('title');
$blogPost-&gt;body = $this-&gt;_request-&gt;getParam('body');
$blogPost-&gt;createdDate = $this-&gt;_request-&gt;getParam('createDate');
$blogPost-&gt;publishedDate = $this-&gt;_request-&gt;getParam('publishedDate');
$blogPost-&gt;status = $this-&gt;_request-&gt;getParam('status');
$blogPost-&gt;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(<span style="font-family: monospace;">);
// assign the object as a view variable
$this-&gt;view-&gt;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.

Further Reading

If you liked what you read and would like to see more, please retweet it, or give it a like on facebook or even give it some digg love.

till next time,

Matt

Matthew is a freelance technical writer and technical editor and regular contributor to a number of tech publications, including PHP Architect, PHPMaster, CloudSpring and New Relic. When he's not contributing there, he's writing content here on Malt Blue. What can he say, he's an avid technical writer and software developer. Get in touch if you want awesome, up to the minute, technical content for your blog, business or publication.

Get Updates! (It's FREE)

Subscribe to the newsletter and get regular updates, podcasts, screencasts, tips, pointers and more - All you need to go from beginner to advanced knowledge of the Zend Framework.

Get The Book :: Zend Framework 2 - For Beginners

Zend Framework 2 - For Beginners :: The Book If you're new to or migrating to the Zend Framework this book will help you get up and running quickly. Whether you're completely new to Zend Framework, have experience in PHP or other MVC-based frameworks, this book will teach you what you need to know to successfully develop applications with Zend Framework 2. Register your interest TODAY to get your copy of the book when it's released in April

Post comment as twitter logo facebook logo
Sort: Newest | Oldest
AlessioDeZotti 5 pts

Hi there, I'm playin' around with zend framework 1.11 and mongo, but I got stuck on a problem i've posted to stackoverflow too. Unluckily, I've received no answer at all, and I'm asking this to you since this looks the only good ref for making zend and mongo work together, and could be updated with this additional "step".

This is my question in detail: http://stackoverflow.com/questions/9044363/shanty-mongo-and-zend-framework-1-11.

Looks like i need to configure a sort of connection, even if I'm working in localhost with no user / pass.

Could you please help?

Thanks!

Alessio

AndreaDiMario 5 pts

Hi, i'm new of zend and i have some problems. I've put the library on zend directory: library/Shanty/

Then, i've added in application.ini: autoloaderNamespaces[] = "Shanty_"

a class models/User.php with:

class User extends Shanty_Mongo_Document {

protected static $_db='apps';

protected static $_collection='user'; }

and in controllers/UserController.php:

public function viewAction() {

$user = new User(); }

But, i've this error:

class User extends Shanty_Mongo_Document { protected static $_db='apps'; protected static $_collection='user'; }

Fatal error: Class 'User' not found in /var/www/zendtest/application/controllers/UserController.php on line 19

Could you give me some help on it?

Thanks for your time. Best regards.

thedreamersmanifesto 6 pts

AndreaDiMario Hi there and thanks for reading the post. It's only a little thing that you're missing. Instead of calling the class User, call it Application_Model_User. Give that a go and let me know if you're still having troubles.

thedreamersmanifesto 6 pts

AndreaDiMario When you've got it up and running, I'd love to hear what you think of the Shanty Mongo library.

AndreaDiMario 5 pts

thedreamersmanifestoAndreaDiMario Hi, thanks for your reply, i've tried this and other possible solutions without success. It strange because it write me back the class as if i've done an echo and then the error.

maltblue 6 pts moderator

AndreaDiMario Andrea, sorry to take so long to get back to you (@thedreamersmanifesto) is me btw. Can you email me a copy of your code? That way I can have a look over it and try and replicate the issue.

My latest conversation: Cloud Development

class Post extends Shanty_Mongo_Document

$blogPost = new Common_Blog_Post();

Who is Common_Blog_Post ?

Steve,

I'm not sure what you mean by who is? What exactly do you mean?

Matt

maltblue 6 pts moderator

Sorry to not be clearer on this one steve but Common_Blog_Post was a class in my Common_ library.

My latest conversation: Cloud Development

Hi Eric,

I was wondering if there a way to make "protected static $_db = 'forum';" part dynamic.

database name comes dynamically and i want to pass it into model before the connection is made.

thanks for the tutorial,

arian

Hi,
Nice post. Quite unsecure blog btw.

++

Hi Eric,

Yes that's true, it is. It was just aimed at the content aspect without any consideration for other areas. Maybe we should post a follow up to it?

Thanks for replying too,

Matt

Nice tutorial. One question I have is how do i use Zend_Paginator with this?. The array and iterator adapters did not work for me. Is there a better way besides first loping through the cursor to create your own array?

Hi Brown and thanks for your comment. I had the same problem myself, but given the limited time I had when I wrote the post, I decided to go with the simpler option of only looping through the results. I'm planning to look at the library more closely during January to see about getting it to work with iterators. That'd definitely make it simpler for sure.

Trackbacks

  1. [...] try this technique. Already do it better? I’d love to learn more from you.Follow-up ReadingWriting a simple blog with the Zend FrameworkWriting a Secure RESTful service in Zend FrameworkWriting a secure, RESTful service in the Zend [...]

  2. [...] tuned for our next post when we extend on this one to start showing you just that!Follow-Up ReadingWriting a simple blog with Zend Framework and mongoDBContributing to Shanty-MongoIf you liked what you read and would like to see more, please retweet [...]