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 name of the class follows the PEAR/Zend convention.

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');
      }

The form uses the 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));
      }

This method is called by a statement like $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>

Just as when we View all blog posts, we display each comment, using the table column name for the Smarty variable, except for the 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();
      }

We use a transaction here for the two deletes. If we did not use a transaction, the deletion of comments could succeed, and the deletion of the post could fail, leading to an unstable system state.

Back to the beginning

pox-php/create_a_comment_for_a_blog_post.txt · Last modified: 2010/05/09 21:05 by gerard
 
 
© 2010 Straylightrun.net under Creative Commons Attribution
Green hosting by Dreamhost.com | Powered by DokuWiki