Tuesday, July 3, 2012

how to send an e-mail when there is a new comment (Comment) to the blog post (Post).

We have a blog application and we need to send an e-mail
when there is a new comment (Comment) to the blog post (Post).
Comment is a standard AR model generated with Gii. Post is the same Gii-generated model
except some customized methods. We will need a custom event NewCommentEvent to store
both Post and Comment models and a handler class Notifier that will do the work.
1. Let's start with protected/components/NewCommentEvent.php:
class NewCommentEvent extends CModelEvent {
public $comment;
public $post;
}
It is pretty simple. We have just added two properties.
2. Now, let's move on to protected/models/Post.php. All standard AR methods are
omitted to emphasize on what was added:
class Post extends CActiveRecord {
// custom method for adding a comment
// to current post
function addComment(Comment $comment){
$comment->post_id = $this->id;
// creating event class instance
$event = new NewCommentEvent($this);
$event->post = $this;
$event->comment = $comment;

// triggering event
$this->onNewComment($event);
return $event->isValid;
}
// defining onNewComment event
public function onNewComment($event) {
// Event is actually triggered here. This way we can use
// onNewComment method instead of raiseEvent.
$this->raiseEvent('onNewComment', $event);
}
}
3. Now, it is time to implement a notifier. Create protected/components/
Notifier.php as follows:
class Notifier {
function comment($event){
$text = "There was new comment from
{$event->comment->author} on post {$event->post->title}";
mail('admin@example.com', 'New comment', $text);
}
}
4. Now, it is time to get these together in protected/controllers/
PostController.php:
class PostController extends CController
{
function actionAddComment()
{
$post = Post::model()->findByPk(10);
$notifier = new Notifier();
// attaching event handler
$post->onNewComment = array($notifier, 'comment');
// in the real application data should come from $_POST
$comment = new Comment();
$comment->author = 'Sam Dark';
$comment->text = 'Yii events are amazing!';
// adding comment
$post->addComment($comment);
}
}
5. After the comment has been added, admin will receive an e-mail about it.
It is not always necessary to attach an event handler. Let's look at how we can handle an
event that is already declared inside an existing component by overriding a base class
method. For example, we have a form model UserForm used to collect some information
about our application user and we need to get the complete name from the first and the
last name entered by the user.
Fortunately, in CModel, which is a base class for all Yii models including form models,
CModel::afterValidate method is defined. This method is being called after a
successful form validation. Let's use it in our protected/models/UserForm.php model:
class UserForm extends CFormModel
{
public $firstName;
public $lastName;
public $fullName;
public function rules()
{
return array(
// First name and last name are required
array('firstName, lastName', 'required'),
);
}
// $event argument here is CEvent instance that
// was created passed when an event method was called.
// This time it was happened inside of
// CModel::afterValidate().
function afterValidate()
{
// If this method was called then
// the model is already filled
// with data and data is valid
// so we can use it safely:
$this->fullName = $this->firstName.' '.$this->lastName;
// It's important to call parent class method
// so all other event handlers are called
return parent::afterValidate();
}
}

We need to call parent method inside of afterValidate because parent implementation
calls onAfterValidate that actually raises events:
protected function afterValidate()
{
$this->onAfterValidate(new CEvent($this));
}

No comments:

Post a Comment