First, create a "Comment" business object class
Here is the code.
application/models/Post/Comment.php
class Post_Comment extends BusinessObject { private $_id; public function __construct($id = null) { $this->_id = $id; } public function load() { $sql = "select * from comments where comment_id = ? limit 1"; $data = Zend_Registry::get('db')->getRows($sql, array($this->_id)); return $data[0]; } public function getTime() { return strtotime($this->_data['create_dt_tm']); } public function save() { $sql = "insert into comments (comment_id, post_id, name, comment, create_dt_tm) values (null, ?, ?, ?, ?)"; $bind = array($this->_data['post_id'], $this->_data['name'], $this->_data['comment'], $this->_data['create_dt_tm']); Zend_Registry::get('db')->query($sql, $bind); } }
The class overrides the class load() method to provide lazy-loading of
database data.
The class provides a time field by implementing the getTime() method.
The class also implements a standard save() method for inserting a new
comment to the database. We won't be implementing editing of comments, although
that could be done easily in the same way editing of posts was done.
Modify the view blog post view to add a comment form.
Here is the new code.
application/views/blog
<html> <body> <h1>{$post->title}</h1> <br/> {$post->body|nl2br} <br/> <br/> Created on: {$post->time|date_format:"%A %b. %e %Y %l:%M %p"} <br/> <br/> <a href="/blog/post/{$post->post_id}">Edit this post .</a> <a href="/blog/delete/{$post->post_id}">Delete this post .</a> <hr/> <h3>Add a comment .</h3> <form action="" method="POST"> Name: <br/> <input type="text" name="name" id="name" value="{$name}" /> <span style="color: #FF0000;">{$nameErr}</span> <br/> Comment: <br/> <textarea name="aComment" id="aComment">{$aComment}</textarea> <span style="color: #FF0000;">{$aCommentErr}</span> <br/> <input type="submit" name="submit" id="submit" value="Submit" /> </form> </body> </html>
The form itself is simple. Note that we have followed naming conventions for the input fields described in how to Create a blog post. Here is a screenshot of the new view blog post page.
Modify the controller "view()" action to handle the comment form submission.
The new code looks like this:
application/controllers/BlogController.php
public function view($id) { if ($_POST) { $validators = array( 'name' => array( 'NotEmpty', 'messages' => 'Name is required' ), 'aComment' => array( 'NotEmpty', 'messages' => 'Comment is required' ) ); $form = new Form($validators, $_POST); if (! $form->isValid()) { $this->view->assign($_POST); $this->view->assign($form->getMessages()); } else { $comment = Zend_Registry::get('factory')->get('Post_Comment'); $comment->post_id = $id; $comment->name = $form->getHTMLEntities('name'); $comment->comment = $form->getHTMLEntities('aComment'); $comment->create_dt_tm = date('Y-m-d H:i:s'); $comment->save(); header("Location: /blog/view/$id"); exit; } } $post = Zend_Registry::get('factory')->get('Post', $id); $this->view->post = $post; $this->view->display('blog/post.tpl'); }
Form class for its validation system in the same way it was
used to Create a blog post.
The form implements form validation, validation failure, and form submission the same way as in Create a blog post.
Click submit on the form. You will see the error messages. Fill in the fields and click submit again. What happened? You won't see your comment because we haven't implemented the display of a post's comments yet!
Create a "getComments()" method for the "Post" business object.
Here is the code.
application/models/Post.php
public function getComments() { $sql = "select comment_id from comments where post_id = ?"; $this->_hint('Post_Comment'); return Zend_Registry::get('db')->getCol($sql, array($this->_id)); }
$post→comments
As with the Posts_All business object that display a list of posts, all that
is required to display a list of comments is an array of ID's (or some suitable
primary key), and the type of items in the array. In this case, we only
return the comment IDs and run the _hint() method.
This is a big concept in the composability of business objects. Post and
Comment are full-fledged business objects in their own rights, but a Post
can have Comments. So a given Post object knows how to retrieve all of its
Comments on its own, using its own ID, by simply representing the relationship
with a SQL query. The comments can create themselves and provide any needed data
at a later time. Thus, all Post code and Comment code are kept in their
respective classes. Only the relationship is coded. There is no need to write a
query that returns all information for all comments in the Post class. In
fact, doing so would be wrong – code to return information about a comment
such as title and comment text, or any code having to do with a comment, should
only occur in one place in the whole system, and it should be in the Comment
class.
Modify the view post template to display comments.
Here is the new code.
application/views/blog
<html> <body> <h1>{$post->title}</h1> <br/> {$post->body|nl2br} <br/> <br/> Created on: {$post->time|date_format:"%A %b. %e %Y %l:%M %p"} <br/> <br/> <a href="/blog/post/{$post->post_id}">Edit this post .</a> <a href="/blog/delete/{$post->post_id}">Delete this post .</a> <hr/> <h3>Comments .</h3> {foreach from=$post->comments item=comment} <div> <u>{$comment->name} at {$comment->time|date_format:"%A %b. %e %Y %l:%M %p"}</u><br/> {$comment->comment} </div> <br/> {/foreach} <hr/> <h3>Add a comment .</h3> <form action="" method="POST"> Name: <br/> <input type="text" name="name" id="name" value="{$name}" /> <span style="color: #FF0000;">{$nameErr}</span> <br/> Comment: <br/> <textarea name="aComment" id="aComment">{$aComment}</textarea> <span style="color: #FF0000;">{$aCommentErr}</span> <br/> <input type="submit" name="submit" id="submit" value="Submit" /> </form> </body> </html>
time field, which is
retrieved using a class “getter” method.
Note that we have not added code to the controller. When Smarty retrieves data
for the $post→comments statement in the foreach loop, the $post object
automatically calls its getComments() method, which returns an array of
Comment objects.
Here is a screenshot of the final version of the view post page.
Modify the "delete()" method for a "Post" object.
To be correct, if we delete a blog post, we want to delete all of that post's
comments, or else we will have garbage comments in the database, just hanging
around. Here is the new delete() method.
application/models/Post.php
public function delete() { $db = Zend_Registry::get('db'); $db->startTransaction(); $sql = "delete from comments where post_id = ?"; $ret = Zend_Registry::get('db')->query($sql, array($this->_id)); if ($ret == true) { $sql = "delete from posts where post_id = ?"; $ret = Zend_Registry::get('db')->query($sql, array($this->_id)); } return ($ret == true) ? $db->commit() : $db->rollback(); }

