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 you’re going to need to follow along with this post is:
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:
All in all, this makes it a good system if you’re looking for an alternative from traditional RDBMS’s.
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.
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
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.
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' => '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->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.
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();
}
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();
}
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->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.
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.
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
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
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
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.
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.
AndreaDiMario When you've got it up and running, I'd love to hear what you think of the Shanty Mongo library.
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.
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 ?
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 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.
Why Kohana is an Excellent Alternative to Zend Framework
20 Jul 2012

Writing a simple blog with Zend Framework and mongoDB
07 Nov 2010

Zend Framework 2 – Hydrators, Models and the TableGateway Pattern
15 May 2013

Zend Framework 2 Event Manager – A Gentle Introduction
15 Jan 2013
[...] 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 [...]
[...] 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 [...]