2010-12-06 11:08:38 +01:00
< ? php
/**
* @ package comments
*/
class CommentingController extends Controller {
2013-04-11 14:23:03 +02:00
private static $allowed_actions = array (
2010-12-11 06:01:19 +01:00
'delete' ,
2012-07-22 03:30:33 +02:00
'spam' ,
'ham' ,
'approve' ,
'rss' ,
2010-12-11 06:01:19 +01:00
'CommentsForm' ,
2013-03-04 11:37:18 +01:00
'doPostComment' ,
'doPreviewComment'
2010-12-11 06:01:19 +01:00
);
2012-07-31 10:45:29 +02:00
2010-12-06 11:08:38 +01:00
private $baseClass = " " ;
private $ownerRecord = " " ;
private $ownerController = " " ;
public function setBaseClass ( $class ) {
$this -> baseClass = $class ;
}
public function getBaseClass () {
return $this -> baseClass ;
}
public function setOwnerRecord ( $record ) {
$this -> ownerRecord = $record ;
}
public function getOwnerRecord () {
return $this -> ownerRecord ;
}
public function setOwnerController ( $controller ) {
$this -> ownerController = $controller ;
}
public function getOwnerController () {
return $this -> ownerController ;
}
/**
* Workaround for generating the link to this controller
2012-07-22 03:30:33 +02:00
*
* @ return string
2010-12-06 11:08:38 +01:00
*/
2012-07-22 03:30:33 +02:00
public function Link ( $action = " " , $id = '' , $other = '' ) {
return Controller :: join_links ( __CLASS__ , $action , $id , $other );
2010-12-06 11:08:38 +01:00
}
/**
2012-07-31 10:45:29 +02:00
* Outputs the RSS feed of comments
*
* @ return XML
*/
public function rss () {
return $this -> getFeed ( $this -> request ) -> outputToBrowser ();
}
/**
* Return an RSSFeed of comments for a given set of comments or all
2012-07-22 03:30:33 +02:00
* comments on the website .
*
* To maintain backwards compatibility with 2.4 this supports mapping
* of PageComment / rss ? pageid = as well as the new RSS format for comments
* of CommentingController / rss / { classname } / { id }
2010-12-11 06:01:19 +01:00
*
2012-07-31 10:45:29 +02:00
* @ param SS_HTTPRequest
*
* @ return RSSFeed
2010-12-11 06:01:19 +01:00
*/
2012-07-31 10:45:29 +02:00
public function getFeed ( SS_HTTPRequest $request ) {
2012-07-22 03:30:33 +02:00
$link = $this -> Link ( 'rss' );
2012-07-31 10:45:29 +02:00
$class = $request -> param ( 'ID' );
$id = $request -> param ( 'OtherID' );
2012-07-22 03:30:33 +02:00
2012-12-16 05:24:58 +01:00
$comments = Comment :: get () -> filter ( array (
'Moderated' => 1 ,
'IsSpam' => 0 ,
));
if ( $request -> getVar ( 'pageid' )) {
$comments = $comments -> filter ( array (
'BaseClass' => 'SiteTree' ,
'ParentID' => $request -> getVar ( 'pageid' ),
2012-07-22 03:30:33 +02:00
));
$link = $this -> Link ( 'rss' , 'SiteTree' , $id );
2012-12-16 05:24:58 +01:00
} elseif ( $class && $id ) {
2012-07-22 03:30:33 +02:00
if ( Commenting :: has_commenting ( $class )) {
2012-12-16 05:24:58 +01:00
$comments = $comments -> filter ( array (
'BaseClass' => $class ,
'ParentID' => $id ,
2012-07-22 03:30:33 +02:00
));
$link = $this -> Link ( 'rss' , Convert :: raw2xml ( $class ), ( int ) $id );
} else {
return $this -> httpError ( 404 );
}
2012-12-16 05:24:58 +01:00
} elseif ( $class ) {
2012-07-22 03:30:33 +02:00
if ( Commenting :: has_commenting ( $class )) {
2012-12-16 05:24:58 +01:00
$comments = $comments -> filter ( 'BaseClass' , $class );
2012-07-22 03:30:33 +02:00
} else {
return $this -> httpError ( 404 );
}
}
$title = _t ( 'CommentingController.RSSTITLE' , " Comments RSS Feed " );
2012-07-31 10:45:29 +02:00
$comments = new PaginatedList ( $comments , $request );
$comments -> setPageLength ( Commenting :: get_config_value ( null , 'comments_per_page' ));
2013-03-05 10:01:42 +01:00
return new RSSFeed (
$comments ,
$link ,
$title ,
$link ,
'Title' , 'EscapedComment' , 'AuthorName'
);
2012-07-22 03:30:33 +02:00
}
/**
* Deletes a given { @ link Comment } via the URL .
*/
2012-07-31 10:45:29 +02:00
public function delete () {
if ( ! $this -> checkSecurityToken ( $this -> request )) {
2012-07-22 03:30:33 +02:00
return $this -> httpError ( 400 );
}
if (( $comment = $this -> getComment ()) && $comment -> canDelete ()) {
$comment -> delete ();
return ( $this -> request -> isAjax ()) ? true : $this -> redirectBack ();
}
return $this -> httpError ( 404 );
}
/**
* Marks a given { @ link Comment } as spam . Removes the comment from display
*/
public function spam () {
2012-07-31 10:45:29 +02:00
if ( ! $this -> checkSecurityToken ( $this -> request )) {
2012-07-22 03:30:33 +02:00
return $this -> httpError ( 400 );
}
$comment = $this -> getComment ();
if (( $comment = $this -> getComment ()) && $comment -> canEdit ()) {
$comment -> IsSpam = true ;
$comment -> Moderated = true ;
$comment -> write ();
2013-02-19 07:46:58 +01:00
return ( $this -> request -> isAjax ()) ? $comment -> renderWith ( 'CommentsInterface_singlecomment' ) : $this -> redirectBack ();
2012-07-22 03:30:33 +02:00
}
return $this -> httpError ( 404 );
}
/**
* Marks a given { @ link Comment } as ham ( not spam ) .
*/
2012-07-31 10:45:29 +02:00
public function ham () {
if ( ! $this -> checkSecurityToken ( $this -> request )) {
2012-07-22 03:30:33 +02:00
return $this -> httpError ( 400 );
}
$comment = $this -> getComment ();
if (( $comment = $this -> getComment ()) && $comment -> canEdit ()) {
$comment -> IsSpam = false ;
$comment -> Moderated = true ;
$comment -> write ();
2013-02-19 07:46:58 +01:00
return ( $this -> request -> isAjax ()) ? $comment -> renderWith ( 'CommentsInterface_singlecomment' ) : $this -> redirectBack ();
2012-07-22 03:30:33 +02:00
}
return $this -> httpError ( 404 );
}
/**
* Marks a given { @ link Comment } as approved .
*/
2012-07-31 10:45:29 +02:00
public function approve () {
if ( ! $this -> checkSecurityToken ( $this -> request )) {
2012-07-22 03:30:33 +02:00
return $this -> httpError ( 400 );
}
$comment = $this -> getComment ();
if (( $comment = $this -> getComment ()) && $comment -> canEdit ()) {
$comment -> IsSpam = false ;
$comment -> Moderated = true ;
$comment -> write ();
2013-02-19 07:46:58 +01:00
return ( $this -> request -> isAjax ()) ? $comment -> renderWith ( 'CommentsInterface_singlecomment' ) : $this -> redirectBack ();
2012-07-22 03:30:33 +02:00
}
return $this -> httpError ( 404 );
}
/**
2012-07-31 10:45:29 +02:00
* Returns the comment referenced in the URL ( by ID ) . Permission checking
* should be done in the callee .
2012-07-22 03:30:33 +02:00
*
* @ return Comment | false
*/
public function getComment () {
2010-12-11 06:01:19 +01:00
$id = isset ( $this -> urlParams [ 'ID' ]) ? $this -> urlParams [ 'ID' ] : false ;
if ( $id ) {
$comment = DataObject :: get_by_id ( 'Comment' , $id );
2012-07-22 03:30:33 +02:00
if ( $comment ) {
return $comment ;
2010-12-11 06:01:19 +01:00
}
}
2012-07-22 03:30:33 +02:00
return false ;
2010-12-11 06:01:19 +01:00
}
2012-07-22 03:30:33 +02:00
/**
* Checks the security token given with the URL to prevent CSRF attacks
* against administrators allowing users to hijack comment moderation .
*
* @ param SS_HTTPRequest
*
* @ return boolean
*/
public function checkSecurityToken ( $req ) {
$token = SecurityToken :: inst ();
return $token -> checkRequest ( $req );
}
2010-12-11 06:01:19 +01:00
/**
* Post a comment form
*
2010-12-06 11:08:38 +01:00
* @ return Form
*/
2012-07-22 03:30:33 +02:00
public function CommentsForm () {
2013-03-04 11:37:18 +01:00
$usePreview = Commenting :: get_config_value ( $this -> getBaseClass (), 'use_preview' );
2010-12-06 11:08:38 +01:00
$member = Member :: currentUser ();
2013-02-20 07:15:28 +01:00
2013-03-05 10:01:42 +01:00
$fields = new FieldList (
$dataFields = new CompositeField (
2013-03-05 15:37:08 +01:00
TextField :: create ( " Name " , _t ( 'CommentInterface.YOURNAME' , 'Your name' ))
-> setCustomValidationMessage ( _t ( 'CommentInterface.YOURNAME_MESSAGE_REQUIRED' , 'Please enter your name' ))
-> setAttribute ( 'data-message-required' , _t ( 'CommentInterface.YOURNAME_MESSAGE_REQUIRED' , 'Please enter your name' )),
2013-03-05 10:01:42 +01:00
2013-03-05 15:37:08 +01:00
EmailField :: create ( " Email " , _t ( 'CommentingController.EMAILADDRESS' , " Your email address (will not be published) " ))
-> setCustomValidationMessage ( _t ( 'CommentInterface.EMAILADDRESS_MESSAGE_REQUIRED' , 'Please enter your email address' ))
-> setAttribute ( 'data-message-required' , _t ( 'CommentInterface.EMAILADDRESS_MESSAGE_REQUIRED' , 'Please enter your email address' ))
-> setAttribute ( 'data-message-email' , _t ( 'CommentInterface.EMAILADDRESS_MESSAGE_EMAIL' , 'Please enter a valid email address' )),
2013-03-05 10:01:42 +01:00
2013-03-05 15:37:08 +01:00
TextField :: create ( " URL " , _t ( 'CommentingController.WEBSITEURL' , " Your website URL " ))
-> setAttribute ( 'data-message-url' , _t ( 'CommentInterface.COMMENT_MESSAGE_URL' , 'Please enter a valid URL' )),
2013-03-05 10:01:42 +01:00
2013-03-05 15:37:08 +01:00
TextareaField :: create ( " Comment " , _t ( 'CommentingController.COMMENTS' , " Comments " ))
-> setCustomValidationMessage ( _t ( 'CommentInterface.COMMENT_MESSAGE_REQUIRED' , 'Please enter your comment' ))
2013-03-05 10:01:42 +01:00
-> setAttribute ( 'data-message-required' , _t ( 'CommentInterface.COMMENT_MESSAGE_REQUIRED' , 'Please enter your comment' ))
),
2013-02-20 07:15:28 +01:00
HiddenField :: create ( " ParentID " ),
HiddenField :: create ( " ReturnURL " ),
HiddenField :: create ( " BaseClass " )
2010-12-06 11:08:38 +01:00
);
2013-03-04 11:37:18 +01:00
// Preview formatted comment. Makes most sense when shortcodes or
// limited HTML is allowed. Populated by JS/Ajax.
if ( $usePreview ) {
$fields -> insertAfter (
ReadonlyField :: create ( 'PreviewComment' , _t ( 'CommentInterface.PREVIEWLABEL' , 'Preview' ))
-> setAttribute ( 'style' , 'display: none' ), // enable through JS
'Comment'
);
}
2013-03-05 10:01:42 +01:00
$dataFields -> addExtraClass ( 'data-fields' );
2013-03-04 11:37:18 +01:00
2010-12-06 11:08:38 +01:00
// save actions
2012-06-01 08:34:31 +02:00
$actions = new FieldList (
2010-12-06 11:08:38 +01:00
new FormAction ( " doPostComment " , _t ( 'CommentInterface.POST' , 'Post' ))
);
2013-03-04 11:37:18 +01:00
if ( $usePreview ) {
$actions -> push (
FormAction :: create ( 'doPreviewComment' , _t ( 'CommentInterface.PREVIEW' , 'Preview' ))
-> addExtraClass ( 'action-minor' )
-> setAttribute ( 'style' , 'display: none' ) // enable through JS
);
}
2010-12-06 11:08:38 +01:00
// required fields for server side
$required = new RequiredFields ( array (
'Name' ,
'Email' ,
'Comment'
));
// create the comment form
$form = new Form ( $this , 'CommentsForm' , $fields , $actions , $required );
// if the record exists load the extra required data
if ( $record = $this -> getOwnerRecord ()) {
$require_login = Commenting :: get_config_value ( $this -> getBaseClass (), 'require_login' );
$permission = Commenting :: get_config_value ( $this -> getBaseClass (), 'required_permission' );
if (( $require_login || $permission ) && $member ) {
$fields = $form -> Fields ();
$fields -> removeByName ( 'Name' );
$fields -> removeByName ( 'Email' );
$fields -> insertBefore ( new ReadonlyField ( " NameView " , _t ( 'CommentInterface.YOURNAME' , 'Your name' ), $member -> getName ()), 'URL' );
$fields -> push ( new HiddenField ( " Name " , " " , $member -> getName ()));
2012-07-26 09:12:05 +02:00
$fields -> push ( new HiddenField ( " Email " , " " , $member -> Email ));
2010-12-06 11:08:38 +01:00
$form -> setFields ( $fields );
}
// we do not want to read a new URL when the form has already been submitted
// which in here, it hasn't been.
$url = ( isset ( $_SERVER [ 'REQUEST_URI' ])) ? Director :: protocolAndHost () . '' . $_SERVER [ 'REQUEST_URI' ] : false ;
$form -> loadDataFrom ( array (
'ParentID' => $record -> ID ,
'ReturnURL' => $url ,
'BaseClass' => $this -> getBaseClass ()
));
}
// Set it so the user gets redirected back down to the form upon form fail
$form -> setRedirectToFormOnValidationError ( true );
// load any data from the cookies
if ( $data = Cookie :: get ( 'CommentsForm_UserData' )) {
2011-09-15 16:37:10 +02:00
$data = Convert :: json2array ( $data );
2010-12-06 11:08:38 +01:00
$form -> loadDataFrom ( array (
" Name " => isset ( $data [ 'Name' ]) ? $data [ 'Name' ] : '' ,
" URL " => isset ( $data [ 'URL' ]) ? $data [ 'URL' ] : '' ,
" Email " => isset ( $data [ 'Email' ]) ? $data [ 'Email' ] : '' ,
" Comment " => Cookie :: get ( 'CommentsForm_Comment' )
));
}
2012-07-22 03:30:33 +02:00
if ( $member ) {
$form -> loadDataFrom ( $member );
}
2010-12-06 11:08:38 +01:00
// hook to allow further extensions to alter the comments form
$this -> extend ( 'alterCommentForm' , $form );
return $form ;
}
/**
* Process which creates a { @ link Comment } once a user submits a comment from this form .
*
* @ param array $data
* @ param Form $form
*/
2012-07-22 03:30:33 +02:00
public function doPostComment ( $data , $form ) {
2010-12-06 11:08:38 +01:00
$class = ( isset ( $data [ 'BaseClass' ])) ? $data [ 'BaseClass' ] : $this -> getBaseClass ();
2013-03-04 11:37:18 +01:00
$usePreview = Commenting :: get_config_value ( $class , 'use_preview' );
2013-03-05 10:01:42 +01:00
$isPreview = ( $usePreview && isset ( $data [ 'IsPreview' ]) && $data [ 'IsPreview' ]);
2010-12-06 11:08:38 +01:00
// if no class then we cannot work out what controller or model they
// are on so throw an error
if ( ! $class ) user_error ( " No OwnerClass set on CommentingController. " , E_USER_ERROR );
// cache users data
2011-09-15 16:37:10 +02:00
Cookie :: set ( " CommentsForm_UserData " , Convert :: raw2json ( $data ));
2010-12-06 11:08:38 +01:00
Cookie :: set ( " CommentsForm_Comment " , $data [ 'Comment' ]);
// extend hook to allow extensions. Also see onAfterPostComment
$this -> extend ( 'onBeforePostComment' , $form );
// If commenting can only be done by logged in users, make sure the user is logged in
$member = Member :: currentUser ();
if ( Commenting :: can_member_post ( $class ) && $member ) {
$form -> Fields () -> push ( new HiddenField ( " AuthorID " , " Author ID " , $member -> ID ));
}
if ( ! Commenting :: can_member_post ( $class )) {
echo _t ( 'CommentingController.PERMISSIONFAILURE' , " You're not able to post comments to this page. Please ensure you are logged in and have an appropriate permission level. " );
return ;
}
// is moderation turned on
$moderated = Commenting :: get_config_value ( $class , 'require_moderation' );
2012-08-08 02:51:14 +02:00
// we want to show a notification if comments are moderated
if ( $moderated ) {
Session :: set ( 'CommentsModerated' , 1 );
}
2010-12-06 11:08:38 +01:00
$comment = new Comment ();
$form -> saveInto ( $comment );
2013-03-05 10:01:42 +01:00
$comment -> AllowHtml = Commenting :: get_config_value ( $class , 'html_allowed' );
2010-12-06 11:08:38 +01:00
$comment -> Moderated = ( $moderated ) ? false : true ;
2013-03-04 11:37:18 +01:00
// Save into DB, or call pre-save hooks to give accurate preview
if ( $isPreview ) {
2013-03-05 10:01:42 +01:00
$comment -> extend ( 'onBeforeWrite' , $dummy );
2013-03-04 11:37:18 +01:00
} else {
$comment -> write ();
2012-11-27 13:56:21 +01:00
2013-03-05 15:37:08 +01:00
// extend hook to allow extensions. Also see onBeforePostComment
$this -> extend ( 'onAfterPostComment' , $comment );
2013-03-05 10:01:42 +01:00
}
2010-12-06 11:08:38 +01:00
// clear the users comment since it passed validation
Cookie :: set ( 'CommentsForm_Comment' , false );
2012-07-31 10:45:29 +02:00
2010-12-07 01:34:17 +01:00
$holder = Commenting :: get_config_value ( $comment -> BaseClass , 'comments_holder_id' );
2013-03-05 15:37:08 +01:00
$hash = ( $moderated ) ? $holder : $comment -> Permalink ();
2010-12-06 11:08:38 +01:00
$url = ( isset ( $data [ 'ReturnURL' ])) ? $data [ 'ReturnURL' ] : false ;
2010-12-07 01:34:17 +01:00
return ( $url ) ? $this -> redirect ( $url . '#' . $hash ) : $this -> redirectBack ();
2010-12-06 11:08:38 +01:00
}
2013-03-04 11:37:18 +01:00
public function doPreviewComment ( $data , $form ) {
$data [ 'IsPreview' ] = 1 ;
2013-03-05 10:01:42 +01:00
2013-03-04 11:37:18 +01:00
return $this -> doPostComment ( $data , $form );
}
2012-08-08 02:51:14 +02:00
}