From 4b317131288091ce5021adc0643d0af48fe6cc1d Mon Sep 17 00:00:00 2001 From: Damian Mooyman Date: Fri, 19 Feb 2016 13:48:25 +1300 Subject: [PATCH] Reformat as PSR-2 --- code/Commenting.php | 254 +-- code/admin/CommentAdmin.php | 179 ++- code/admin/CommentsGridField.php | 38 +- code/admin/CommentsGridFieldAction.php | 178 ++- code/admin/CommentsGridFieldBulkAction.php | 79 +- code/admin/CommentsGridFieldConfig.php | 80 +- code/controllers/CommentingController.php | 1074 +++++++------ code/extensions/CommentsExtension.php | 1024 ++++++------ code/model/Comment.php | 1663 ++++++++++---------- code/model/CommentList.php | 155 +- tests/CommentAdminTest.php | 23 +- tests/CommentListTest.php | 29 +- tests/CommentTestHelper.php | 9 +- tests/CommentingControllerTest.php | 205 +-- tests/CommentingTest.php | 47 +- tests/CommentsExtensionTest.php | 151 +- tests/CommentsGridFieldActionTest.php | 58 +- tests/CommentsGridFieldBulkActionTest.php | 18 +- tests/CommentsGridFieldConfigTest.php | 11 +- tests/CommentsGridFieldTest.php | 25 +- tests/CommentsTest.php | 1109 +++++++------ 21 files changed, 3368 insertions(+), 3041 deletions(-) diff --git a/code/Commenting.php b/code/Commenting.php index f81dd25..af976b5 100644 --- a/code/Commenting.php +++ b/code/Commenting.php @@ -13,134 +13,150 @@ * * @package comments */ -class Commenting { +class Commenting +{ - /** - * Adds commenting to a {@link DataObject} - * - * @deprecated since version 2.0 - * - * @param string classname to add commenting to - * @param array $settings Settings. See {@link self::$default_config} for - * available settings - * - * @throws InvalidArgumentException - */ - public static function add($class, $settings = false) { - Deprecation::notice('2.0', 'Using Commenting::add is deprecated. Please use the config API instead'); - Config::inst()->update($class, 'extensions', array('CommentsExtension')); + /** + * Adds commenting to a {@link DataObject} + * + * @deprecated since version 2.0 + * + * @param string classname to add commenting to + * @param array $settings Settings. See {@link self::$default_config} for + * available settings + * + * @throws InvalidArgumentException + */ + public static function add($class, $settings = false) + { + Deprecation::notice('2.0', 'Using Commenting::add is deprecated. Please use the config API instead'); + Config::inst()->update($class, 'extensions', array('CommentsExtension')); - // Check if settings must be customised - if($settings === false) return; - if(!is_array($settings)) { - throw new InvalidArgumentException('$settings needs to be an array or null'); - } - Config::inst()->update($class, 'comments', $settings); - } + // Check if settings must be customised + if ($settings === false) { + return; + } + if (!is_array($settings)) { + throw new InvalidArgumentException('$settings needs to be an array or null'); + } + Config::inst()->update($class, 'comments', $settings); + } - /** - * Removes commenting from a {@link DataObject}. Does not remove existing comments - * but does remove the extension. - * - * @deprecated since version 2.0 - * - * @param string $class Class to remove {@link CommentsExtension} from - */ - public static function remove($class) { - Deprecation::notice('2.0', 'Using Commenting::remove is deprecated. Please use the config API instead'); - $class::remove_extension('CommentsExtension'); - } + /** + * Removes commenting from a {@link DataObject}. Does not remove existing comments + * but does remove the extension. + * + * @deprecated since version 2.0 + * + * @param string $class Class to remove {@link CommentsExtension} from + */ + public static function remove($class) + { + Deprecation::notice('2.0', 'Using Commenting::remove is deprecated. Please use the config API instead'); + $class::remove_extension('CommentsExtension'); + } - /** - * Returns whether a given class name has commenting enabled - * - * @deprecated since version 2.0 - * - * @return bool - */ - public static function has_commenting($class) { - Deprecation::notice('2.0', 'Using Commenting::has_commenting is deprecated. Please use the config API instead'); - return $class::has_extension('CommentsExtension'); - } + /** + * Returns whether a given class name has commenting enabled + * + * @deprecated since version 2.0 + * + * @return bool + */ + public static function has_commenting($class) + { + Deprecation::notice('2.0', 'Using Commenting::has_commenting is deprecated. Please use the config API instead'); + return $class::has_extension('CommentsExtension'); + } - /** - * Sets a value for a class of a given config setting. Passing 'all' as the class - * sets it for everything - * - * @deprecated since version 2.0 - * - * @param string $class Class to set the value on. Passing 'all' will set it to all - * active mappings - * @param string $key setting to change - * @param mixed $value value of the setting - */ - public static function set_config_value($class, $key, $value = false) { - Deprecation::notice('2.0', 'Commenting::set_config_value is deprecated. Use the config api instead'); - if($class === "all") $class = 'CommentsExtension'; - Config::inst()->update($class, 'comments', array($key => $value)); - } + /** + * Sets a value for a class of a given config setting. Passing 'all' as the class + * sets it for everything + * + * @deprecated since version 2.0 + * + * @param string $class Class to set the value on. Passing 'all' will set it to all + * active mappings + * @param string $key setting to change + * @param mixed $value value of the setting + */ + public static function set_config_value($class, $key, $value = false) + { + Deprecation::notice('2.0', 'Commenting::set_config_value is deprecated. Use the config api instead'); + if ($class === "all") { + $class = 'CommentsExtension'; + } + Config::inst()->update($class, 'comments', array($key => $value)); + } - /** - * Returns a given config value for a commenting class - * - * @deprecated since version 2.0 - * - * @param string $class - * @param string $key config value to return - * - * @throws Exception - * @return mixed - */ - public static function get_config_value($class, $key) { - Deprecation::notice( - '2.0', - 'Using Commenting::get_config_value is deprecated. Please use $parent->getCommentsOption() or ' - . 'CommentingController::getOption() instead' - ); + /** + * Returns a given config value for a commenting class + * + * @deprecated since version 2.0 + * + * @param string $class + * @param string $key config value to return + * + * @throws Exception + * @return mixed + */ + public static function get_config_value($class, $key) + { + Deprecation::notice( + '2.0', + 'Using Commenting::get_config_value is deprecated. Please use $parent->getCommentsOption() or ' + . 'CommentingController::getOption() instead' + ); - // Get settings - if(!$class) { - $class = 'CommentsExtension'; - } elseif(!$class::has_extension('CommentsExtension')) { - throw new InvalidArgumentException("$class does not have commenting enabled"); - } - return singleton($class)->getCommentsOption($key); - } + // Get settings + if (!$class) { + $class = 'CommentsExtension'; + } elseif (!$class::has_extension('CommentsExtension')) { + throw new InvalidArgumentException("$class does not have commenting enabled"); + } + return singleton($class)->getCommentsOption($key); + } - /** - * Determines whether a config value on the commenting extension - * matches a given value. - * - * @deprecated since version 2.0 - * - * @param string $class - * @param string $key - * @param string $value Expected value - * @return boolean - */ - public static function config_value_equals($class, $key, $value) { - $check = self::get_config_value($class, $key); - if($check && ($check == $value)) return true; - } + /** + * Determines whether a config value on the commenting extension + * matches a given value. + * + * @deprecated since version 2.0 + * + * @param string $class + * @param string $key + * @param string $value Expected value + * @return boolean + */ + public static function config_value_equals($class, $key, $value) + { + $check = self::get_config_value($class, $key); + if ($check && ($check == $value)) { + return true; + } + } - /** - * Return whether a user can post on a given commenting instance - * - * @deprecated since version 2.0 - * - * @param string $class - * @return boolean true - */ - public static function can_member_post($class) { - Deprecation::notice('2.0', 'Use $instance->canPostComment() directly instead'); - $member = Member::currentUser(); + /** + * Return whether a user can post on a given commenting instance + * + * @deprecated since version 2.0 + * + * @param string $class + * @return boolean true + */ + public static function can_member_post($class) + { + Deprecation::notice('2.0', 'Use $instance->canPostComment() directly instead'); + $member = Member::currentUser(); - // Check permission - $permission = self::get_config_value($class, 'required_permission'); - if($permission && !Permission::check($permission)) return false; + // Check permission + $permission = self::get_config_value($class, 'required_permission'); + if ($permission && !Permission::check($permission)) { + return false; + } - // Check login required - $requireLogin = self::get_config_value($class, 'require_login'); - return !$requireLogin || $member; - } + // Check login required + $requireLogin = self::get_config_value($class, 'require_login'); + return !$requireLogin || $member; + } } diff --git a/code/admin/CommentAdmin.php b/code/admin/CommentAdmin.php index a7d1329..f58acd8 100644 --- a/code/admin/CommentAdmin.php +++ b/code/admin/CommentAdmin.php @@ -5,114 +5,119 @@ * * @package comments */ -class CommentAdmin extends LeftAndMain implements PermissionProvider { +class CommentAdmin extends LeftAndMain implements PermissionProvider +{ - private static $url_segment = 'comments'; + private static $url_segment = 'comments'; - private static $url_rule = '/$Action'; + private static $url_rule = '/$Action'; - private static $menu_title = 'Comments'; + private static $menu_title = 'Comments'; - private static $allowed_actions = array( - 'approvedmarked', - 'deleteall', - 'deletemarked', - 'hammarked', - 'showtable', - 'spammarked', - 'EditForm', - 'unmoderated' - ); + private static $allowed_actions = array( + 'approvedmarked', + 'deleteall', + 'deletemarked', + 'hammarked', + 'showtable', + 'spammarked', + 'EditForm', + 'unmoderated' + ); - public function providePermissions() { - return array( - "CMS_ACCESS_CommentAdmin" => array( - 'name' => _t('CommentAdmin.ADMIN_PERMISSION', "Access to 'Comments' section"), - 'category' => _t('Permission.CMS_ACCESS_CATEGORY', 'CMS Access') - ) - ); - } + public function providePermissions() + { + return array( + "CMS_ACCESS_CommentAdmin" => array( + 'name' => _t('CommentAdmin.ADMIN_PERMISSION', "Access to 'Comments' section"), + 'category' => _t('Permission.CMS_ACCESS_CATEGORY', 'CMS Access') + ) + ); + } - /** - * @return Form - */ - public function getEditForm($id = null, $fields = null) { - if(!$id) $id = $this->currentPageID(); + /** + * @return Form + */ + public function getEditForm($id = null, $fields = null) + { + if (!$id) { + $id = $this->currentPageID(); + } - $form = parent::getEditForm($id); - $record = $this->getRecord($id); + $form = parent::getEditForm($id); + $record = $this->getRecord($id); - if($record && !$record->canView()) { - return Security::permissionFailure($this); - } + if ($record && !$record->canView()) { + return Security::permissionFailure($this); + } - $newComments = Comment::get()->filter('Moderated', 0); + $newComments = Comment::get()->filter('Moderated', 0); - $newGrid = new CommentsGridField( - 'NewComments', - _t('CommentsAdmin.NewComments', 'New'), - $newComments, - CommentsGridFieldConfig::create() - ); + $newGrid = new CommentsGridField( + 'NewComments', + _t('CommentsAdmin.NewComments', 'New'), + $newComments, + CommentsGridFieldConfig::create() + ); - $approvedComments = Comment::get()->filter('Moderated', 1)->filter('IsSpam', 0); + $approvedComments = Comment::get()->filter('Moderated', 1)->filter('IsSpam', 0); - $approvedGrid = new CommentsGridField( - 'ApprovedComments', - _t('CommentsAdmin.ApprovedComments', 'Approved'), - $approvedComments, - CommentsGridFieldConfig::create() - ); + $approvedGrid = new CommentsGridField( + 'ApprovedComments', + _t('CommentsAdmin.ApprovedComments', 'Approved'), + $approvedComments, + CommentsGridFieldConfig::create() + ); - $spamComments = Comment::get()->filter('Moderated', 1)->filter('IsSpam', 1); + $spamComments = Comment::get()->filter('Moderated', 1)->filter('IsSpam', 1); - $spamGrid = new CommentsGridField( - 'SpamComments', - _t('CommentsAdmin.SpamComments', 'Spam'), - $spamComments, - CommentsGridFieldConfig::create() - ); + $spamGrid = new CommentsGridField( + 'SpamComments', + _t('CommentsAdmin.SpamComments', 'Spam'), + $spamComments, + CommentsGridFieldConfig::create() + ); - $newCount = '(' . count($newComments) . ')'; - $approvedCount = '(' . count($approvedComments) . ')'; - $spamCount = '(' . count($spamComments) . ')'; + $newCount = '(' . count($newComments) . ')'; + $approvedCount = '(' . count($approvedComments) . ')'; + $spamCount = '(' . count($spamComments) . ')'; - $fields = new FieldList( - $root = new TabSet( - 'Root', - new Tab('NewComments', _t('CommentAdmin.NewComments', 'New') . ' ' . $newCount, - $newGrid - ), - new Tab('ApprovedComments', _t('CommentAdmin.ApprovedComments', 'Approved') . ' ' . $approvedCount, - $approvedGrid - ), - new Tab('SpamComments', _t('CommentAdmin.SpamComments', 'Spam') . ' ' . $spamCount, - $spamGrid - ) - ) - ); + $fields = new FieldList( + $root = new TabSet( + 'Root', + new Tab('NewComments', _t('CommentAdmin.NewComments', 'New') . ' ' . $newCount, + $newGrid + ), + new Tab('ApprovedComments', _t('CommentAdmin.ApprovedComments', 'Approved') . ' ' . $approvedCount, + $approvedGrid + ), + new Tab('SpamComments', _t('CommentAdmin.SpamComments', 'Spam') . ' ' . $spamCount, + $spamGrid + ) + ) + ); - $root->setTemplate('CMSTabSet'); + $root->setTemplate('CMSTabSet'); - $actions = new FieldList(); + $actions = new FieldList(); - $form = new Form( - $this, - 'EditForm', - $fields, - $actions - ); + $form = new Form( + $this, + 'EditForm', + $fields, + $actions + ); - $form->addExtraClass('cms-edit-form'); - $form->setTemplate($this->getTemplatesWithSuffix('_EditForm')); + $form->addExtraClass('cms-edit-form'); + $form->setTemplate($this->getTemplatesWithSuffix('_EditForm')); - if($form->Fields()->hasTabset()) { - $form->Fields()->findOrMakeTab('Root')->setTemplate('CMSTabSet'); - $form->addExtraClass('center ss-tabset cms-tabset ' . $this->BaseCSSClasses()); - } + if ($form->Fields()->hasTabset()) { + $form->Fields()->findOrMakeTab('Root')->setTemplate('CMSTabSet'); + $form->addExtraClass('center ss-tabset cms-tabset ' . $this->BaseCSSClasses()); + } - $this->extend('updateEditForm', $form); + $this->extend('updateEditForm', $form); - return $form; - } + return $form; + } } diff --git a/code/admin/CommentsGridField.php b/code/admin/CommentsGridField.php index b434820..f94a958 100644 --- a/code/admin/CommentsGridField.php +++ b/code/admin/CommentsGridField.php @@ -1,22 +1,24 @@ IsSpam) { - $attributes['class'] .= ' spam'; - } + if ($record->IsSpam) { + $attributes['class'] .= ' spam'; + } - return FormField::create_tag( - 'tr', - $attributes, - $content - ); - } -} \ No newline at end of file + return FormField::create_tag( + 'tr', + $attributes, + $content + ); + } +} diff --git a/code/admin/CommentsGridFieldAction.php b/code/admin/CommentsGridFieldAction.php index 80869a8..8c9df65 100644 --- a/code/admin/CommentsGridFieldAction.php +++ b/code/admin/CommentsGridFieldAction.php @@ -1,100 +1,110 @@ 'col-buttons'); - } + /** + * {@inheritdoc} + */ + public function getColumnAttributes($gridField, $record, $columnName) + { + return array('class' => 'col-buttons'); + } - /** - * {@inheritdoc} - */ - public function getColumnMetadata($gridField, $columnName) { - if($columnName == 'Actions') { - return array('title' => ''); - } - } + /** + * {@inheritdoc} + */ + public function getColumnMetadata($gridField, $columnName) + { + if ($columnName == 'Actions') { + return array('title' => ''); + } + } - /** - * {@inheritdoc} - */ - public function getColumnsHandled($gridField) { - return array('Actions'); - } + /** + * {@inheritdoc} + */ + public function getColumnsHandled($gridField) + { + return array('Actions'); + } - /** - * {@inheritdoc} - */ - public function getColumnContent($gridField, $record, $columnName) { - if(!$record->canEdit()) return; + /** + * {@inheritdoc} + */ + public function getColumnContent($gridField, $record, $columnName) + { + if (!$record->canEdit()) { + return; + } - $field = ""; + $field = ""; - if(!$record->IsSpam || !$record->Moderated) { - $field .= GridField_FormAction::create( - $gridField, - 'CustomAction' . $record->ID . 'Spam', - 'Spam', - 'spam', - array('RecordID' => $record->ID) - )->Field(); - } + if (!$record->IsSpam || !$record->Moderated) { + $field .= GridField_FormAction::create( + $gridField, + 'CustomAction' . $record->ID . 'Spam', + 'Spam', + 'spam', + array('RecordID' => $record->ID) + )->Field(); + } - if($record->IsSpam || !$record->Moderated) { - $field .= GridField_FormAction::create( - $gridField, - 'CustomAction' . $record->ID . 'Approve', - 'Approve', - 'approve', - array('RecordID' => $record->ID) - )->Field(); - } + if ($record->IsSpam || !$record->Moderated) { + $field .= GridField_FormAction::create( + $gridField, + 'CustomAction' . $record->ID . 'Approve', + 'Approve', + 'approve', + array('RecordID' => $record->ID) + )->Field(); + } - return $field; - } + return $field; + } - /** - * {@inheritdoc} - */ - public function getActions($gridField) { - return array('spam', 'approve'); - } + /** + * {@inheritdoc} + */ + public function getActions($gridField) + { + return array('spam', 'approve'); + } - /** - * {@inheritdoc} - */ - public function handleAction(GridField $gridField, $actionName, $arguments, $data) { - if($actionName == 'spam') { - $comment = Comment::get()->byID($arguments["RecordID"]); - $comment->markSpam(); + /** + * {@inheritdoc} + */ + public function handleAction(GridField $gridField, $actionName, $arguments, $data) + { + if ($actionName == 'spam') { + $comment = Comment::get()->byID($arguments["RecordID"]); + $comment->markSpam(); - // output a success message to the user - Controller::curr()->getResponse()->setStatusCode( - 200, - 'Comment marked as spam.' - ); - } + // output a success message to the user + Controller::curr()->getResponse()->setStatusCode( + 200, + 'Comment marked as spam.' + ); + } - if($actionName == 'approve') { - $comment = Comment::get()->byID($arguments["RecordID"]); - $comment->markApproved(); + if ($actionName == 'approve') { + $comment = Comment::get()->byID($arguments["RecordID"]); + $comment->markApproved(); - // output a success message to the user - Controller::curr()->getResponse()->setStatusCode( - 200, - 'Comment approved.' - ); - } - } + // output a success message to the user + Controller::curr()->getResponse()->setStatusCode( + 200, + 'Comment approved.' + ); + } + } } diff --git a/code/admin/CommentsGridFieldBulkAction.php b/code/admin/CommentsGridFieldBulkAction.php index 138ff70..457f698 100644 --- a/code/admin/CommentsGridFieldBulkAction.php +++ b/code/admin/CommentsGridFieldBulkAction.php @@ -3,8 +3,8 @@ /** * @package comments */ -class CommentsGridFieldBulkAction extends GridFieldBulkActionHandler { - +class CommentsGridFieldBulkAction extends GridFieldBulkActionHandler +{ } /** @@ -12,53 +12,56 @@ class CommentsGridFieldBulkAction extends GridFieldBulkActionHandler { * * @package comments */ -class CommentsGridFieldBulkAction_Handlers extends CommentsGridFieldBulkAction { +class CommentsGridFieldBulkAction_Handlers extends CommentsGridFieldBulkAction +{ - private static $allowed_actions = array( - 'spam', - 'approve', - ); + private static $allowed_actions = array( + 'spam', + 'approve', + ); - private static $url_handlers = array( - 'spam' => 'spam', - 'approve' => 'approve', - ); + private static $url_handlers = array( + 'spam' => 'spam', + 'approve' => 'approve', + ); - public function spam(SS_HTTPRequest $request) { - $ids = array(); + public function spam(SS_HTTPRequest $request) + { + $ids = array(); - foreach($this->getRecords() as $record) { - array_push($ids, $record->ID); - $record->markSpam(); - } + foreach ($this->getRecords() as $record) { + array_push($ids, $record->ID); + $record->markSpam(); + } - $response = new SS_HTTPResponse(Convert::raw2json(array( - 'done' => true, - 'records' => $ids - ))); + $response = new SS_HTTPResponse(Convert::raw2json(array( + 'done' => true, + 'records' => $ids + ))); - $response->addHeader('Content-Type', 'text/json'); + $response->addHeader('Content-Type', 'text/json'); - return $response; - } + return $response; + } - public function approve(SS_HTTPRequest $request) { - $ids = array(); + public function approve(SS_HTTPRequest $request) + { + $ids = array(); - foreach($this->getRecords() as $record) { - array_push($ids, $record->ID); - $record->markApproved(); - } + foreach ($this->getRecords() as $record) { + array_push($ids, $record->ID); + $record->markApproved(); + } - $response = new SS_HTTPResponse(Convert::raw2json(array( - 'done' => true, - 'records' => $ids - ))); + $response = new SS_HTTPResponse(Convert::raw2json(array( + 'done' => true, + 'records' => $ids + ))); - $response->addHeader('Content-Type', 'text/json'); + $response->addHeader('Content-Type', 'text/json'); - return $response; - } -} \ No newline at end of file + return $response; + } +} diff --git a/code/admin/CommentsGridFieldConfig.php b/code/admin/CommentsGridFieldConfig.php index bc01dd4..2748b5c 100644 --- a/code/admin/CommentsGridFieldConfig.php +++ b/code/admin/CommentsGridFieldConfig.php @@ -1,49 +1,51 @@ addComponent(new GridFieldExportButton()); + // $this->addComponent(new GridFieldExportButton()); - $this->addComponent(new CommentsGridFieldAction()); + $this->addComponent(new CommentsGridFieldAction()); - // Format column - $columns = $this->getComponentByType('GridFieldDataColumns'); - $columns->setFieldFormatting(array( - 'ParentTitle' => function($value, &$item) { - return sprintf( - '%s', - Convert::raw2att($item->Link()), - $item->obj('ParentTitle')->forTemplate() - ); - } - )); + // Format column + $columns = $this->getComponentByType('GridFieldDataColumns'); + $columns->setFieldFormatting(array( + 'ParentTitle' => function ($value, &$item) { + return sprintf( + '%s', + Convert::raw2att($item->Link()), + $item->obj('ParentTitle')->forTemplate() + ); + } + )); - // Add bulk option - $manager = new GridFieldBulkManager(); + // Add bulk option + $manager = new GridFieldBulkManager(); - $manager->addBulkAction( - 'spam', 'Spam', 'CommentsGridFieldBulkAction_Handlers', - array( - 'isAjax' => true, - 'icon' => 'cross', - 'isDestructive' => false - ) - ); + $manager->addBulkAction( + 'spam', 'Spam', 'CommentsGridFieldBulkAction_Handlers', + array( + 'isAjax' => true, + 'icon' => 'cross', + 'isDestructive' => false + ) + ); - $manager->addBulkAction( - 'approve', 'Approve', 'CommentsGridFieldBulkAction_Handlers', - array( - 'isAjax' => true, - 'icon' => 'cross', - 'isDestructive' => false - ) - ); + $manager->addBulkAction( + 'approve', 'Approve', 'CommentsGridFieldBulkAction_Handlers', + array( + 'isAjax' => true, + 'icon' => 'cross', + 'isDestructive' => false + ) + ); - $manager->removeBulkAction('bulkEdit'); - $manager->removeBulkAction('unLink'); + $manager->removeBulkAction('bulkEdit'); + $manager->removeBulkAction('unLink'); - $this->addComponent($manager); - } -} \ No newline at end of file + $this->addComponent($manager); + } +} diff --git a/code/controllers/CommentingController.php b/code/controllers/CommentingController.php index f333579..5277bd1 100644 --- a/code/controllers/CommentingController.php +++ b/code/controllers/CommentingController.php @@ -4,284 +4,316 @@ * @package comments */ -class CommentingController extends Controller { +class CommentingController extends Controller +{ - private static $allowed_actions = array( - 'delete', - 'spam', - 'ham', - 'approve', - 'rss', - 'CommentsForm', - 'reply', - 'doPostComment', - 'doPreviewComment' - ); + private static $allowed_actions = array( + 'delete', + 'spam', + 'ham', + 'approve', + 'rss', + 'CommentsForm', + 'reply', + 'doPostComment', + 'doPreviewComment' + ); - private static $url_handlers = array( - 'reply/$ParentCommentID//$ID/$OtherID' => 'reply', - ); + private static $url_handlers = array( + 'reply/$ParentCommentID//$ID/$OtherID' => 'reply', + ); - /** - * Fields required for this form - * - * @var array - * @config - */ - private static $required_fields = array( - 'Name', - 'Email', - 'Comment' - ); + /** + * Fields required for this form + * + * @var array + * @config + */ + private static $required_fields = array( + 'Name', + 'Email', + 'Comment' + ); - /** - * Base class this commenting form is for - * - * @var string - */ - private $baseClass = ""; + /** + * Base class this commenting form is for + * + * @var string + */ + private $baseClass = ""; - /** - * The record this commenting form is for - * - * @var DataObject - */ - private $ownerRecord = null; + /** + * The record this commenting form is for + * + * @var DataObject + */ + private $ownerRecord = null; - /** - * Parent controller record - * - * @var Controller - */ - private $ownerController = null; + /** + * Parent controller record + * + * @var Controller + */ + private $ownerController = null; - /** - * Backup url to return to - * - * @var string - */ - protected $fallbackReturnURL = null; + /** + * Backup url to return to + * + * @var string + */ + protected $fallbackReturnURL = null; - /** - * Set the base class to use - * - * @param string $class - */ - public function setBaseClass($class) { - $this->baseClass = $class; - } + /** + * Set the base class to use + * + * @param string $class + */ + public function setBaseClass($class) + { + $this->baseClass = $class; + } - /** - * Get the base class used - * - * @return string - */ - public function getBaseClass() { - return $this->baseClass; - } + /** + * Get the base class used + * + * @return string + */ + public function getBaseClass() + { + return $this->baseClass; + } - /** - * Set the record this controller is working on - * - * @param DataObject $record - */ - public function setOwnerRecord($record) { - $this->ownerRecord = $record; - } + /** + * Set the record this controller is working on + * + * @param DataObject $record + */ + public function setOwnerRecord($record) + { + $this->ownerRecord = $record; + } - /** - * Get the record - * - * @return DataObject - */ - public function getOwnerRecord() { - return $this->ownerRecord; - } + /** + * Get the record + * + * @return DataObject + */ + public function getOwnerRecord() + { + return $this->ownerRecord; + } - /** - * Set the parent controller - * - * @param Controller $controller - */ - public function setOwnerController($controller) { - $this->ownerController = $controller; - } + /** + * Set the parent controller + * + * @param Controller $controller + */ + public function setOwnerController($controller) + { + $this->ownerController = $controller; + } - /** - * Get the parent controller - * - * @return Controller - */ - public function getOwnerController() { - return $this->ownerController; - } + /** + * Get the parent controller + * + * @return Controller + */ + public function getOwnerController() + { + return $this->ownerController; + } - /** - * Get the commenting option for the current state - * - * @param string $key - * @return mixed Result if the setting is available, or null otherwise - */ - public function getOption($key) { - // If possible use the current record - if($record = $this->getOwnerRecord()) { - return $record->getCommentsOption($key); - } + /** + * Get the commenting option for the current state + * + * @param string $key + * @return mixed Result if the setting is available, or null otherwise + */ + public function getOption($key) + { + // If possible use the current record + if ($record = $this->getOwnerRecord()) { + return $record->getCommentsOption($key); + } - // Otherwise a singleton of that record - if($class = $this->getBaseClass()) { - return singleton($class)->getCommentsOption($key); - } + // Otherwise a singleton of that record + if ($class = $this->getBaseClass()) { + return singleton($class)->getCommentsOption($key); + } - // Otherwise just use the default options - return singleton('CommentsExtension')->getCommentsOption($key); - } + // Otherwise just use the default options + return singleton('CommentsExtension')->getCommentsOption($key); + } - /** - * Workaround for generating the link to this controller - * - * @return string - */ - public function Link($action = '', $id = '', $other = '') { - return Controller::join_links(Director::baseURL(), __CLASS__ , $action, $id, $other); - } + /** + * Workaround for generating the link to this controller + * + * @return string + */ + public function Link($action = '', $id = '', $other = '') + { + return Controller::join_links(Director::baseURL(), __CLASS__, $action, $id, $other); + } - /** - * Outputs the RSS feed of comments - * - * @return HTMLText - */ - public function rss() { - return $this->getFeed($this->request)->outputToBrowser(); - } + /** + * Outputs the RSS feed of comments + * + * @return HTMLText + */ + public function rss() + { + return $this->getFeed($this->request)->outputToBrowser(); + } - /** - * Return an RSSFeed of comments for a given set of comments or all - * 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} - * - * @param SS_HTTPRequest - * - * @return RSSFeed - */ - public function getFeed(SS_HTTPRequest $request) { - $link = $this->Link('rss'); - $class = $request->param('ID'); - $id = $request->param('OtherID'); + /** + * Return an RSSFeed of comments for a given set of comments or all + * 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} + * + * @param SS_HTTPRequest + * + * @return RSSFeed + */ + public function getFeed(SS_HTTPRequest $request) + { + $link = $this->Link('rss'); + $class = $request->param('ID'); + $id = $request->param('OtherID'); - // Support old pageid param - if(!$id && !$class && ($id = $request->getVar('pageid'))) { - $class = 'SiteTree'; - } + // Support old pageid param + if (!$id && !$class && ($id = $request->getVar('pageid'))) { + $class = 'SiteTree'; + } - $comments = Comment::get()->filter(array( - 'Moderated' => 1, - 'IsSpam' => 0, - )); + $comments = Comment::get()->filter(array( + 'Moderated' => 1, + 'IsSpam' => 0, + )); - // Check if class filter - if($class) { - if(!is_subclass_of($class, 'DataObject') || !$class::has_extension('CommentsExtension')) { - return $this->httpError(404); - } - $this->setBaseClass($class); - $comments = $comments->filter('BaseClass', $class); - $link = Controller::join_links($link, $class); + // Check if class filter + if ($class) { + if (!is_subclass_of($class, 'DataObject') || !$class::has_extension('CommentsExtension')) { + return $this->httpError(404); + } + $this->setBaseClass($class); + $comments = $comments->filter('BaseClass', $class); + $link = Controller::join_links($link, $class); - // Check if id filter - if($id) { - $comments = $comments->filter('ParentID', $id); - $link = Controller::join_links($link, $id); - $this->setOwnerRecord(DataObject::get_by_id($class, $id)); - } - } + // Check if id filter + if ($id) { + $comments = $comments->filter('ParentID', $id); + $link = Controller::join_links($link, $id); + $this->setOwnerRecord(DataObject::get_by_id($class, $id)); + } + } - $title = _t('CommentingController.RSSTITLE', "Comments RSS Feed"); + $title = _t('CommentingController.RSSTITLE', "Comments RSS Feed"); - $comments = new PaginatedList($comments, $request); - $comments->setPageLength($this->getOption('comments_per_page')); + $comments = new PaginatedList($comments, $request); + $comments->setPageLength($this->getOption('comments_per_page')); - return new RSSFeed( - $comments, - $link, - $title, - $link, - 'Title', 'EscapedComment', 'AuthorName' - ); - } + return new RSSFeed( + $comments, + $link, + $title, + $link, + 'Title', 'EscapedComment', 'AuthorName' + ); + } - /** - * Deletes a given {@link Comment} via the URL. - */ - public function delete() { - $comment = $this->getComment(); - if(!$comment) return $this->httpError(404); - if(!$comment->canDelete()) { - return Security::permissionFailure($this, 'You do not have permission to delete this comment'); - } - if(!$comment->getSecurityToken()->checkRequest($this->request)) return $this->httpError(400); + /** + * Deletes a given {@link Comment} via the URL. + */ + public function delete() + { + $comment = $this->getComment(); + if (!$comment) { + return $this->httpError(404); + } + if (!$comment->canDelete()) { + return Security::permissionFailure($this, 'You do not have permission to delete this comment'); + } + if (!$comment->getSecurityToken()->checkRequest($this->request)) { + return $this->httpError(400); + } - $comment->delete(); + $comment->delete(); - return $this->request->isAjax() - ? true - : $this->redirectBack(); - } + return $this->request->isAjax() + ? true + : $this->redirectBack(); + } - /** - * Marks a given {@link Comment} as spam. Removes the comment from display - */ - public function spam() { - $comment = $this->getComment(); - if(!$comment) return $this->httpError(404); - if(!$comment->canEdit()) { - return Security::permissionFailure($this, 'You do not have permission to edit this comment'); - } - if(!$comment->getSecurityToken()->checkRequest($this->request)) return $this->httpError(400); + /** + * Marks a given {@link Comment} as spam. Removes the comment from display + */ + public function spam() + { + $comment = $this->getComment(); + if (!$comment) { + return $this->httpError(404); + } + if (!$comment->canEdit()) { + return Security::permissionFailure($this, 'You do not have permission to edit this comment'); + } + if (!$comment->getSecurityToken()->checkRequest($this->request)) { + return $this->httpError(400); + } - $comment->markSpam(); + $comment->markSpam(); return $this->renderChangedCommentState($comment); - } + } - /** - * Marks a given {@link Comment} as ham (not spam). - */ - public function ham() { - $comment = $this->getComment(); - if(!$comment) return $this->httpError(404); - if(!$comment->canEdit()) { - return Security::permissionFailure($this, 'You do not have permission to edit this comment'); - } - if(!$comment->getSecurityToken()->checkRequest($this->request)) return $this->httpError(400); + /** + * Marks a given {@link Comment} as ham (not spam). + */ + public function ham() + { + $comment = $this->getComment(); + if (!$comment) { + return $this->httpError(404); + } + if (!$comment->canEdit()) { + return Security::permissionFailure($this, 'You do not have permission to edit this comment'); + } + if (!$comment->getSecurityToken()->checkRequest($this->request)) { + return $this->httpError(400); + } - $comment->markApproved(); + $comment->markApproved(); return $this->renderChangedCommentState($comment); - } + } - /** - * Marks a given {@link Comment} as approved. - */ - public function approve() { - $comment = $this->getComment(); - if(!$comment) return $this->httpError(404); - if(!$comment->canEdit()) { - return Security::permissionFailure($this, 'You do not have permission to approve this comment'); - } - if(!$comment->getSecurityToken()->checkRequest($this->request)) return $this->httpError(400); + /** + * Marks a given {@link Comment} as approved. + */ + public function approve() + { + $comment = $this->getComment(); + if (!$comment) { + return $this->httpError(404); + } + if (!$comment->canEdit()) { + return Security::permissionFailure($this, 'You do not have permission to approve this comment'); + } + if (!$comment->getSecurityToken()->checkRequest($this->request)) { + return $this->httpError(400); + } - $comment->markApproved(); + $comment->markApproved(); return $this->renderChangedCommentState($comment); - } + } /** * Redirect back to referer if available, ensuring that only site URLs * are allowed to avoid phishing. If it's an AJAX request render the * comment in it's new state */ - private function renderChangedCommentState($comment) { + private function renderChangedCommentState($comment) + { $referer = $this->request->getHeader('Referer'); // Render comment using AJAX @@ -295,7 +327,7 @@ class CommentingController extends Controller { // Redirect to the comment, but check for phishing $url = $referer . '#comment-' . $comment->ID; // absolute redirection URLs not located on this site may cause phishing - if(Director::is_site_url($url)) { + if (Director::is_site_url($url)) { return $this->redirect($url); } else { return false; @@ -304,336 +336,348 @@ class CommentingController extends Controller { } } - /** - * Returns the comment referenced in the URL (by ID). Permission checking - * should be done in the callee. - * - * @return Comment|false - */ - public function getComment() { - $id = isset($this->urlParams['ID']) ? $this->urlParams['ID'] : false; + /** + * Returns the comment referenced in the URL (by ID). Permission checking + * should be done in the callee. + * + * @return Comment|false + */ + public function getComment() + { + $id = isset($this->urlParams['ID']) ? $this->urlParams['ID'] : false; - if($id) { - $comment = DataObject::get_by_id('Comment', $id); + if ($id) { + $comment = DataObject::get_by_id('Comment', $id); - if($comment) { - $this->fallbackReturnURL = $comment->Link(); - return $comment; - } - } + if ($comment) { + $this->fallbackReturnURL = $comment->Link(); + return $comment; + } + } - return false; - } + return false; + } - /** - * Create a reply form for a specified comment - * - * @param Comment $comment - */ - public function ReplyForm($comment) { - // Enables multiple forms with different names to use the same handler - $form = $this->CommentsForm(); - $form->setName('ReplyForm_'.$comment->ID); - $form->addExtraClass('reply-form'); + /** + * Create a reply form for a specified comment + * + * @param Comment $comment + */ + public function ReplyForm($comment) + { + // Enables multiple forms with different names to use the same handler + $form = $this->CommentsForm(); + $form->setName('ReplyForm_'.$comment->ID); + $form->addExtraClass('reply-form'); - // Load parent into reply form - $form->loadDataFrom(array( - 'ParentCommentID' => $comment->ID - )); + // Load parent into reply form + $form->loadDataFrom(array( + 'ParentCommentID' => $comment->ID + )); - // Customise action - $form->setFormAction($this->Link('reply', $comment->ID)); + // Customise action + $form->setFormAction($this->Link('reply', $comment->ID)); - $this->extend('updateReplyForm', $form); - return $form; - } + $this->extend('updateReplyForm', $form); + return $form; + } - /** - * Request handler for reply form. - * This method will disambiguate multiple reply forms in the same method - * - * @param SS_HTTPRequest $request - */ - public function reply(SS_HTTPRequest $request) { - // Extract parent comment from reply and build this way - if($parentID = $request->param('ParentCommentID')) { - $comment = DataObject::get_by_id('Comment', $parentID, true); - if($comment) { - return $this->ReplyForm($comment); - } - } - return $this->httpError(404); - } + /** + * Request handler for reply form. + * This method will disambiguate multiple reply forms in the same method + * + * @param SS_HTTPRequest $request + */ + public function reply(SS_HTTPRequest $request) + { + // Extract parent comment from reply and build this way + if ($parentID = $request->param('ParentCommentID')) { + $comment = DataObject::get_by_id('Comment', $parentID, true); + if ($comment) { + return $this->ReplyForm($comment); + } + } + return $this->httpError(404); + } - /** - * Post a comment form - * - * @return Form - */ - public function CommentsForm() { - $usePreview = $this->getOption('use_preview'); + /** + * Post a comment form + * + * @return Form + */ + public function CommentsForm() + { + $usePreview = $this->getOption('use_preview'); - $nameRequired = _t('CommentInterface.YOURNAME_MESSAGE_REQUIRED', 'Please enter your name'); - $emailRequired = _t('CommentInterface.EMAILADDRESS_MESSAGE_REQUIRED', 'Please enter your email address'); - $emailInvalid = _t('CommentInterface.EMAILADDRESS_MESSAGE_EMAIL', 'Please enter a valid email address'); - $urlInvalid = _t('CommentInterface.COMMENT_MESSAGE_URL', 'Please enter a valid URL'); - $commentRequired = _t('CommentInterface.COMMENT_MESSAGE_REQUIRED', 'Please enter your comment'); + $nameRequired = _t('CommentInterface.YOURNAME_MESSAGE_REQUIRED', 'Please enter your name'); + $emailRequired = _t('CommentInterface.EMAILADDRESS_MESSAGE_REQUIRED', 'Please enter your email address'); + $emailInvalid = _t('CommentInterface.EMAILADDRESS_MESSAGE_EMAIL', 'Please enter a valid email address'); + $urlInvalid = _t('CommentInterface.COMMENT_MESSAGE_URL', 'Please enter a valid URL'); + $commentRequired = _t('CommentInterface.COMMENT_MESSAGE_REQUIRED', 'Please enter your comment'); - $fields = new FieldList( - $dataFields = new CompositeField( - // Name - TextField::create("Name", _t('CommentInterface.YOURNAME', 'Your name')) - ->setCustomValidationMessage($nameRequired) - ->setAttribute('data-msg-required', $nameRequired), + $fields = new FieldList( + $dataFields = new CompositeField( + // Name + TextField::create("Name", _t('CommentInterface.YOURNAME', 'Your name')) + ->setCustomValidationMessage($nameRequired) + ->setAttribute('data-msg-required', $nameRequired), - // Email - EmailField::create( - "Email", - _t('CommentingController.EMAILADDRESS', "Your email address (will not be published)") - ) - ->setCustomValidationMessage($emailRequired) - ->setAttribute('data-msg-required', $emailRequired) - ->setAttribute('data-msg-email', $emailInvalid) - ->setAttribute('data-rule-email', true), + // Email + EmailField::create( + "Email", + _t('CommentingController.EMAILADDRESS', "Your email address (will not be published)") + ) + ->setCustomValidationMessage($emailRequired) + ->setAttribute('data-msg-required', $emailRequired) + ->setAttribute('data-msg-email', $emailInvalid) + ->setAttribute('data-rule-email', true), - // Url - TextField::create("URL", _t('CommentingController.WEBSITEURL', "Your website URL")) - ->setAttribute('data-msg-url', $urlInvalid) - ->setAttribute('data-rule-url', true), + // Url + TextField::create("URL", _t('CommentingController.WEBSITEURL', "Your website URL")) + ->setAttribute('data-msg-url', $urlInvalid) + ->setAttribute('data-rule-url', true), - // Comment - TextareaField::create("Comment", _t('CommentingController.COMMENTS', "Comments")) - ->setCustomValidationMessage($commentRequired) - ->setAttribute('data-msg-required', $commentRequired) - ), - HiddenField::create("ParentID"), - HiddenField::create("ReturnURL"), - HiddenField::create("ParentCommentID"), - HiddenField::create("BaseClass") - ); + // Comment + TextareaField::create("Comment", _t('CommentingController.COMMENTS', "Comments")) + ->setCustomValidationMessage($commentRequired) + ->setAttribute('data-msg-required', $commentRequired) + ), + HiddenField::create("ParentID"), + HiddenField::create("ReturnURL"), + HiddenField::create("ParentCommentID"), + HiddenField::create("BaseClass") + ); - // 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' - ); - } + // 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' + ); + } - $dataFields->addExtraClass('data-fields'); + $dataFields->addExtraClass('data-fields'); - // save actions - $actions = new FieldList( - new FormAction("doPostComment", _t('CommentInterface.POST', 'Post')) - ); - if($usePreview) { - $actions->push( - FormAction::create('doPreviewComment', _t('CommentInterface.PREVIEW', 'Preview')) - ->addExtraClass('action-minor') - ->setAttribute('style', 'display: none') // enable through JS - ); - } + // save actions + $actions = new FieldList( + new FormAction("doPostComment", _t('CommentInterface.POST', 'Post')) + ); + if ($usePreview) { + $actions->push( + FormAction::create('doPreviewComment', _t('CommentInterface.PREVIEW', 'Preview')) + ->addExtraClass('action-minor') + ->setAttribute('style', 'display: none') // enable through JS + ); + } - // required fields for server side - $required = new RequiredFields($this->config()->required_fields); + // required fields for server side + $required = new RequiredFields($this->config()->required_fields); - // create the comment form - $form = new Form($this, 'CommentsForm', $fields, $actions, $required); + // 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()) { + // if the record exists load the extra required data + if ($record = $this->getOwnerRecord()) { - // Load member data - $member = Member::currentUser(); - if(($record->CommentsRequireLogin || $record->PostingRequiredPermission) && $member) { - $fields = $form->Fields(); + // Load member data + $member = Member::currentUser(); + if (($record->CommentsRequireLogin || $record->PostingRequiredPermission) && $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())); - $fields->push(new HiddenField("Email", "", $member->Email)); - } + $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())); + $fields->push(new HiddenField("Email", "", $member->Email)); + } - // we do not want to read a new URL when the form has already been submitted - // which in here, it hasn't been. - $form->loadDataFrom(array( - 'ParentID' => $record->ID, - 'ReturnURL' => $this->request->getURL(), - 'BaseClass' => $this->getBaseClass() - )); - } + // we do not want to read a new URL when the form has already been submitted + // which in here, it hasn't been. + $form->loadDataFrom(array( + 'ParentID' => $record->ID, + 'ReturnURL' => $this->request->getURL(), + 'BaseClass' => $this->getBaseClass() + )); + } - // Set it so the user gets redirected back down to the form upon form fail - $form->setRedirectToFormOnValidationError(true); + // 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')) { - $data = Convert::json2array($data); + // load any data from the cookies + if ($data = Cookie::get('CommentsForm_UserData')) { + $data = Convert::json2array($data); - $form->loadDataFrom(array( - "Name" => isset($data['Name']) ? $data['Name'] : '', - "URL" => isset($data['URL']) ? $data['URL'] : '', - "Email" => isset($data['Email']) ? $data['Email'] : '' - )); - // allow previous value to fill if comment not stored in cookie (i.e. validation error) - $prevComment = Cookie::get('CommentsForm_Comment'); - if($prevComment && $prevComment != ''){ - $form->loadDataFrom(array("Comment" => $prevComment)); - } - } + $form->loadDataFrom(array( + "Name" => isset($data['Name']) ? $data['Name'] : '', + "URL" => isset($data['URL']) ? $data['URL'] : '', + "Email" => isset($data['Email']) ? $data['Email'] : '' + )); + // allow previous value to fill if comment not stored in cookie (i.e. validation error) + $prevComment = Cookie::get('CommentsForm_Comment'); + if ($prevComment && $prevComment != '') { + $form->loadDataFrom(array("Comment" => $prevComment)); + } + } - if(!empty($member)) { - $form->loadDataFrom($member); - } + if (!empty($member)) { + $form->loadDataFrom($member); + } - // hook to allow further extensions to alter the comments form - $this->extend('alterCommentForm', $form); + // hook to allow further extensions to alter the comments form + $this->extend('alterCommentForm', $form); - return $form; - } + return $form; + } - /** - * Process which creates a {@link Comment} once a user submits a comment from this form. - * - * @param array $data - * @param Form $form - */ - public function doPostComment($data, $form) { - // Load class and parent from data - if(isset($data['BaseClass'])) { - $this->setBaseClass($data['BaseClass']); - } - if(isset($data['ParentID']) && ($class = $this->getBaseClass())) { - $this->setOwnerRecord($class::get()->byID($data['ParentID'])); - } - if(!$this->getOwnerRecord()) return $this->httpError(404); + /** + * Process which creates a {@link Comment} once a user submits a comment from this form. + * + * @param array $data + * @param Form $form + */ + public function doPostComment($data, $form) + { + // Load class and parent from data + if (isset($data['BaseClass'])) { + $this->setBaseClass($data['BaseClass']); + } + if (isset($data['ParentID']) && ($class = $this->getBaseClass())) { + $this->setOwnerRecord($class::get()->byID($data['ParentID'])); + } + if (!$this->getOwnerRecord()) { + return $this->httpError(404); + } - // cache users data - Cookie::set("CommentsForm_UserData", Convert::raw2json($data)); - Cookie::set("CommentsForm_Comment", $data['Comment']); + // cache users data + Cookie::set("CommentsForm_UserData", Convert::raw2json($data)); + Cookie::set("CommentsForm_Comment", $data['Comment']); - // extend hook to allow extensions. Also see onAfterPostComment - $this->extend('onBeforePostComment', $form); + // 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 - if(!$this->getOwnerRecord()->canPostComment()) { - return Security::permissionFailure( - $this, - _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." - ) - ); - } + // If commenting can only be done by logged in users, make sure the user is logged in + if (!$this->getOwnerRecord()->canPostComment()) { + return Security::permissionFailure( + $this, + _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." + ) + ); + } - if($member = Member::currentUser()) { - $form->Fields()->push(new HiddenField("AuthorID", "Author ID", $member->ID)); - } + if ($member = Member::currentUser()) { + $form->Fields()->push(new HiddenField("AuthorID", "Author ID", $member->ID)); + } - // What kind of moderation is required? - switch($this->getOwnerRecord()->ModerationRequired) { - case 'Required': - $requireModeration = true; - break; - case 'NonMembersOnly': - $requireModeration = empty($member); - break; - case 'None': - default: - $requireModeration = false; - break; - } + // What kind of moderation is required? + switch ($this->getOwnerRecord()->ModerationRequired) { + case 'Required': + $requireModeration = true; + break; + case 'NonMembersOnly': + $requireModeration = empty($member); + break; + case 'None': + default: + $requireModeration = false; + break; + } - $comment = new Comment(); - $form->saveInto($comment); + $comment = new Comment(); + $form->saveInto($comment); - $comment->AllowHtml = $this->getOption('html_allowed'); - $comment->Moderated = !$requireModeration; + $comment->AllowHtml = $this->getOption('html_allowed'); + $comment->Moderated = !$requireModeration; - // Save into DB, or call pre-save hooks to give accurate preview - $usePreview = $this->getOption('use_preview'); - $isPreview = $usePreview && !empty($data['IsPreview']); - if($isPreview) { - $comment->extend('onBeforeWrite'); - } else { - $comment->write(); + // Save into DB, or call pre-save hooks to give accurate preview + $usePreview = $this->getOption('use_preview'); + $isPreview = $usePreview && !empty($data['IsPreview']); + if ($isPreview) { + $comment->extend('onBeforeWrite'); + } else { + $comment->write(); - // extend hook to allow extensions. Also see onBeforePostComment - $this->extend('onAfterPostComment', $comment); - } + // extend hook to allow extensions. Also see onBeforePostComment + $this->extend('onAfterPostComment', $comment); + } - // we want to show a notification if comments are moderated - if ($requireModeration && !$comment->IsSpam) { - Session::set('CommentsModerated', 1); - } + // we want to show a notification if comments are moderated + if ($requireModeration && !$comment->IsSpam) { + Session::set('CommentsModerated', 1); + } - // clear the users comment since it passed validation - Cookie::set('CommentsForm_Comment', false); + // clear the users comment since it passed validation + Cookie::set('CommentsForm_Comment', false); - // Find parent link - if(!empty($data['ReturnURL'])) { - $url = $data['ReturnURL']; - } elseif($parent = $comment->getParent()) { - $url = $parent->Link(); - } else { - return $this->redirectBack(); - } + // Find parent link + if (!empty($data['ReturnURL'])) { + $url = $data['ReturnURL']; + } elseif ($parent = $comment->getParent()) { + $url = $parent->Link(); + } else { + return $this->redirectBack(); + } - // Given a redirect page exists, attempt to link to the correct anchor - if($comment->IsSpam) { - // Link to the form with the error message contained - $hash = $form->FormName(); - } else if(!$comment->Moderated) { - // Display the "awaiting moderation" text - $holder = $this->getOption('comments_holder_id'); - $hash = "{$holder}_PostCommentForm_error"; - } else { - // Link to the moderated, non-spam comment - $hash = $comment->Permalink(); - } + // Given a redirect page exists, attempt to link to the correct anchor + if ($comment->IsSpam) { + // Link to the form with the error message contained + $hash = $form->FormName(); + } elseif (!$comment->Moderated) { + // Display the "awaiting moderation" text + $holder = $this->getOption('comments_holder_id'); + $hash = "{$holder}_PostCommentForm_error"; + } else { + // Link to the moderated, non-spam comment + $hash = $comment->Permalink(); + } - return $this->redirect(Controller::join_links($url, "#{$hash}")); - } + return $this->redirect(Controller::join_links($url, "#{$hash}")); + } - public function doPreviewComment($data, $form) { - $data['IsPreview'] = 1; + public function doPreviewComment($data, $form) + { + $data['IsPreview'] = 1; - return $this->doPostComment($data, $form); - } + return $this->doPostComment($data, $form); + } - public function redirectBack() { - // Don't cache the redirect back ever - HTTP::set_cache_age(0); + public function redirectBack() + { + // Don't cache the redirect back ever + HTTP::set_cache_age(0); - $url = null; + $url = null; - // In edge-cases, this will be called outside of a handleRequest() context; in that case, - // redirect to the homepage - don't break into the global state at this stage because we'll - // be calling from a test context or something else where the global state is inappropraite - if($this->request) { - if($this->request->requestVar('BackURL')) { - $url = $this->request->requestVar('BackURL'); - } else if($this->request->isAjax() && $this->request->getHeader('X-Backurl')) { - $url = $this->request->getHeader('X-Backurl'); - } else if($this->request->getHeader('Referer')) { - $url = $this->request->getHeader('Referer'); - } - } + // In edge-cases, this will be called outside of a handleRequest() context; in that case, + // redirect to the homepage - don't break into the global state at this stage because we'll + // be calling from a test context or something else where the global state is inappropraite + if ($this->request) { + if ($this->request->requestVar('BackURL')) { + $url = $this->request->requestVar('BackURL'); + } elseif ($this->request->isAjax() && $this->request->getHeader('X-Backurl')) { + $url = $this->request->getHeader('X-Backurl'); + } elseif ($this->request->getHeader('Referer')) { + $url = $this->request->getHeader('Referer'); + } + } - if(!$url) $url = $this->fallbackReturnURL; - if(!$url) $url = Director::baseURL(); + if (!$url) { + $url = $this->fallbackReturnURL; + } + if (!$url) { + $url = Director::baseURL(); + } - // absolute redirection URLs not located on this site may cause phishing - if(Director::is_site_url($url)) { - return $this->redirect($url); - } else { - return false; - } - - } + // absolute redirection URLs not located on this site may cause phishing + if (Director::is_site_url($url)) { + return $this->redirect($url); + } else { + return false; + } + } } diff --git a/code/extensions/CommentsExtension.php b/code/extensions/CommentsExtension.php index 403c9b6..88ad47b 100644 --- a/code/extensions/CommentsExtension.php +++ b/code/extensions/CommentsExtension.php @@ -5,558 +5,600 @@ * * @package comments */ -class CommentsExtension extends DataExtension { - /** - * Default configuration values - * - * enabled: Allows commenting to be disabled even if the extension is present - * enabled_cms: Allows commenting to be enabled or disabled via the CMS - * require_login: Boolean, whether a user needs to login (required for required_permission) - * require_login_cms: Allows require_login to be set via the CMS - * required_permission: Permission (or array of permissions) required to comment - * include_js: Enhance operation by ajax behaviour on moderation links (required for use_preview) - * use_gravatar: Set to true to show gravatar icons - * gravatar_default: Theme for 'not found' gravatar {@see http://gravatar.com/site/implement/images} - * gravatar_rating: Gravatar rating (same as the standard default) - * show_comments_when_disabled: Show older comments when commenting has been disabled. - * order_comments_by: Default sort order. - * order_replies_by: Sort order for replies. - * comments_holder_id: ID for the comments holder - * comment_permalink_prefix: ID prefix for each comment - * require_moderation: Require moderation for all comments - * require_moderation_cms: Ignore other comment moderation config settings and set via CMS - * frontend_moderation: Display unmoderated comments in the frontend, if the user can moderate them. - * frontend_spam: Display spam comments in the frontend, if the user can moderate them. - * html_allowed: Allow for sanitized HTML in comments - * use_preview: Preview formatted comment (when allowing HTML) - * nested_comments: Enable nested comments - * nested_depth: Max depth of nested comments in levels (where root is 1 depth) 0 means no limit. - * - * @var array - * - * @config - */ - private static $comments = array( - 'enabled' => true, - 'enabled_cms' => false, - 'require_login' => false, - 'require_login_cms' => false, - 'required_permission' => false, - 'include_js' => true, - 'use_gravatar' => false, - 'gravatar_size' => 80, - 'gravatar_default' => 'identicon', - 'gravatar_rating' => 'g', - 'show_comments_when_disabled' => false, - 'order_comments_by' => '"Created" DESC', - 'order_replies_by' => false, - 'comments_per_page' => 10, - 'comments_holder_id' => 'comments-holder', - 'comment_permalink_prefix' => 'comment-', - 'require_moderation' => false, - 'require_moderation_nonmembers' => false, - 'require_moderation_cms' => false, - 'frontend_moderation' => false, - 'frontend_spam' => false, - 'html_allowed' => false, - 'html_allowed_elements' => array('a', 'img', 'i', 'b'), - 'use_preview' => false, - 'nested_comments' => false, - 'nested_depth' => 2, - ); +class CommentsExtension extends DataExtension +{ + /** + * Default configuration values + * + * enabled: Allows commenting to be disabled even if the extension is present + * enabled_cms: Allows commenting to be enabled or disabled via the CMS + * require_login: Boolean, whether a user needs to login (required for required_permission) + * require_login_cms: Allows require_login to be set via the CMS + * required_permission: Permission (or array of permissions) required to comment + * include_js: Enhance operation by ajax behaviour on moderation links (required for use_preview) + * use_gravatar: Set to true to show gravatar icons + * gravatar_default: Theme for 'not found' gravatar {@see http://gravatar.com/site/implement/images} + * gravatar_rating: Gravatar rating (same as the standard default) + * show_comments_when_disabled: Show older comments when commenting has been disabled. + * order_comments_by: Default sort order. + * order_replies_by: Sort order for replies. + * comments_holder_id: ID for the comments holder + * comment_permalink_prefix: ID prefix for each comment + * require_moderation: Require moderation for all comments + * require_moderation_cms: Ignore other comment moderation config settings and set via CMS + * frontend_moderation: Display unmoderated comments in the frontend, if the user can moderate them. + * frontend_spam: Display spam comments in the frontend, if the user can moderate them. + * html_allowed: Allow for sanitized HTML in comments + * use_preview: Preview formatted comment (when allowing HTML) + * nested_comments: Enable nested comments + * nested_depth: Max depth of nested comments in levels (where root is 1 depth) 0 means no limit. + * + * @var array + * + * @config + */ + private static $comments = array( + 'enabled' => true, + 'enabled_cms' => false, + 'require_login' => false, + 'require_login_cms' => false, + 'required_permission' => false, + 'include_js' => true, + 'use_gravatar' => false, + 'gravatar_size' => 80, + 'gravatar_default' => 'identicon', + 'gravatar_rating' => 'g', + 'show_comments_when_disabled' => false, + 'order_comments_by' => '"Created" DESC', + 'order_replies_by' => false, + 'comments_per_page' => 10, + 'comments_holder_id' => 'comments-holder', + 'comment_permalink_prefix' => 'comment-', + 'require_moderation' => false, + 'require_moderation_nonmembers' => false, + 'require_moderation_cms' => false, + 'frontend_moderation' => false, + 'frontend_spam' => false, + 'html_allowed' => false, + 'html_allowed_elements' => array('a', 'img', 'i', 'b'), + 'use_preview' => false, + 'nested_comments' => false, + 'nested_depth' => 2, + ); - /** - * @var array - */ - private static $db = array( - 'ProvideComments' => 'Boolean', - 'ModerationRequired' => 'Enum(\'None,Required,NonMembersOnly\',\'None\')', - 'CommentsRequireLogin' => 'Boolean', - ); + /** + * @var array + */ + private static $db = array( + 'ProvideComments' => 'Boolean', + 'ModerationRequired' => 'Enum(\'None,Required,NonMembersOnly\',\'None\')', + 'CommentsRequireLogin' => 'Boolean', + ); - /** - * CMS configurable options should default to the config values, but respect - * default values specified by the object - */ - public function populateDefaults() { - $defaults = $this->owner->config()->defaults; + /** + * CMS configurable options should default to the config values, but respect + * default values specified by the object + */ + public function populateDefaults() + { + $defaults = $this->owner->config()->defaults; - // Set if comments should be enabled by default - if(isset($defaults['ProvideComments'])) { - $this->owner->ProvideComments = $defaults['ProvideComments']; - } else { - $this->owner->ProvideComments = $this->owner->getCommentsOption('enabled') ? 1 : 0; - } + // Set if comments should be enabled by default + if (isset($defaults['ProvideComments'])) { + $this->owner->ProvideComments = $defaults['ProvideComments']; + } else { + $this->owner->ProvideComments = $this->owner->getCommentsOption('enabled') ? 1 : 0; + } - // If moderation options should be configurable via the CMS then - if(isset($defaults['ModerationRequired'])) { - $this->owner->ModerationRequired = $defaults['ModerationRequired']; - } elseif($this->owner->getCommentsOption('require_moderation')) { - $this->owner->ModerationRequired = 'Required'; - } elseif($this->owner->getCommentsOption('require_moderation_nonmembers')) { - $this->owner->ModerationRequired = 'NonMembersOnly'; - } else { - $this->owner->ModerationRequired = 'None'; - } + // If moderation options should be configurable via the CMS then + if (isset($defaults['ModerationRequired'])) { + $this->owner->ModerationRequired = $defaults['ModerationRequired']; + } elseif ($this->owner->getCommentsOption('require_moderation')) { + $this->owner->ModerationRequired = 'Required'; + } elseif ($this->owner->getCommentsOption('require_moderation_nonmembers')) { + $this->owner->ModerationRequired = 'NonMembersOnly'; + } else { + $this->owner->ModerationRequired = 'None'; + } - // Set login required - if(isset($defaults['CommentsRequireLogin'])) { - $this->owner->CommentsRequireLogin = $defaults['CommentsRequireLogin']; - } else { - $this->owner->CommentsRequireLogin = $this->owner->getCommentsOption('require_login') ? 1 : 0; - } - } + // Set login required + if (isset($defaults['CommentsRequireLogin'])) { + $this->owner->CommentsRequireLogin = $defaults['CommentsRequireLogin']; + } else { + $this->owner->CommentsRequireLogin = $this->owner->getCommentsOption('require_login') ? 1 : 0; + } + } - /** - * If this extension is applied to a {@link SiteTree} record then - * append a Provide Comments checkbox to allow authors to trigger - * whether or not to display comments - * - * @todo Allow customization of other {@link Commenting} configuration - * - * @param FieldList $fields - */ - public function updateSettingsFields(FieldList $fields) { + /** + * If this extension is applied to a {@link SiteTree} record then + * append a Provide Comments checkbox to allow authors to trigger + * whether or not to display comments + * + * @todo Allow customization of other {@link Commenting} configuration + * + * @param FieldList $fields + */ + public function updateSettingsFields(FieldList $fields) + { + $options = FieldGroup::create()->setTitle(_t('CommentsExtension.COMMENTOPTIONS', 'Comments')); - $options = FieldGroup::create()->setTitle(_t('CommentsExtension.COMMENTOPTIONS', 'Comments')); + // Check if enabled setting should be cms configurable + if ($this->owner->getCommentsOption('enabled_cms')) { + $options->push(new CheckboxField('ProvideComments', _t('Comment.ALLOWCOMMENTS', 'Allow Comments'))); + } - // Check if enabled setting should be cms configurable - if($this->owner->getCommentsOption('enabled_cms')) { - $options->push(new CheckboxField('ProvideComments', _t('Comment.ALLOWCOMMENTS', 'Allow Comments'))); - } + // Check if we should require users to login to comment + if ($this->owner->getCommentsOption('require_login_cms')) { + $options->push( + new CheckboxField( + 'CommentsRequireLogin', + _t('Comments.COMMENTSREQUIRELOGIN', 'Require login to comment') + ) + ); + } - // Check if we should require users to login to comment - if($this->owner->getCommentsOption('require_login_cms')) { - $options->push( - new CheckboxField( - 'CommentsRequireLogin', - _t('Comments.COMMENTSREQUIRELOGIN', 'Require login to comment') - ) - ); - } + if ($options->FieldList()->count()) { + if ($fields->hasTabSet()) { + $fields->addFieldsToTab('Root.Settings', $options); + } else { + $fields->push($options); + } + } - if($options->FieldList()->count()) { - if($fields->hasTabSet()) { - $fields->addFieldsToTab('Root.Settings', $options); - } else { - $fields->push($options); - } - } + // Check if moderation should be enabled via cms configurable + if ($this->owner->getCommentsOption('require_moderation_cms')) { + $moderationField = new DropdownField('ModerationRequired', 'Comment Moderation', array( + 'None' => _t('CommentsExtension.MODERATIONREQUIRED_NONE', 'No moderation required'), + 'Required' => _t('CommentsExtension.MODERATIONREQUIRED_REQUIRED', 'Moderate all comments'), + 'NonMembersOnly' => _t( + 'CommentsExtension.MODERATIONREQUIRED_NONMEMBERSONLY', + 'Only moderate non-members' + ), + )); + if ($fields->hasTabSet()) { + $fields->addFieldsToTab('Root.Settings', $moderationField); + } else { + $fields->push($moderationField); + } + } + } - // Check if moderation should be enabled via cms configurable - if($this->owner->getCommentsOption('require_moderation_cms')) { - $moderationField = new DropdownField('ModerationRequired', 'Comment Moderation', array( - 'None' => _t('CommentsExtension.MODERATIONREQUIRED_NONE', 'No moderation required'), - 'Required' => _t('CommentsExtension.MODERATIONREQUIRED_REQUIRED', 'Moderate all comments'), - 'NonMembersOnly' => _t( - 'CommentsExtension.MODERATIONREQUIRED_NONMEMBERSONLY', - 'Only moderate non-members' - ), - )); - if($fields->hasTabSet()) { - $fields->addFieldsToTab('Root.Settings', $moderationField); - } else { - $fields->push($moderationField); - } - } - } + /** + * Get comment moderation rules for this parent + * + * None: No moderation required + * Required: All comments + * NonMembersOnly: Only anonymous users + * + * @return string + */ + public function getModerationRequired() + { + if ($this->owner->getCommentsOption('require_moderation_cms')) { + return $this->owner->getField('ModerationRequired'); + } elseif ($this->owner->getCommentsOption('require_moderation')) { + return 'Required'; + } elseif ($this->owner->getCommentsOption('require_moderation_nonmembers')) { + return 'NonMembersOnly'; + } else { + return 'None'; + } + } - /** - * Get comment moderation rules for this parent - * - * None: No moderation required - * Required: All comments - * NonMembersOnly: Only anonymous users - * - * @return string - */ - public function getModerationRequired() { - if($this->owner->getCommentsOption('require_moderation_cms')) { - return $this->owner->getField('ModerationRequired'); - } elseif($this->owner->getCommentsOption('require_moderation')) { - return 'Required'; - } elseif($this->owner->getCommentsOption('require_moderation_nonmembers')) { - return 'NonMembersOnly'; - } else { - return 'None'; - } - } + /** + * Determine if users must be logged in to post comments + * + * @return boolean + */ + public function getCommentsRequireLogin() + { + if ($this->owner->getCommentsOption('require_login_cms')) { + return (bool) $this->owner->getField('CommentsRequireLogin'); + } else { + return (bool) $this->owner->getCommentsOption('require_login'); + } + } - /** - * Determine if users must be logged in to post comments - * - * @return boolean - */ - public function getCommentsRequireLogin() { - if($this->owner->getCommentsOption('require_login_cms')) { - return (bool) $this->owner->getField('CommentsRequireLogin'); - } else { - return (bool) $this->owner->getCommentsOption('require_login'); - } - } + /** + * Returns the RelationList of all comments against this object. Can be used as a data source + * for a gridfield with write access. + * + * @return CommentList + */ + public function AllComments() + { + $order = $this->owner->getCommentsOption('order_comments_by'); + $comments = CommentList::create($this->ownerBaseClass) + ->forForeignID($this->owner->ID) + ->sort($order); + $this->owner->extend('updateAllComments', $comments); + return $comments; + } - /** - * Returns the RelationList of all comments against this object. Can be used as a data source - * for a gridfield with write access. - * - * @return CommentList - */ - public function AllComments() { - $order = $this->owner->getCommentsOption('order_comments_by'); - $comments = CommentList::create($this->ownerBaseClass) - ->forForeignID($this->owner->ID) - ->sort($order); - $this->owner->extend('updateAllComments', $comments); - return $comments; - } + /** + * Returns all comments against this object, with with spam and unmoderated items excluded, for use in the frontend + * + * @return CommentList + */ + public function AllVisibleComments() + { + $list = $this->AllComments(); - /** - * Returns all comments against this object, with with spam and unmoderated items excluded, for use in the frontend - * - * @return CommentList - */ - public function AllVisibleComments() { - $list = $this->AllComments(); + // Filter spam comments for non-administrators if configured + $showSpam = $this->owner->getCommentsOption('frontend_spam') && $this->owner->canModerateComments(); + if (!$showSpam) { + $list = $list->filter('IsSpam', 0); + } - // Filter spam comments for non-administrators if configured - $showSpam = $this->owner->getCommentsOption('frontend_spam') && $this->owner->canModerateComments(); - if(!$showSpam) { - $list = $list->filter('IsSpam', 0); - } + // Filter un-moderated comments for non-administrators if moderation is enabled + $showUnmoderated = ($this->owner->ModerationRequired === 'None') + || ($this->owner->getCommentsOption('frontend_moderation') && $this->owner->canModerateComments()); + if (!$showUnmoderated) { + $list = $list->filter('Moderated', 1); + } - // Filter un-moderated comments for non-administrators if moderation is enabled - $showUnmoderated = ($this->owner->ModerationRequired === 'None') - || ($this->owner->getCommentsOption('frontend_moderation') && $this->owner->canModerateComments()); - if(!$showUnmoderated) { - $list = $list->filter('Moderated', 1); - } + $this->owner->extend('updateAllVisibleComments', $list); + return $list; + } - $this->owner->extend('updateAllVisibleComments', $list); - return $list; - } + /** + * Returns the root level comments, with spam and unmoderated items excluded, for use in the frontend + * + * @return CommentList + */ + public function Comments() + { + $list = $this->AllVisibleComments(); - /** - * Returns the root level comments, with spam and unmoderated items excluded, for use in the frontend - * - * @return CommentList - */ - public function Comments() { - $list = $this->AllVisibleComments(); + // If nesting comments, only show root level + if ($this->owner->getCommentsOption('nested_comments')) { + $list = $list->filter('ParentCommentID', 0); + } - // If nesting comments, only show root level - if($this->owner->getCommentsOption('nested_comments')) { - $list = $list->filter('ParentCommentID', 0); - } + $this->owner->extend('updateComments', $list); + return $list; + } - $this->owner->extend('updateComments', $list); - return $list; - } + /** + * Returns a paged list of the root level comments, with spam and unmoderated items excluded, + * for use in the frontend + * + * @return PaginatedList + */ + public function PagedComments() + { + $list = $this->Comments(); - /** - * Returns a paged list of the root level comments, with spam and unmoderated items excluded, - * for use in the frontend - * - * @return PaginatedList - */ - public function PagedComments() { - $list = $this->Comments(); + // Add pagination + $list = new PaginatedList($list, Controller::curr()->getRequest()); + $list->setPaginationGetVar('commentsstart' . $this->owner->ID); + $list->setPageLength($this->owner->getCommentsOption('comments_per_page')); - // Add pagination - $list = new PaginatedList($list, Controller::curr()->getRequest()); - $list->setPaginationGetVar('commentsstart' . $this->owner->ID); - $list->setPageLength($this->owner->getCommentsOption('comments_per_page')); + $this->owner->extend('updatePagedComments', $list); + return $list; + } - $this->owner->extend('updatePagedComments', $list); - return $list; - } + /** + * Check if comments are configured for this page even if they are currently disabled. + * Do not include the comments on pages which don't have id's such as security pages + * + * @deprecated since version 2.0 + * + * @return boolean + */ + public function getCommentsConfigured() + { + Deprecation::notice('2.0', 'getCommentsConfigured is deprecated. Use getCommentsEnabled instead'); + return true; // by virtue of all classes with this extension being 'configured' + } - /** - * Check if comments are configured for this page even if they are currently disabled. - * Do not include the comments on pages which don't have id's such as security pages - * - * @deprecated since version 2.0 - * - * @return boolean - */ - public function getCommentsConfigured() { - Deprecation::notice('2.0', 'getCommentsConfigured is deprecated. Use getCommentsEnabled instead'); - return true; // by virtue of all classes with this extension being 'configured' - } + /** + * Determine if comments are enabled for this instance + * + * @return boolean + */ + public function getCommentsEnabled() + { + // Don't display comments form for pseudo-pages (such as the login form) + if (!$this->owner->exists()) { + return false; + } - /** - * Determine if comments are enabled for this instance - * - * @return boolean - */ - public function getCommentsEnabled() { - // Don't display comments form for pseudo-pages (such as the login form) - if(!$this->owner->exists()) return false; + // Determine which flag should be used to determine if this is enabled + if ($this->owner->getCommentsOption('enabled_cms')) { + return $this->owner->ProvideComments; + } else { + return $this->owner->getCommentsOption('enabled'); + } + } - // Determine which flag should be used to determine if this is enabled - if($this->owner->getCommentsOption('enabled_cms')) { - return $this->owner->ProvideComments; - } else { - return $this->owner->getCommentsOption('enabled'); - } - } + /** + * Get the HTML ID for the comment holder in the template + * + * @return string + */ + public function getCommentHolderID() + { + return $this->owner->getCommentsOption('comments_holder_id'); + } - /** - * Get the HTML ID for the comment holder in the template - * - * @return string - */ - public function getCommentHolderID() { - return $this->owner->getCommentsOption('comments_holder_id'); - } + /** + * @deprecated since version 2.0 + */ + public function getPostingRequiresPermission() + { + Deprecation::notice('2.0', 'Use getPostingRequiredPermission instead'); + return $this->getPostingRequiredPermission(); + } - /** - * @deprecated since version 2.0 - */ - public function getPostingRequiresPermission() { - Deprecation::notice('2.0', 'Use getPostingRequiredPermission instead'); - return $this->getPostingRequiredPermission(); - } + /** + * Permission codes required in order to post (or empty if none required) + * + * @return string|array Permission or list of permissions, if required + */ + public function getPostingRequiredPermission() + { + return $this->owner->getCommentsOption('required_permission'); + } - /** - * Permission codes required in order to post (or empty if none required) - * - * @return string|array Permission or list of permissions, if required - */ - public function getPostingRequiredPermission() { - return $this->owner->getCommentsOption('required_permission'); - } + public function canPost() + { + Deprecation::notice('2.0', 'Use canPostComment instead'); + return $this->canPostComment(); + } - public function canPost() { - Deprecation::notice('2.0', 'Use canPostComment instead'); - return $this->canPostComment(); - } + /** + * Determine if a user can post comments on this item + * + * @param Member $member Member to check + * + * @return boolean + */ + public function canPostComment($member = null) + { + // Deny if not enabled for this object + if (!$this->owner->CommentsEnabled) { + return false; + } - /** - * Determine if a user can post comments on this item - * - * @param Member $member Member to check - * - * @return boolean - */ - public function canPostComment($member = null) { - // Deny if not enabled for this object - if(!$this->owner->CommentsEnabled) return false; + // Check if member is required + $requireLogin = $this->owner->CommentsRequireLogin; + if (!$requireLogin) { + return true; + } - // Check if member is required - $requireLogin = $this->owner->CommentsRequireLogin; - if(!$requireLogin) return true; + // Check member is logged in + $member = $member ?: Member::currentUser(); + if (!$member) { + return false; + } - // Check member is logged in - $member = $member ?: Member::currentUser(); - if(!$member) return false; + // If member required check permissions + $requiredPermission = $this->owner->PostingRequiredPermission; + if ($requiredPermission && !Permission::checkMember($member, $requiredPermission)) { + return false; + } - // If member required check permissions - $requiredPermission = $this->owner->PostingRequiredPermission; - if($requiredPermission && !Permission::checkMember($member, $requiredPermission)) return false; + return true; + } - return true; - } + /** + * Determine if this member can moderate comments in the CMS + * + * @param Member $member + * + * @return boolean + */ + public function canModerateComments($member = null) + { + // Deny if not enabled for this object + if (!$this->owner->CommentsEnabled) { + return false; + } - /** - * Determine if this member can moderate comments in the CMS - * - * @param Member $member - * - * @return boolean - */ - public function canModerateComments($member = null) { - // Deny if not enabled for this object - if(!$this->owner->CommentsEnabled) return false; + // Fallback to can-edit + return $this->owner->canEdit($member); + } - // Fallback to can-edit - return $this->owner->canEdit($member); - } + public function getRssLink() + { + Deprecation::notice('2.0', 'Use getCommentRSSLink instead'); + return $this->getCommentRSSLink(); + } - public function getRssLink() { - Deprecation::notice('2.0', 'Use getCommentRSSLink instead'); - return $this->getCommentRSSLink(); - } + /** + * Gets the RSS link to all comments + * + * @return string + */ + public function getCommentRSSLink() + { + return Controller::join_links(Director::baseURL(), 'CommentingController/rss'); + } - /** - * Gets the RSS link to all comments - * - * @return string - */ - public function getCommentRSSLink() { - return Controller::join_links(Director::baseURL(), 'CommentingController/rss'); - } + public function getRssLinkPage() + { + Deprecation::notice('2.0', 'Use getCommentRSSLinkPage instead'); + return $this->getCommentRSSLinkPage(); + } - public function getRssLinkPage() { - Deprecation::notice('2.0', 'Use getCommentRSSLinkPage instead'); - return $this->getCommentRSSLinkPage(); - } + /** + * Get the RSS link to all comments on this page + * + * @return string + */ + public function getCommentRSSLinkPage() + { + return Controller::join_links( + $this->getCommentRSSLink(), $this->ownerBaseClass, $this->owner->ID + ); + } - /** - * Get the RSS link to all comments on this page - * - * @return string - */ - public function getCommentRSSLinkPage() { - return Controller::join_links( - $this->getCommentRSSLink(), $this->ownerBaseClass, $this->owner->ID - ); - } + /** + * Comments interface for the front end. Includes the CommentAddForm and the composition + * of the comments display. + * + * To customize the html see templates/CommentInterface.ss or extend this function with + * your own extension. + * + * @todo Cleanup the passing of all this configuration based functionality + * + * @see docs/en/Extending + */ + public function CommentsForm() + { + // Check if enabled + $enabled = $this->getCommentsEnabled(); + if ($enabled && $this->owner->getCommentsOption('include_js')) { + Requirements::javascript(THIRDPARTY_DIR . '/jquery/jquery.js'); + Requirements::javascript(THIRDPARTY_DIR . '/jquery-entwine/dist/jquery.entwine-dist.js'); + Requirements::javascript(THIRDPARTY_DIR . '/jquery-validate/lib/jquery.form.js'); + Requirements::javascript(COMMENTS_THIRDPARTY . '/jquery-validate/jquery.validate.min.js'); + Requirements::add_i18n_javascript('comments/javascript/lang'); + Requirements::javascript('comments/javascript/CommentsInterface.js'); + } - /** - * Comments interface for the front end. Includes the CommentAddForm and the composition - * of the comments display. - * - * To customize the html see templates/CommentInterface.ss or extend this function with - * your own extension. - * - * @todo Cleanup the passing of all this configuration based functionality - * - * @see docs/en/Extending - */ - public function CommentsForm() { - // Check if enabled - $enabled = $this->getCommentsEnabled(); - if($enabled && $this->owner->getCommentsOption('include_js')) { - Requirements::javascript(THIRDPARTY_DIR . '/jquery/jquery.js'); - Requirements::javascript(THIRDPARTY_DIR . '/jquery-entwine/dist/jquery.entwine-dist.js'); - Requirements::javascript(THIRDPARTY_DIR . '/jquery-validate/lib/jquery.form.js'); - Requirements::javascript(COMMENTS_THIRDPARTY . '/jquery-validate/jquery.validate.min.js'); - Requirements::add_i18n_javascript('comments/javascript/lang'); - Requirements::javascript('comments/javascript/CommentsInterface.js'); - } + $controller = CommentingController::create(); + $controller->setOwnerRecord($this->owner); + $controller->setBaseClass($this->ownerBaseClass); + $controller->setOwnerController(Controller::curr()); - $controller = CommentingController::create(); - $controller->setOwnerRecord($this->owner); - $controller->setBaseClass($this->ownerBaseClass); - $controller->setOwnerController(Controller::curr()); + $moderatedSubmitted = Session::get('CommentsModerated'); + Session::clear('CommentsModerated'); - $moderatedSubmitted = Session::get('CommentsModerated'); - Session::clear('CommentsModerated'); + $form = ($enabled) ? $controller->CommentsForm() : false; - $form = ($enabled) ? $controller->CommentsForm() : false; + // a little bit all over the show but to ensure a slightly easier upgrade for users + // return back the same variables as previously done in comments + return $this + ->owner + ->customise(array( + 'AddCommentForm' => $form, + 'ModeratedSubmitted' => $moderatedSubmitted, + )) + ->renderWith('CommentsInterface'); + } - // a little bit all over the show but to ensure a slightly easier upgrade for users - // return back the same variables as previously done in comments - return $this - ->owner - ->customise(array( - 'AddCommentForm' => $form, - 'ModeratedSubmitted' => $moderatedSubmitted, - )) - ->renderWith('CommentsInterface'); - } + /** + * Returns whether this extension instance is attached to a {@link SiteTree} object + * + * @return bool + */ + public function attachedToSiteTree() + { + $class = $this->ownerBaseClass; - /** - * Returns whether this extension instance is attached to a {@link SiteTree} object - * - * @return bool - */ - public function attachedToSiteTree() { - $class = $this->ownerBaseClass; + return (is_subclass_of($class, 'SiteTree')) || ($class == 'SiteTree'); + } - return (is_subclass_of($class, 'SiteTree')) || ($class == 'SiteTree'); - } + /** + * @deprecated 1.0 Please use {@link CommentsExtension->CommentsForm()} + */ + public function PageComments() + { + // This method is very commonly used, don't throw a warning just yet + Deprecation::notice('1.0', '$PageComments is deprecated. Please use $CommentsForm'); + return $this->CommentsForm(); + } - /** - * @deprecated 1.0 Please use {@link CommentsExtension->CommentsForm()} - */ - public function PageComments() { - // This method is very commonly used, don't throw a warning just yet - Deprecation::notice('1.0', '$PageComments is deprecated. Please use $CommentsForm'); - return $this->CommentsForm(); - } + /** + * Get the commenting option for this object + * + * This can be overridden in any instance or extension to customise the option available + * + * @param string $key + * + * @return mixed Result if the setting is available, or null otherwise + */ + public function getCommentsOption($key) + { + $settings = $this->owner // In case singleton is called on the extension directly + ? $this->owner->config()->comments + : Config::inst()->get(__CLASS__, 'comments'); + $value = null; + if (isset($settings[$key])) { + $value = $settings[$key]; + } - /** - * Get the commenting option for this object - * - * This can be overridden in any instance or extension to customise the option available - * - * @param string $key - * - * @return mixed Result if the setting is available, or null otherwise - */ - public function getCommentsOption($key) { - $settings = $this->owner // In case singleton is called on the extension directly - ? $this->owner->config()->comments - : Config::inst()->get(__CLASS__, 'comments'); - $value = null; - if(isset($settings[$key])) $value = $settings[$key]; + // To allow other extensions to customise this option + if ($this->owner) { + $this->owner->extend('updateCommentsOption', $key, $value); + } + return $value; + } - // To allow other extensions to customise this option - if($this->owner) $this->owner->extend('updateCommentsOption', $key, $value); - return $value; - } + /** + * Add moderation functions to the current fieldlist + * + * @param FieldList $fields + */ + protected function updateModerationFields(FieldList $fields) + { + Requirements::css(COMMENTS_DIR . '/css/cms.css'); - /** - * Add moderation functions to the current fieldlist - * - * @param FieldList $fields - */ - protected function updateModerationFields(FieldList $fields) { - Requirements::css(COMMENTS_DIR . '/css/cms.css'); + $newComments = $this->owner->AllComments()->filter('Moderated', 0); - $newComments = $this->owner->AllComments()->filter('Moderated', 0); + $newGrid = new CommentsGridField( + 'NewComments', + _t('CommentsAdmin.NewComments', 'New'), + $newComments, + CommentsGridFieldConfig::create() + ); - $newGrid = new CommentsGridField( - 'NewComments', - _t('CommentsAdmin.NewComments', 'New'), - $newComments, - CommentsGridFieldConfig::create() - ); + $approvedComments = $this->owner->AllComments()->filter('Moderated', 1)->filter('IsSpam', 0); - $approvedComments = $this->owner->AllComments()->filter('Moderated', 1)->filter('IsSpam', 0); + $approvedGrid = new CommentsGridField( + 'ApprovedComments', + _t('CommentsAdmin.Comments', 'Approved'), + $approvedComments, + CommentsGridFieldConfig::create() + ); - $approvedGrid = new CommentsGridField( - 'ApprovedComments', - _t('CommentsAdmin.Comments', 'Approved'), - $approvedComments, - CommentsGridFieldConfig::create() - ); + $spamComments = $this->owner->AllComments()->filter('Moderated', 1)->filter('IsSpam', 1); - $spamComments = $this->owner->AllComments()->filter('Moderated', 1)->filter('IsSpam', 1); + $spamGrid = new CommentsGridField( + 'SpamComments', + _t('CommentsAdmin.SpamComments', 'Spam'), + $spamComments, + CommentsGridFieldConfig::create() + ); - $spamGrid = new CommentsGridField( - 'SpamComments', - _t('CommentsAdmin.SpamComments', 'Spam'), - $spamComments, - CommentsGridFieldConfig::create() - ); + $newCount = '(' . count($newComments) . ')'; + $approvedCount = '(' . count($approvedComments) . ')'; + $spamCount = '(' . count($spamComments) . ')'; - $newCount = '(' . count($newComments) . ')'; - $approvedCount = '(' . count($approvedComments) . ')'; - $spamCount = '(' . count($spamComments) . ')'; + if ($fields->hasTabSet()) { + $tabs = new TabSet( + 'Comments', + new Tab('CommentsNewCommentsTab', _t('CommentAdmin.NewComments', 'New') . ' ' . $newCount, + $newGrid + ), + new Tab('CommentsCommentsTab', _t('CommentAdmin.Comments', 'Approved') . ' ' . $approvedCount, + $approvedGrid + ), + new Tab('CommentsSpamCommentsTab', _t('CommentAdmin.SpamComments', 'Spam') . ' ' . $spamCount, + $spamGrid + ) + ); + $fields->addFieldToTab('Root', $tabs); + } else { + $fields->push($newGrid); + $fields->push($approvedGrid); + $fields->push($spamGrid); + } + } - if($fields->hasTabSet()) { - $tabs = new TabSet( - 'Comments', - new Tab('CommentsNewCommentsTab', _t('CommentAdmin.NewComments', 'New') . ' ' . $newCount, - $newGrid - ), - new Tab('CommentsCommentsTab', _t('CommentAdmin.Comments', 'Approved') . ' ' . $approvedCount, - $approvedGrid - ), - new Tab('CommentsSpamCommentsTab', _t('CommentAdmin.SpamComments', 'Spam') . ' ' . $spamCount, - $spamGrid - ) - ); - $fields->addFieldToTab('Root', $tabs); - } else { - $fields->push($newGrid); - $fields->push($approvedGrid); - $fields->push($spamGrid); - } - } + public function updateCMSFields(FieldList $fields) + { + // Disable moderation if not permitted + if ($this->owner->canModerateComments()) { + $this->updateModerationFields($fields); + } - public function updateCMSFields(FieldList $fields) { - // Disable moderation if not permitted - if($this->owner->canModerateComments()) { - $this->updateModerationFields($fields); - } - - // If this isn't a page we should merge the settings into the CMS fields - if(!$this->attachedToSiteTree()) { - $this->updateSettingsFields($fields); - } - } + // If this isn't a page we should merge the settings into the CMS fields + if (!$this->attachedToSiteTree()) { + $this->updateSettingsFields($fields); + } + } } diff --git a/code/model/Comment.php b/code/model/Comment.php index d3834b5..60491ed 100755 --- a/code/model/Comment.php +++ b/code/model/Comment.php @@ -20,556 +20,593 @@ * @method Comment ParentComment() Parent comment this is a reply to * @package comments */ -class Comment extends DataObject { - - /** - * @var array - */ - private static $db = array( - 'Name' => 'Varchar(200)', - 'Comment' => 'Text', - 'Email' => 'Varchar(200)', - 'URL' => 'Varchar(255)', - 'BaseClass' => 'Varchar(200)', - 'Moderated' => 'Boolean(0)', - 'IsSpam' => 'Boolean(0)', - 'ParentID' => 'Int', - 'AllowHtml' => 'Boolean', - 'SecretToken' => 'Varchar(255)', - 'Depth' => 'Int', - ); - - private static $has_one = array( - "Author" => "Member", - "ParentComment" => "Comment", - ); - - private static $has_many = array( - "ChildComments" => "Comment" - ); - - private static $default_sort = '"Created" DESC'; - - private static $defaults = array( - 'Moderated' => 0, - 'IsSpam' => 0, - ); - - private static $casting = array( - 'Title' => 'Varchar', - 'ParentTitle' => 'Varchar', - 'ParentClassName' => 'Varchar', - 'AuthorName' => 'Varchar', - 'RSSName' => 'Varchar', - 'DeleteLink' => 'Varchar', - 'SpamLink' => 'Varchar', - 'HamLink' => 'Varchar', - 'ApproveLink' => 'Varchar', - 'Permalink' => 'Varchar', - ); - - private static $searchable_fields = array( - 'Name', - 'Email', - 'Comment', - 'Created', - 'BaseClass', - ); - - private static $summary_fields = array( - 'Name' => 'Submitted By', - 'Email' => 'Email', - 'Comment.LimitWordCount' => 'Comment', - 'Created' => 'Date Posted', - 'ParentTitle' => 'Post', - 'IsSpam' => 'Is Spam', - ); - - private static $field_labels = array( - 'Author' => 'Author Member', - ); - - public function onBeforeWrite() { - parent::onBeforeWrite(); - - // Sanitize HTML, because its expected to be passed to the template unescaped later - if($this->AllowHtml) { - $this->Comment = $this->purifyHtml($this->Comment); - } - - // Check comment depth - $this->updateDepth(); - } - - public function onBeforeDelete() { - parent::onBeforeDelete(); - - // Delete all children - foreach($this->ChildComments() as $comment) { - $comment->delete(); - } - } - - /** - * @return Comment_SecurityToken - */ - public function getSecurityToken() { - return Injector::inst()->createWithArgs('Comment_SecurityToken', array($this)); - } - - /** - * Migrates the old {@link PageComment} objects to {@link Comment} - */ - public function requireDefaultRecords() { - parent::requireDefaultRecords(); - - if(DB::getConn()->hasTable('PageComment')) { - $comments = DB::query('SELECT * FROM "PageComment"'); - - if($comments) { - while($pageComment = $comments->nextRecord()) { - // create a new comment from the older page comment - $comment = new Comment(); - $comment->update($pageComment); - - // set the variables which have changed - $comment->BaseClass = 'SiteTree'; - $comment->URL = (isset($pageComment['CommenterURL'])) ? $pageComment['CommenterURL'] : ''; - if((int) $pageComment['NeedsModeration'] == 0) $comment->Moderated = true; - - $comment->write(); - } - } - - DB::alteration_message('Migrated PageComment to Comment', 'changed'); - DB::getConn()->dontRequireTable('PageComment'); - } - } - - /** - * Return a link to this comment - * - * @param string $action - * - * @return string link to this comment. - */ - public function Link($action = '') { - if($parent = $this->getParent()) { - return $parent->Link($action) . '#' . $this->Permalink(); - } - } - - /** - * Returns the permalink for this {@link Comment}. Inserted into - * the ID tag of the comment - * - * @return string - */ - public function Permalink() { - $prefix = $this->getOption('comment_permalink_prefix'); - return $prefix . $this->ID; - } - - /** - * Translate the form field labels for the CMS administration - * - * @param boolean $includerelations - * - * @return array - */ - public function fieldLabels($includerelations = true) { - $labels = parent::fieldLabels($includerelations); - - $labels['Name'] = _t('Comment.NAME', 'Author Name'); - $labels['Comment'] = _t('Comment.COMMENT', 'Comment'); - $labels['Email'] = _t('Comment.EMAIL', 'Email'); - $labels['URL'] = _t('Comment.URL', 'URL'); - $labels['IsSpam'] = _t('Comment.ISSPAM', 'Spam?'); - $labels['Moderated'] = _t('Comment.MODERATED', 'Moderated?'); - $labels['ParentTitle'] = _t('Comment.PARENTTITLE', 'Parent'); - $labels['Created'] = _t('Comment.CREATED', 'Date posted'); - - return $labels; - } - - /** - * Get the commenting option - * - * @param string $key - * - * @return mixed Result if the setting is available, or null otherwise - */ - public function getOption($key) { - // If possible use the current record - $record = $this->getParent(); - - if(!$record && $this->BaseClass) { - // Otherwise a singleton of that record - $record = singleton($this->BaseClass); - } - else if(!$record) { - // Otherwise just use the default options - $record = singleton('CommentsExtension'); - } - - return ($record->hasMethod('getCommentsOption')) ? $record->getCommentsOption($key) : null; - } - - /** - * Returns the parent {@link DataObject} this comment is attached too - * - * @return DataObject - */ - public function getParent() { - return $this->BaseClass && $this->ParentID - ? DataObject::get_by_id($this->BaseClass, $this->ParentID, true) - : null; - } - - - /** - * Returns a string to help identify the parent of the comment - * - * @return string - */ - public function getParentTitle() { - if($parent = $this->getParent()) { - return $parent->Title ?: ($parent->ClassName . ' #' . $parent->ID); - } - } - - /** - * Comment-parent classnames obviously vary, return the parent classname - * - * @return string - */ - public function getParentClassName() { - return $this->BaseClass; - } - - public function castingHelper($field) { - // Safely escape the comment - if($field === 'EscapedComment') { - return $this->AllowHtml ? 'HTMLText' : 'Text'; - } - return parent::castingHelper($field); - } - - /** - * Content to be safely escaped on the frontend - * - * @return string - */ - public function getEscapedComment() { - return $this->Comment; - } - - /** - * Return whether this comment is a preview (has not been written to the db) - * - * @return boolean - */ - public function isPreview() { - return !$this->exists(); - } - - /** - * @todo needs to compare to the new {@link Commenting} configuration API - * - * @param Member $member - * - * @return bool - */ - public function canCreate($member = null) { - return false; - } - - /** - * Checks for association with a page, and {@link SiteTree->ProvidePermission} - * flag being set to true. - * - * @param Member $member - * - * @return Boolean - */ - public function canView($member = null) { - $member = $this->getMember($member); - - $extended = $this->extendedCan('canView', $member); - if($extended !== null) { - return $extended; - } - - if(Permission::checkMember($member, 'CMS_ACCESS_CommentAdmin')) { - return true; - } - - if($parent = $this->getParent()) { - return $parent->canView($member) - && $parent->has_extension('CommentsExtension') - && $parent->CommentsEnabled; - } - - return false; - } - - /** - * Checks if the comment can be edited. - * - * @param null|int|Member $member - * - * @return Boolean - */ - public function canEdit($member = null) { - $member = $this->getMember($member); - - if(!$member) { - return false; - } - - $extended = $this->extendedCan('canEdit', $member); - if($extended !== null) { - return $extended; - } - - if(Permission::checkMember($member, 'CMS_ACCESS_CommentAdmin')) { - return true; - } - - if($parent = $this->getParent()) { - return $parent->canEdit($member); - } - - return false; - } - - /** - * Checks if the comment can be deleted. - * - * @param null|int|Member $member - * - * @return Boolean - */ - public function canDelete($member = null) { - $member = $this->getMember($member); - - if(!$member) { - return false; - } - - $extended = $this->extendedCan('canDelete', $member); - if($extended !== null) { - return $extended; - } - - return $this->canEdit($member); - } - - /** - * Resolves Member object. - * - * @param Member|int|null $member - * @return Member|null - */ - protected function getMember($member = null) { - if(!$member) { - $member = Member::currentUser(); - } - - if(is_numeric($member)) { - $member = DataObject::get_by_id('Member', $member, true); - } - - return $member; - } - - /** - * Return the authors name for the comment - * - * @return string - */ - public function getAuthorName() { - if($this->Name) { - return $this->Name; - } else if($author = $this->Author()) { - return $author->getName(); - } - } - - /** - * Generate a secure admin-action link authorised for the specified member - * - * @param string $action An action on CommentingController to link to - * @param Member $member The member authorised to invoke this action - * - * @return string - */ - protected function actionLink($action, $member = null) { - if(!$member) $member = Member::currentUser(); - if(!$member) return false; - - $url = Controller::join_links( - Director::baseURL(), - 'CommentingController', - $action, - $this->ID - ); - - // Limit access for this user - $token = $this->getSecurityToken(); - return $token->addToUrl($url, $member); - } - - /** - * Link to delete this comment - * - * @param Member $member - * - * @return string - */ - public function DeleteLink($member = null) { - if($this->canDelete($member)) { - return $this->actionLink('delete', $member); - } - } - - /** - * Link to mark as spam - * - * @param Member $member - * - * @return string - */ - public function SpamLink($member = null) { - if($this->canEdit($member) && !$this->IsSpam) { - return $this->actionLink('spam', $member); - } - } - - /** - * Link to mark as not-spam (ham) - * - * @param Member $member - * - * @return string - */ - public function HamLink($member = null) { - if($this->canEdit($member) && $this->IsSpam) { - return $this->actionLink('ham', $member); - } - } - - /** - * Link to approve this comment - * - * @param Member $member - * - * @return string - */ - public function ApproveLink($member = null) { - if($this->canEdit($member) && !$this->Moderated) { - return $this->actionLink('approve', $member); - } - } - - /** - * Mark this comment as spam - */ - public function markSpam() { - $this->IsSpam = true; - $this->Moderated = true; - $this->write(); - $this->extend('afterMarkSpam'); - } - - /** - * Mark this comment as approved - */ - public function markApproved() { - $this->IsSpam = false; - $this->Moderated = true; - $this->write(); - $this->extend('afterMarkApproved'); - } - - /** - * Mark this comment as unapproved - */ - public function markUnapproved() { - $this->Moderated = false; - $this->write(); - $this->extend('afterMarkUnapproved'); - } - - /** - * @return string - */ - public function SpamClass() { - if($this->IsSpam) { - return 'spam'; - } else if(!$this->Moderated) { - return 'unmoderated'; - } else { - return 'notspam'; - } - } - - /** - * @return string - */ - public function getTitle() { - $title = sprintf(_t('Comment.COMMENTBY', 'Comment by %s', 'Name'), $this->getAuthorName()); - - if($parent = $this->getParent()) { - if($parent->Title) { - $title .= sprintf(' %s %s', _t('Comment.ON', 'on'), $parent->Title); - } - } - - return $title; - } - - /* - * Modify the default fields shown to the user - */ - public function getCMSFields() { - $commentField = $this->AllowHtml ? 'HtmlEditorField' : 'TextareaField'; - $fields = new FieldList( - $this - ->obj('Created') - ->scaffoldFormField($this->fieldLabel('Created')) - ->performReadonlyTransformation(), - TextField::create('Name', $this->fieldLabel('AuthorName')), - $commentField::create('Comment', $this->fieldLabel('Comment')), - EmailField::create('Email', $this->fieldLabel('Email')), - TextField::create('URL', $this->fieldLabel('URL')), - FieldGroup::create(array( - CheckboxField::create('Moderated', $this->fieldLabel('Moderated')), - CheckboxField::create('IsSpam', $this->fieldLabel('IsSpam')), - )) - ->setTitle('Options') - ->setDescription(_t( - 'Comment.OPTION_DESCRIPTION', - 'Unmoderated and spam comments will not be displayed until approved' - )) - ); - - // Show member name if given - if(($author = $this->Author()) && $author->exists()) { - $fields->insertAfter( - TextField::create('AuthorMember', $this->fieldLabel('Author'), $author->Title) - ->performReadonlyTransformation(), - 'Name' - ); - } - - // Show parent comment if given - if(($parent = $this->ParentComment()) && $parent->exists()) { - $fields->push(new HeaderField( - 'ParentComment_Title', - _t('Comment.ParentComment_Title', 'This comment is a reply to the below') - )); - // Created date +class Comment extends DataObject +{ + + /** + * @var array + */ + private static $db = array( + 'Name' => 'Varchar(200)', + 'Comment' => 'Text', + 'Email' => 'Varchar(200)', + 'URL' => 'Varchar(255)', + 'BaseClass' => 'Varchar(200)', + 'Moderated' => 'Boolean(0)', + 'IsSpam' => 'Boolean(0)', + 'ParentID' => 'Int', + 'AllowHtml' => 'Boolean', + 'SecretToken' => 'Varchar(255)', + 'Depth' => 'Int', + ); + + private static $has_one = array( + "Author" => "Member", + "ParentComment" => "Comment", + ); + + private static $has_many = array( + "ChildComments" => "Comment" + ); + + private static $default_sort = '"Created" DESC'; + + private static $defaults = array( + 'Moderated' => 0, + 'IsSpam' => 0, + ); + + private static $casting = array( + 'Title' => 'Varchar', + 'ParentTitle' => 'Varchar', + 'ParentClassName' => 'Varchar', + 'AuthorName' => 'Varchar', + 'RSSName' => 'Varchar', + 'DeleteLink' => 'Varchar', + 'SpamLink' => 'Varchar', + 'HamLink' => 'Varchar', + 'ApproveLink' => 'Varchar', + 'Permalink' => 'Varchar', + ); + + private static $searchable_fields = array( + 'Name', + 'Email', + 'Comment', + 'Created', + 'BaseClass', + ); + + private static $summary_fields = array( + 'Name' => 'Submitted By', + 'Email' => 'Email', + 'Comment.LimitWordCount' => 'Comment', + 'Created' => 'Date Posted', + 'ParentTitle' => 'Post', + 'IsSpam' => 'Is Spam', + ); + + private static $field_labels = array( + 'Author' => 'Author Member', + ); + + public function onBeforeWrite() + { + parent::onBeforeWrite(); + + // Sanitize HTML, because its expected to be passed to the template unescaped later + if ($this->AllowHtml) { + $this->Comment = $this->purifyHtml($this->Comment); + } + + // Check comment depth + $this->updateDepth(); + } + + public function onBeforeDelete() + { + parent::onBeforeDelete(); + + // Delete all children + foreach ($this->ChildComments() as $comment) { + $comment->delete(); + } + } + + /** + * @return Comment_SecurityToken + */ + public function getSecurityToken() + { + return Injector::inst()->createWithArgs('Comment_SecurityToken', array($this)); + } + + /** + * Migrates the old {@link PageComment} objects to {@link Comment} + */ + public function requireDefaultRecords() + { + parent::requireDefaultRecords(); + + if (DB::getConn()->hasTable('PageComment')) { + $comments = DB::query('SELECT * FROM "PageComment"'); + + if ($comments) { + while ($pageComment = $comments->nextRecord()) { + // create a new comment from the older page comment + $comment = new Comment(); + $comment->update($pageComment); + + // set the variables which have changed + $comment->BaseClass = 'SiteTree'; + $comment->URL = (isset($pageComment['CommenterURL'])) ? $pageComment['CommenterURL'] : ''; + if ((int) $pageComment['NeedsModeration'] == 0) { + $comment->Moderated = true; + } + + $comment->write(); + } + } + + DB::alteration_message('Migrated PageComment to Comment', 'changed'); + DB::getConn()->dontRequireTable('PageComment'); + } + } + + /** + * Return a link to this comment + * + * @param string $action + * + * @return string link to this comment. + */ + public function Link($action = '') + { + if ($parent = $this->getParent()) { + return $parent->Link($action) . '#' . $this->Permalink(); + } + } + + /** + * Returns the permalink for this {@link Comment}. Inserted into + * the ID tag of the comment + * + * @return string + */ + public function Permalink() + { + $prefix = $this->getOption('comment_permalink_prefix'); + return $prefix . $this->ID; + } + + /** + * Translate the form field labels for the CMS administration + * + * @param boolean $includerelations + * + * @return array + */ + public function fieldLabels($includerelations = true) + { + $labels = parent::fieldLabels($includerelations); + + $labels['Name'] = _t('Comment.NAME', 'Author Name'); + $labels['Comment'] = _t('Comment.COMMENT', 'Comment'); + $labels['Email'] = _t('Comment.EMAIL', 'Email'); + $labels['URL'] = _t('Comment.URL', 'URL'); + $labels['IsSpam'] = _t('Comment.ISSPAM', 'Spam?'); + $labels['Moderated'] = _t('Comment.MODERATED', 'Moderated?'); + $labels['ParentTitle'] = _t('Comment.PARENTTITLE', 'Parent'); + $labels['Created'] = _t('Comment.CREATED', 'Date posted'); + + return $labels; + } + + /** + * Get the commenting option + * + * @param string $key + * + * @return mixed Result if the setting is available, or null otherwise + */ + public function getOption($key) + { + // If possible use the current record + $record = $this->getParent(); + + if (!$record && $this->BaseClass) { + // Otherwise a singleton of that record + $record = singleton($this->BaseClass); + } elseif (!$record) { + // Otherwise just use the default options + $record = singleton('CommentsExtension'); + } + + return ($record->hasMethod('getCommentsOption')) ? $record->getCommentsOption($key) : null; + } + + /** + * Returns the parent {@link DataObject} this comment is attached too + * + * @return DataObject + */ + public function getParent() + { + return $this->BaseClass && $this->ParentID + ? DataObject::get_by_id($this->BaseClass, $this->ParentID, true) + : null; + } + + + /** + * Returns a string to help identify the parent of the comment + * + * @return string + */ + public function getParentTitle() + { + if ($parent = $this->getParent()) { + return $parent->Title ?: ($parent->ClassName . ' #' . $parent->ID); + } + } + + /** + * Comment-parent classnames obviously vary, return the parent classname + * + * @return string + */ + public function getParentClassName() + { + return $this->BaseClass; + } + + public function castingHelper($field) + { + // Safely escape the comment + if ($field === 'EscapedComment') { + return $this->AllowHtml ? 'HTMLText' : 'Text'; + } + return parent::castingHelper($field); + } + + /** + * Content to be safely escaped on the frontend + * + * @return string + */ + public function getEscapedComment() + { + return $this->Comment; + } + + /** + * Return whether this comment is a preview (has not been written to the db) + * + * @return boolean + */ + public function isPreview() + { + return !$this->exists(); + } + + /** + * @todo needs to compare to the new {@link Commenting} configuration API + * + * @param Member $member + * + * @return bool + */ + public function canCreate($member = null) + { + return false; + } + + /** + * Checks for association with a page, and {@link SiteTree->ProvidePermission} + * flag being set to true. + * + * @param Member $member + * + * @return Boolean + */ + public function canView($member = null) + { + $member = $this->getMember($member); + + $extended = $this->extendedCan('canView', $member); + if ($extended !== null) { + return $extended; + } + + if (Permission::checkMember($member, 'CMS_ACCESS_CommentAdmin')) { + return true; + } + + if ($parent = $this->getParent()) { + return $parent->canView($member) + && $parent->has_extension('CommentsExtension') + && $parent->CommentsEnabled; + } + + return false; + } + + /** + * Checks if the comment can be edited. + * + * @param null|int|Member $member + * + * @return Boolean + */ + public function canEdit($member = null) + { + $member = $this->getMember($member); + + if (!$member) { + return false; + } + + $extended = $this->extendedCan('canEdit', $member); + if ($extended !== null) { + return $extended; + } + + if (Permission::checkMember($member, 'CMS_ACCESS_CommentAdmin')) { + return true; + } + + if ($parent = $this->getParent()) { + return $parent->canEdit($member); + } + + return false; + } + + /** + * Checks if the comment can be deleted. + * + * @param null|int|Member $member + * + * @return Boolean + */ + public function canDelete($member = null) + { + $member = $this->getMember($member); + + if (!$member) { + return false; + } + + $extended = $this->extendedCan('canDelete', $member); + if ($extended !== null) { + return $extended; + } + + return $this->canEdit($member); + } + + /** + * Resolves Member object. + * + * @param Member|int|null $member + * @return Member|null + */ + protected function getMember($member = null) + { + if (!$member) { + $member = Member::currentUser(); + } + + if (is_numeric($member)) { + $member = DataObject::get_by_id('Member', $member, true); + } + + return $member; + } + + /** + * Return the authors name for the comment + * + * @return string + */ + public function getAuthorName() + { + if ($this->Name) { + return $this->Name; + } elseif ($author = $this->Author()) { + return $author->getName(); + } + } + + /** + * Generate a secure admin-action link authorised for the specified member + * + * @param string $action An action on CommentingController to link to + * @param Member $member The member authorised to invoke this action + * + * @return string + */ + protected function actionLink($action, $member = null) + { + if (!$member) { + $member = Member::currentUser(); + } + if (!$member) { + return false; + } + + $url = Controller::join_links( + Director::baseURL(), + 'CommentingController', + $action, + $this->ID + ); + + // Limit access for this user + $token = $this->getSecurityToken(); + return $token->addToUrl($url, $member); + } + + /** + * Link to delete this comment + * + * @param Member $member + * + * @return string + */ + public function DeleteLink($member = null) + { + if ($this->canDelete($member)) { + return $this->actionLink('delete', $member); + } + } + + /** + * Link to mark as spam + * + * @param Member $member + * + * @return string + */ + public function SpamLink($member = null) + { + if ($this->canEdit($member) && !$this->IsSpam) { + return $this->actionLink('spam', $member); + } + } + + /** + * Link to mark as not-spam (ham) + * + * @param Member $member + * + * @return string + */ + public function HamLink($member = null) + { + if ($this->canEdit($member) && $this->IsSpam) { + return $this->actionLink('ham', $member); + } + } + + /** + * Link to approve this comment + * + * @param Member $member + * + * @return string + */ + public function ApproveLink($member = null) + { + if ($this->canEdit($member) && !$this->Moderated) { + return $this->actionLink('approve', $member); + } + } + + /** + * Mark this comment as spam + */ + public function markSpam() + { + $this->IsSpam = true; + $this->Moderated = true; + $this->write(); + $this->extend('afterMarkSpam'); + } + + /** + * Mark this comment as approved + */ + public function markApproved() + { + $this->IsSpam = false; + $this->Moderated = true; + $this->write(); + $this->extend('afterMarkApproved'); + } + + /** + * Mark this comment as unapproved + */ + public function markUnapproved() + { + $this->Moderated = false; + $this->write(); + $this->extend('afterMarkUnapproved'); + } + + /** + * @return string + */ + public function SpamClass() + { + if ($this->IsSpam) { + return 'spam'; + } elseif (!$this->Moderated) { + return 'unmoderated'; + } else { + return 'notspam'; + } + } + + /** + * @return string + */ + public function getTitle() + { + $title = sprintf(_t('Comment.COMMENTBY', 'Comment by %s', 'Name'), $this->getAuthorName()); + + if ($parent = $this->getParent()) { + if ($parent->Title) { + $title .= sprintf(' %s %s', _t('Comment.ON', 'on'), $parent->Title); + } + } + + return $title; + } + + /* + * Modify the default fields shown to the user + */ + public function getCMSFields() + { + $commentField = $this->AllowHtml ? 'HtmlEditorField' : 'TextareaField'; + $fields = new FieldList( + $this + ->obj('Created') + ->scaffoldFormField($this->fieldLabel('Created')) + ->performReadonlyTransformation(), + TextField::create('Name', $this->fieldLabel('AuthorName')), + $commentField::create('Comment', $this->fieldLabel('Comment')), + EmailField::create('Email', $this->fieldLabel('Email')), + TextField::create('URL', $this->fieldLabel('URL')), + FieldGroup::create(array( + CheckboxField::create('Moderated', $this->fieldLabel('Moderated')), + CheckboxField::create('IsSpam', $this->fieldLabel('IsSpam')), + )) + ->setTitle('Options') + ->setDescription(_t( + 'Comment.OPTION_DESCRIPTION', + 'Unmoderated and spam comments will not be displayed until approved' + )) + ); + + // Show member name if given + if (($author = $this->Author()) && $author->exists()) { + $fields->insertAfter( + TextField::create('AuthorMember', $this->fieldLabel('Author'), $author->Title) + ->performReadonlyTransformation(), + 'Name' + ); + } + + // Show parent comment if given + if (($parent = $this->ParentComment()) && $parent->exists()) { + $fields->push(new HeaderField( + 'ParentComment_Title', + _t('Comment.ParentComment_Title', 'This comment is a reply to the below') + )); + // Created date // FIXME - the method setName in DatetimeField is not chainable, hence // the lack of chaining here $createdField = $parent @@ -580,46 +617,48 @@ class Comment extends DataObject { $createdField->performReadonlyTransformation(); $fields->push($createdField); - // Name (could be member or string value) - $fields->push( - $parent - ->obj('AuthorName') - ->scaffoldFormField($parent->fieldLabel('AuthorName')) - ->setName('ParentComment_AuthorName') - ->setValue($parent->getAuthorName()) - ->performReadonlyTransformation() - ); + // Name (could be member or string value) + $fields->push( + $parent + ->obj('AuthorName') + ->scaffoldFormField($parent->fieldLabel('AuthorName')) + ->setName('ParentComment_AuthorName') + ->setValue($parent->getAuthorName()) + ->performReadonlyTransformation() + ); - // Comment body - $fields->push( - $parent - ->obj('EscapedComment') - ->scaffoldFormField($parent->fieldLabel('Comment')) - ->setName('ParentComment_EscapedComment') - ->setValue($parent->Comment) - ->performReadonlyTransformation() - ); - } + // Comment body + $fields->push( + $parent + ->obj('EscapedComment') + ->scaffoldFormField($parent->fieldLabel('Comment')) + ->setName('ParentComment_EscapedComment') + ->setValue($parent->Comment) + ->performReadonlyTransformation() + ); + } - $this->extend('updateCMSFields', $fields); - return $fields; - } + $this->extend('updateCMSFields', $fields); + return $fields; + } - /** - * @param String $dirtyHtml - * - * @return String - */ - public function purifyHtml($dirtyHtml) { - $purifier = $this->getHtmlPurifierService(); - return $purifier->purify($dirtyHtml); - } + /** + * @param String $dirtyHtml + * + * @return String + */ + public function purifyHtml($dirtyHtml) + { + $purifier = $this->getHtmlPurifierService(); + return $purifier->purify($dirtyHtml); + } - /** - * @return HTMLPurifier (or anything with a "purify()" method) - */ - public function getHtmlPurifierService() { - $config = HTMLPurifier_Config::createDefault(); + /** + * @return HTMLPurifier (or anything with a "purify()" method) + */ + public function getHtmlPurifierService() + { + $config = HTMLPurifier_Config::createDefault(); $allowedElements = $this->getOption('html_allowed_elements'); $config->set('HTML.AllowedElements', $allowedElements); @@ -628,256 +667,274 @@ class Comment extends DataObject { $config->set('AutoFormat.AutoParagraph', true); } - $config->set('AutoFormat.Linkify', true); - $config->set('URI.DisableExternalResources', true); - $config->set('Cache.SerializerPath', getTempFolder()); - return new HTMLPurifier($config); - } + $config->set('AutoFormat.Linkify', true); + $config->set('URI.DisableExternalResources', true); + $config->set('Cache.SerializerPath', getTempFolder()); + return new HTMLPurifier($config); + } - /** - * Calculate the Gravatar link from the email address - * - * @return string - */ - public function Gravatar() { - $gravatar = ''; - $use_gravatar = $this->getOption('use_gravatar'); - if($use_gravatar) { - $gravatar = 'http://www.gravatar.com/avatar/' . md5(strtolower(trim($this->Email))); - $gravatarsize = $this->getOption('gravatar_size'); - $gravatardefault = $this->getOption('gravatar_default'); - $gravatarrating = $this->getOption('gravatar_rating'); - $gravatar .= '?s=' . $gravatarsize . '&d=' . $gravatardefault . '&r=' . $gravatarrating; - } + /** + * Calculate the Gravatar link from the email address + * + * @return string + */ + public function Gravatar() + { + $gravatar = ''; + $use_gravatar = $this->getOption('use_gravatar'); + if ($use_gravatar) { + $gravatar = 'http://www.gravatar.com/avatar/' . md5(strtolower(trim($this->Email))); + $gravatarsize = $this->getOption('gravatar_size'); + $gravatardefault = $this->getOption('gravatar_default'); + $gravatarrating = $this->getOption('gravatar_rating'); + $gravatar .= '?s=' . $gravatarsize . '&d=' . $gravatardefault . '&r=' . $gravatarrating; + } - return $gravatar; - } + return $gravatar; + } - /** - * Determine if replies are enabled for this instance - * - * @return boolean - */ - public function getRepliesEnabled() { - // Check reply option - if(!$this->getOption('nested_comments')) { - return false; - } + /** + * Determine if replies are enabled for this instance + * + * @return boolean + */ + public function getRepliesEnabled() + { + // Check reply option + if (!$this->getOption('nested_comments')) { + return false; + } - // Check if depth is limited - $maxLevel = $this->getOption('nested_depth'); - $notSpam = ($this->SpamClass() == 'notspam'); - return $notSpam && (!$maxLevel || $this->Depth < $maxLevel); - } + // Check if depth is limited + $maxLevel = $this->getOption('nested_depth'); + $notSpam = ($this->SpamClass() == 'notspam'); + return $notSpam && (!$maxLevel || $this->Depth < $maxLevel); + } - /** - * Returns the list of all replies - * - * @return SS_List - */ - public function AllReplies() { - // No replies if disabled - if(!$this->getRepliesEnabled()) { - return new ArrayList(); - } + /** + * Returns the list of all replies + * + * @return SS_List + */ + public function AllReplies() + { + // No replies if disabled + if (!$this->getRepliesEnabled()) { + return new ArrayList(); + } - // Get all non-spam comments - $order = $this->getOption('order_replies_by') - ?: $this->getOption('order_comments_by'); - $list = $this - ->ChildComments() - ->sort($order); + // Get all non-spam comments + $order = $this->getOption('order_replies_by') + ?: $this->getOption('order_comments_by'); + $list = $this + ->ChildComments() + ->sort($order); - $this->extend('updateAllReplies', $list); - return $list; - } + $this->extend('updateAllReplies', $list); + return $list; + } - /** - * Returns the list of replies, with spam and unmoderated items excluded, for use in the frontend - * - * @return SS_List - */ - public function Replies() { - // No replies if disabled - if(!$this->getRepliesEnabled()) { - return new ArrayList(); - } - $list = $this->AllReplies(); + /** + * Returns the list of replies, with spam and unmoderated items excluded, for use in the frontend + * + * @return SS_List + */ + public function Replies() + { + // No replies if disabled + if (!$this->getRepliesEnabled()) { + return new ArrayList(); + } + $list = $this->AllReplies(); - // Filter spam comments for non-administrators if configured - $parent = $this->getParent(); - $showSpam = $this->getOption('frontend_spam') && $parent && $parent->canModerateComments(); - if(!$showSpam) { - $list = $list->filter('IsSpam', 0); - } + // Filter spam comments for non-administrators if configured + $parent = $this->getParent(); + $showSpam = $this->getOption('frontend_spam') && $parent && $parent->canModerateComments(); + if (!$showSpam) { + $list = $list->filter('IsSpam', 0); + } - // Filter un-moderated comments for non-administrators if moderation is enabled - $showUnmoderated = $parent && ( - ($parent->ModerationRequired === 'None') - || ($this->getOption('frontend_moderation') && $parent->canModerateComments()) - ); - if (!$showUnmoderated) { - $list = $list->filter('Moderated', 1); - } + // Filter un-moderated comments for non-administrators if moderation is enabled + $showUnmoderated = $parent && ( + ($parent->ModerationRequired === 'None') + || ($this->getOption('frontend_moderation') && $parent->canModerateComments()) + ); + if (!$showUnmoderated) { + $list = $list->filter('Moderated', 1); + } - $this->extend('updateReplies', $list); - return $list; - } + $this->extend('updateReplies', $list); + return $list; + } - /** - * Returns the list of replies paged, with spam and unmoderated items excluded, for use in the frontend - * - * @return PaginatedList - */ - public function PagedReplies() { - $list = $this->Replies(); + /** + * Returns the list of replies paged, with spam and unmoderated items excluded, for use in the frontend + * + * @return PaginatedList + */ + public function PagedReplies() + { + $list = $this->Replies(); - // Add pagination - $list = new PaginatedList($list, Controller::curr()->getRequest()); - $list->setPaginationGetVar('repliesstart'.$this->ID); - $list->setPageLength($this->getOption('comments_per_page')); + // Add pagination + $list = new PaginatedList($list, Controller::curr()->getRequest()); + $list->setPaginationGetVar('repliesstart'.$this->ID); + $list->setPageLength($this->getOption('comments_per_page')); - $this->extend('updatePagedReplies', $list); - return $list; - } + $this->extend('updatePagedReplies', $list); + return $list; + } - /** - * Generate a reply form for this comment - * - * @return Form - */ - public function ReplyForm() { - // Ensure replies are enabled - if(!$this->getRepliesEnabled()) { - return null; - } + /** + * Generate a reply form for this comment + * + * @return Form + */ + public function ReplyForm() + { + // Ensure replies are enabled + if (!$this->getRepliesEnabled()) { + return null; + } - // Check parent is available - $parent = $this->getParent(); - if(!$parent || !$parent->exists()) { - return null; - } + // Check parent is available + $parent = $this->getParent(); + if (!$parent || !$parent->exists()) { + return null; + } - // Build reply controller - $controller = CommentingController::create(); - $controller->setOwnerRecord($parent); - $controller->setBaseClass($parent->ClassName); - $controller->setOwnerController(Controller::curr()); + // Build reply controller + $controller = CommentingController::create(); + $controller->setOwnerRecord($parent); + $controller->setBaseClass($parent->ClassName); + $controller->setOwnerController(Controller::curr()); - return $controller->ReplyForm($this); - } + return $controller->ReplyForm($this); + } - /** - * Refresh of this comment in the hierarchy - */ - public function updateDepth() { - $parent = $this->ParentComment(); - if($parent && $parent->exists()) { - $parent->updateDepth(); - $this->Depth = $parent->Depth + 1; - } else { - $this->Depth = 1; - } - } + /** + * Refresh of this comment in the hierarchy + */ + public function updateDepth() + { + $parent = $this->ParentComment(); + if ($parent && $parent->exists()) { + $parent->updateDepth(); + $this->Depth = $parent->Depth + 1; + } else { + $this->Depth = 1; + } + } } /** * Provides the ability to generate cryptographically secure tokens for comment moderation */ -class Comment_SecurityToken { +class Comment_SecurityToken +{ - private $secret = null; + private $secret = null; - /** - * @param Comment $comment Comment to generate this token for - */ - public function __construct($comment) { - if(!$comment->SecretToken) { - $comment->SecretToken = $this->generate(); - $comment->write(); - } - $this->secret = $comment->SecretToken; - } + /** + * @param Comment $comment Comment to generate this token for + */ + public function __construct($comment) + { + if (!$comment->SecretToken) { + $comment->SecretToken = $this->generate(); + $comment->write(); + } + $this->secret = $comment->SecretToken; + } - /** - * Generate the token for the given salt and current secret - * - * @param string $salt - * - * @return string - */ - protected function getToken($salt) { - return hash_pbkdf2('sha256', $this->secret, $salt, 1000, 30); - } + /** + * Generate the token for the given salt and current secret + * + * @param string $salt + * + * @return string + */ + protected function getToken($salt) + { + return hash_pbkdf2('sha256', $this->secret, $salt, 1000, 30); + } - /** - * Get the member-specific salt. - * - * The reason for making the salt specific to a user is that it cannot be "passed in" via a - * querystring, requiring the same user to be present at both the link generation and the - * controller action. - * - * @param string $salt Single use salt - * @param Member $member Member object - * - * @return string Generated salt specific to this member - */ - protected function memberSalt($salt, $member) { - // Fallback to salting with ID in case the member has not one set - return $salt . ($member->Salt ?: $member->ID); - } + /** + * Get the member-specific salt. + * + * The reason for making the salt specific to a user is that it cannot be "passed in" via a + * querystring, requiring the same user to be present at both the link generation and the + * controller action. + * + * @param string $salt Single use salt + * @param Member $member Member object + * + * @return string Generated salt specific to this member + */ + protected function memberSalt($salt, $member) + { + // Fallback to salting with ID in case the member has not one set + return $salt . ($member->Salt ?: $member->ID); + } - /** - * @param string $url Comment action URL - * @param Member $member Member to restrict access to this action to - * - * @return string - */ - public function addToUrl($url, $member) { - $salt = $this->generate(15); // New random salt; Will be passed into url - // Generate salt specific to this member - $memberSalt = $this->memberSalt($salt, $member); - $token = $this->getToken($memberSalt); - return Controller::join_links( - $url, - sprintf( - '?t=%s&s=%s', - urlencode($token), - urlencode($salt) - ) - ); - } + /** + * @param string $url Comment action URL + * @param Member $member Member to restrict access to this action to + * + * @return string + */ + public function addToUrl($url, $member) + { + $salt = $this->generate(15); // New random salt; Will be passed into url + // Generate salt specific to this member + $memberSalt = $this->memberSalt($salt, $member); + $token = $this->getToken($memberSalt); + return Controller::join_links( + $url, + sprintf( + '?t=%s&s=%s', + urlencode($token), + urlencode($salt) + ) + ); + } - /** - * @param SS_HTTPRequest $request - * - * @return boolean - */ - public function checkRequest($request) { - $member = Member::currentUser(); - if(!$member) return false; + /** + * @param SS_HTTPRequest $request + * + * @return boolean + */ + public function checkRequest($request) + { + $member = Member::currentUser(); + if (!$member) { + return false; + } - $salt = $request->getVar('s'); - $memberSalt = $this->memberSalt($salt, $member); - $token = $this->getToken($memberSalt); + $salt = $request->getVar('s'); + $memberSalt = $this->memberSalt($salt, $member); + $token = $this->getToken($memberSalt); - // Ensure tokens match - return $token === $request->getVar('t'); - } + // Ensure tokens match + return $token === $request->getVar('t'); + } - /** - * Generates new random key - * - * @param integer $length - * - * @return string - */ - protected function generate($length = null) { - $generator = new RandomGenerator(); - $result = $generator->randomToken('sha256'); - if($length !== null) return substr($result, 0, $length); - return $result; - } + /** + * Generates new random key + * + * @param integer $length + * + * @return string + */ + protected function generate($length = null) + { + $generator = new RandomGenerator(); + $result = $generator->randomToken('sha256'); + if ($length !== null) { + return substr($result, 0, $length); + } + return $result; + } } diff --git a/code/model/CommentList.php b/code/model/CommentList.php index 3296b13..ecba2e8 100644 --- a/code/model/CommentList.php +++ b/code/model/CommentList.php @@ -7,85 +7,92 @@ * * @author dmooyman */ -class CommentList extends HasManyList { +class CommentList extends HasManyList +{ - /** - * Retrieve the name of the class this relation is filtered by - * - * @return string - */ - public function getForeignClass() { - return $this->dataQuery->getQueryParam('Foreign.Class'); - } + /** + * Retrieve the name of the class this relation is filtered by + * + * @return string + */ + public function getForeignClass() + { + return $this->dataQuery->getQueryParam('Foreign.Class'); + } - public function __construct($parentClassName) { - parent::__construct('Comment', 'ParentID'); + public function __construct($parentClassName) + { + parent::__construct('Comment', 'ParentID'); - // Ensure underlying DataQuery globally references the class filter - $this->dataQuery->setQueryParam('Foreign.Class', $parentClassName); + // Ensure underlying DataQuery globally references the class filter + $this->dataQuery->setQueryParam('Foreign.Class', $parentClassName); - // For queries with multiple foreign IDs (such as that generated by - // DataList::relation) the filter must be generalised to filter by subclasses - $classNames = Convert::raw2sql(ClassInfo::subclassesFor($parentClassName)); - $this->dataQuery->where(sprintf( - "\"BaseClass\" IN ('%s')", implode("', '", $classNames) - )); - } + // For queries with multiple foreign IDs (such as that generated by + // DataList::relation) the filter must be generalised to filter by subclasses + $classNames = Convert::raw2sql(ClassInfo::subclassesFor($parentClassName)); + $this->dataQuery->where(sprintf( + "\"BaseClass\" IN ('%s')", implode("', '", $classNames) + )); + } - /** - * Adds the item to this relation. - * - * @param Comment $item The comment to be added - */ - public function add($item) { - // Check item given - if(is_numeric($item)) { - $item = Comment::get()->byID($item); - } - if(!($item instanceof Comment)) { - throw new InvalidArgumentException("CommentList::add() expecting a Comment object, or ID value"); - } - - // Validate foreignID - $foreignID = $this->getForeignID(); - if(!$foreignID || is_array($foreignID)) { - throw new InvalidArgumentException("CommentList::add() can't be called until a single foreign ID is set"); - } + /** + * Adds the item to this relation. + * + * @param Comment $item The comment to be added + */ + public function add($item) + { + // Check item given + if (is_numeric($item)) { + $item = Comment::get()->byID($item); + } + if (!($item instanceof Comment)) { + throw new InvalidArgumentException("CommentList::add() expecting a Comment object, or ID value"); + } + + // Validate foreignID + $foreignID = $this->getForeignID(); + if (!$foreignID || is_array($foreignID)) { + throw new InvalidArgumentException("CommentList::add() can't be called until a single foreign ID is set"); + } - $item->ParentID = $foreignID; - $item->BaseClass = $this->getForeignClass(); - $item->write(); - } - /** - * Remove a Comment from this relation by clearing the foreign key. Does not actually delete the comment. - * - * @param Comment $item The Comment to be removed - */ - public function remove($item) { - // Check item given - if(is_numeric($item)) { - $item = Comment::get()->byID($item); - } - if(!($item instanceof Comment)) { - throw new InvalidArgumentException("CommentList::remove() expecting a Comment object, or ID", - E_USER_ERROR); - } - - // Don't remove item with unrelated class key - $foreignClass = $this->getForeignClass(); - $classNames = ClassInfo::subclassesFor($foreignClass); - if(!in_array($item->BaseClass, $classNames)) return; - - // Don't remove item which doesn't belong to this list - $foreignID = $this->getForeignID(); - if( empty($foreignID) - || (is_array($foreignID) && in_array($item->ParentID, $foreignID)) - || $foreignID == $item->ParentID - ) { - $item->ParentID = null; - $item->BaseClass = null; - $item->write(); - } - } + $item->ParentID = $foreignID; + $item->BaseClass = $this->getForeignClass(); + $item->write(); + } + /** + * Remove a Comment from this relation by clearing the foreign key. Does not actually delete the comment. + * + * @param Comment $item The Comment to be removed + */ + public function remove($item) + { + // Check item given + if (is_numeric($item)) { + $item = Comment::get()->byID($item); + } + if (!($item instanceof Comment)) { + throw new InvalidArgumentException("CommentList::remove() expecting a Comment object, or ID", + E_USER_ERROR); + } + + // Don't remove item with unrelated class key + $foreignClass = $this->getForeignClass(); + $classNames = ClassInfo::subclassesFor($foreignClass); + if (!in_array($item->BaseClass, $classNames)) { + return; + } + + // Don't remove item which doesn't belong to this list + $foreignID = $this->getForeignID(); + if (empty($foreignID) + || (is_array($foreignID) && in_array($item->ParentID, $foreignID)) + || $foreignID == $item->ParentID + ) { + $item->ParentID = null; + $item->BaseClass = null; + $item->write(); + } + } } diff --git a/tests/CommentAdminTest.php b/tests/CommentAdminTest.php index 2463f4b..2790f58 100644 --- a/tests/CommentAdminTest.php +++ b/tests/CommentAdminTest.php @@ -1,7 +1,9 @@ assertEquals($expected, $commentAdmin->providePermissions()); - } + } - public function testGetEditForm() { + public function testGetEditForm() + { $commentAdmin = new CommentAdmin(); $this->logInWithPermission('CMS_ACCESS_CommentAdmin'); - $form = $commentAdmin->getEditForm(); + $form = $commentAdmin->getEditForm(); $names = $this->getFormFieldNames($form); $expected = array( 'NewComments', @@ -38,12 +41,15 @@ class CommentAdminTest extends SapphireTest { ); $this->assertEquals($expected, $names); - if($member = Member::currentUser()) $member->logOut(); + if ($member = Member::currentUser()) { + $member->logOut(); + } $form = $commentAdmin->getEditForm(); - } + } - private function getFormFieldNames($form) { + private function getFormFieldNames($form) + { $result = array(); $fields = $form->Fields(); $tab = $fields->findOrMakeTab('Root'); @@ -53,5 +59,4 @@ class CommentAdminTest extends SapphireTest { } return $result; } - } diff --git a/tests/CommentListTest.php b/tests/CommentListTest.php index 19d01c4..64509f8 100644 --- a/tests/CommentListTest.php +++ b/tests/CommentListTest.php @@ -1,6 +1,7 @@ objFromFixture('CommentableItem', 'first'); // This is the class the Comments are related to $this->assertEquals('CommentableItem', $item->Comments()->getForeignClass()); - } + } - public function testAddNonComment() { + public function testAddNonComment() + { $item = $this->objFromFixture('CommentableItem', 'first'); $comments = $item->Comments(); $this->assertEquals(4, $comments->count()); @@ -63,7 +68,8 @@ class CommentListTest extends FunctionalTest { } } - public function testAddComment() { + public function testAddComment() + { $item = $this->objFromFixture('CommentableItem', 'first'); $firstComment = $this->objFromFixture('Comment', 'firstComA'); $comments = $item->Comments();//->sort('Created'); @@ -97,9 +103,10 @@ class CommentListTest extends FunctionalTest { ); $list = new CommentList('CommentableItem'); $list->add($newComment); - } + } - public function testRemoveComment() { + public function testRemoveComment() + { // remove by comment $item = $this->objFromFixture('CommentableItem', 'first'); $this->assertEquals(4, $item->Comments()->count()); @@ -114,7 +121,8 @@ class CommentListTest extends FunctionalTest { $this->assertEquals(2, $item->Comments()->count()); } - public function testRemoveNonComment() { + public function testRemoveNonComment() + { $item = $this->objFromFixture('CommentableItem', 'first'); $this->assertEquals(4, $item->Comments()->count()); $comments = $item->Comments(); @@ -134,5 +142,4 @@ class CommentListTest extends FunctionalTest { ); } } - } diff --git a/tests/CommentTestHelper.php b/tests/CommentTestHelper.php index 3a139d3..1717a56 100644 --- a/tests/CommentTestHelper.php +++ b/tests/CommentTestHelper.php @@ -1,17 +1,20 @@ findOrMakeTab($tabName); $fields = $tab->FieldList(); CommentTestHelper::assertFieldNames($context, $expected, $fields); } - public static function assertFieldNames($context, $expected, $fields) { + public static function assertFieldNames($context, $expected, $fields) + { $actual = array(); foreach ($fields as $field) { if (get_class($field) == 'FieldGroup') { diff --git a/tests/CommentingControllerTest.php b/tests/CommentingControllerTest.php index 9368f82..704bcb7 100644 --- a/tests/CommentingControllerTest.php +++ b/tests/CommentingControllerTest.php @@ -4,31 +4,35 @@ * @package comments * @subpackage tests */ -class CommentingControllerTest extends FunctionalTest { +class CommentingControllerTest extends FunctionalTest +{ - public static $fixture_file = 'CommentsTest.yml'; + public static $fixture_file = 'CommentsTest.yml'; - protected $extraDataObjects = array( - 'CommentableItem' - ); + protected $extraDataObjects = array( + 'CommentableItem' + ); - protected $securityEnabled; + protected $securityEnabled; - public function tearDown() { - if($this->securityEnabled) { - SecurityToken::enable(); - } else { - SecurityToken::disable(); - } - parent::tearDown(); - } + public function tearDown() + { + if ($this->securityEnabled) { + SecurityToken::enable(); + } else { + SecurityToken::disable(); + } + parent::tearDown(); + } - public function setUp() { - parent::setUp(); - $this->securityEnabled = SecurityToken::is_enabled(); - } + public function setUp() + { + parent::setUp(); + $this->securityEnabled = SecurityToken::is_enabled(); + } - public function testApprove() { + public function testApprove() + { SecurityToken::disable(); // mark a comment as spam then approve it @@ -49,10 +53,10 @@ class CommentingControllerTest extends FunctionalTest { // try and approve a non existent comment $response = $this->get('CommentingController/approve/100000'); $this->assertEquals(404, $response->getStatusCode()); - } - public function testSetGetOwnerController() { + public function testSetGetOwnerController() + { $commController = new CommentingController(); $commController->setOwnerController(Controller::curr()); $this->assertEquals(Controller::curr(), $commController->getOwnerController()); @@ -60,7 +64,8 @@ class CommentingControllerTest extends FunctionalTest { $this->assertNull($commController->getOwnerController()); } - public function testHam() { + public function testHam() + { SecurityToken::disable(); // mark a comment as spam then ham it @@ -81,10 +86,10 @@ class CommentingControllerTest extends FunctionalTest { // try and ham a non existent comment $response = $this->get('CommentingController/ham/100000'); $this->assertEquals(404, $response->getStatusCode()); - } - public function testSpam() { + public function testSpam() + { // mark a comment as approved then spam it $this->logInWithPermission('CMS_ACCESS_CommentAdmin'); $comment = $this->objFromFixture('Comment', 'firstComA'); @@ -103,10 +108,10 @@ class CommentingControllerTest extends FunctionalTest { // try and spam a non existent comment $response = $this->get('CommentingController/spam/100000'); $this->assertEquals(404, $response->getStatusCode()); - } - public function testRSS() { + public function testRSS() + { // Delete the newly added children of firstComA so as not to have to recalculate values below $this->objFromFixture('Comment', 'firstComAChild1')->delete(); $this->objFromFixture('Comment', 'firstComAChild2')->delete(); @@ -115,29 +120,29 @@ class CommentingControllerTest extends FunctionalTest { $item = $this->objFromFixture('CommentableItem', 'first'); - // comments sitewide - $response = $this->get('CommentingController/rss'); - $this->assertEquals(10, substr_count($response->getBody(), ""), "10 approved, non spam comments on page 1"); + // comments sitewide + $response = $this->get('CommentingController/rss'); + $this->assertEquals(10, substr_count($response->getBody(), ""), "10 approved, non spam comments on page 1"); - $response = $this->get('CommentingController/rss?start=10'); - $this->assertEquals(4, substr_count($response->getBody(), ""), "3 approved, non spam comments on page 2"); + $response = $this->get('CommentingController/rss?start=10'); + $this->assertEquals(4, substr_count($response->getBody(), ""), "3 approved, non spam comments on page 2"); - // all comments on a type - $response = $this->get('CommentingController/rss/CommentableItem'); - $this->assertEquals(10, substr_count($response->getBody(), "")); + // all comments on a type + $response = $this->get('CommentingController/rss/CommentableItem'); + $this->assertEquals(10, substr_count($response->getBody(), "")); - $response = $this->get('CommentingController/rss/CommentableItem?start=10'); - $this->assertEquals(4, substr_count($response->getBody(), ""), "3 approved, non spam comments on page 2"); + $response = $this->get('CommentingController/rss/CommentableItem?start=10'); + $this->assertEquals(4, substr_count($response->getBody(), ""), "3 approved, non spam comments on page 2"); - // specific page - $response = $this->get('CommentingController/rss/CommentableItem/'.$item->ID); - $this->assertEquals(1, substr_count($response->getBody(), "")); - $this->assertContains('FA', $response->getBody()); + // specific page + $response = $this->get('CommentingController/rss/CommentableItem/'.$item->ID); + $this->assertEquals(1, substr_count($response->getBody(), "")); + $this->assertContains('FA', $response->getBody()); - // test accessing comments on a type that doesn't exist - $response = $this->get('CommentingController/rss/Fake'); - $this->assertEquals(404, $response->getStatusCode()); - } + // test accessing comments on a type that doesn't exist + $response = $this->get('CommentingController/rss/Fake'); + $this->assertEquals(404, $response->getStatusCode()); + } // This is returning a 404 which looks logical code wise but also a bit weird. // Test module on a clean install and check what the actual URL is first @@ -177,7 +182,8 @@ class CommentingControllerTest extends FunctionalTest { } */ - public function testCommentsFormUsePreview() { + public function testCommentsFormUsePreview() + { // test with preview on Config::inst()->update('CommentableItem', 'comments', array( 'use_preview' => true @@ -208,67 +214,66 @@ class CommentingControllerTest extends FunctionalTest { CommentTestHelper::assertFieldNames($this, $expected, $commentsFields); } - public function testCommentsForm() { + public function testCommentsForm() + { // Delete the newly added children of firstComA so as not to change this test $this->objFromFixture('Comment', 'firstComAChild1')->delete(); $this->objFromFixture('Comment', 'firstComAChild2')->delete(); $this->objFromFixture('Comment', 'firstComAChild3')->delete(); - SecurityToken::disable(); - $this->autoFollowRedirection = false; - $parent = $this->objFromFixture('CommentableItem', 'first'); + SecurityToken::disable(); + $this->autoFollowRedirection = false; + $parent = $this->objFromFixture('CommentableItem', 'first'); - // Test posting to base comment - $response = $this->post('CommentingController/CommentsForm', - array( - 'Name' => 'Poster', - 'Email' => 'guy@test.com', - 'Comment' => 'My Comment', - 'ParentID' => $parent->ID, - 'BaseClass' => 'CommentableItem', - 'action_doPostComment' => 'Post' - ) - ); - $this->assertEquals(302, $response->getStatusCode()); - $this->assertStringStartsWith('CommentableItem_Controller#comment-', $response->getHeader('Location')); - $this->assertDOSEquals( - array(array( - 'Name' => 'Poster', - 'Email' => 'guy@test.com', - 'Comment' => 'My Comment', - 'ParentID' => $parent->ID, - 'BaseClass' => 'CommentableItem', - )), - Comment::get()->filter('Email', 'guy@test.com') - ); + // Test posting to base comment + $response = $this->post('CommentingController/CommentsForm', + array( + 'Name' => 'Poster', + 'Email' => 'guy@test.com', + 'Comment' => 'My Comment', + 'ParentID' => $parent->ID, + 'BaseClass' => 'CommentableItem', + 'action_doPostComment' => 'Post' + ) + ); + $this->assertEquals(302, $response->getStatusCode()); + $this->assertStringStartsWith('CommentableItem_Controller#comment-', $response->getHeader('Location')); + $this->assertDOSEquals( + array(array( + 'Name' => 'Poster', + 'Email' => 'guy@test.com', + 'Comment' => 'My Comment', + 'ParentID' => $parent->ID, + 'BaseClass' => 'CommentableItem', + )), + Comment::get()->filter('Email', 'guy@test.com') + ); - // Test posting to parent comment - $parentComment = $this->objFromFixture('Comment', 'firstComA'); - $this->assertEquals(0, $parentComment->ChildComments()->count()); + // Test posting to parent comment + $parentComment = $this->objFromFixture('Comment', 'firstComA'); + $this->assertEquals(0, $parentComment->ChildComments()->count()); - $response = $this->post( - 'CommentingController/reply/'.$parentComment->ID, - array( - 'Name' => 'Test Author', - 'Email' => 'test@test.com', - 'Comment' => 'Making a reply to firstComA', - 'ParentID' => $parent->ID, - 'BaseClass' => 'CommentableItem', - 'ParentCommentID' => $parentComment->ID, - 'action_doPostComment' => 'Post' - ) - ); - $this->assertEquals(302, $response->getStatusCode()); - $this->assertStringStartsWith('CommentableItem_Controller#comment-', $response->getHeader('Location')); - $this->assertDOSEquals(array(array( - 'Name' => 'Test Author', - 'Email' => 'test@test.com', - 'Comment' => 'Making a reply to firstComA', - 'ParentID' => $parent->ID, - 'BaseClass' => 'CommentableItem', - 'ParentCommentID' => $parentComment->ID - )), $parentComment->ChildComments()); - - - } + $response = $this->post( + 'CommentingController/reply/'.$parentComment->ID, + array( + 'Name' => 'Test Author', + 'Email' => 'test@test.com', + 'Comment' => 'Making a reply to firstComA', + 'ParentID' => $parent->ID, + 'BaseClass' => 'CommentableItem', + 'ParentCommentID' => $parentComment->ID, + 'action_doPostComment' => 'Post' + ) + ); + $this->assertEquals(302, $response->getStatusCode()); + $this->assertStringStartsWith('CommentableItem_Controller#comment-', $response->getHeader('Location')); + $this->assertDOSEquals(array(array( + 'Name' => 'Test Author', + 'Email' => 'test@test.com', + 'Comment' => 'Making a reply to firstComA', + 'ParentID' => $parent->ID, + 'BaseClass' => 'CommentableItem', + 'ParentCommentID' => $parentComment->ID + )), $parentComment->ChildComments()); + } } diff --git a/tests/CommentingTest.php b/tests/CommentingTest.php index 6b0acfb..0c8ac15 100644 --- a/tests/CommentingTest.php +++ b/tests/CommentingTest.php @@ -1,12 +1,15 @@ get( + $config = Config::inst()->get( 'CommentsExtension', 'comments' ); @@ -53,10 +57,11 @@ class CommentingTest extends SapphireTest { 'all_items_actually_commentsextension', $actual ); - } + } - public function test_get_config_value() { - Config::inst()->update('CommentableItem', 'comments', + public function test_get_config_value() + { + Config::inst()->update('CommentableItem', 'comments', array( 'comments_holder_id' => 'commentable_item' ) @@ -82,10 +87,11 @@ class CommentingTest extends SapphireTest { 'Member does not have commenting enabled' ); Commenting::get_config_value('Member', 'comments_holder_id'); - } + } - public function test_config_value_equals() { - Config::inst()->update('CommentableItem', 'comments', + public function test_config_value_equals() + { + Config::inst()->update('CommentableItem', 'comments', array( 'comments_holder_id' => 'some_value' ) @@ -106,9 +112,10 @@ class CommentingTest extends SapphireTest { 'not_some_value' ) ); - } + } - public function test_add() { + public function test_add() + { Commenting::add('Member', array('comments_holder_id' => 'test_add_value')); $config = Config::inst()->get( @@ -136,13 +143,14 @@ class CommentingTest extends SapphireTest { $this->setExpectedException('InvalidArgumentException', "\$settings needs to be an array or null"); Commenting::add('Member', 'illegal format, not an array'); - - } - public function test_can_member_post() { + public function test_can_member_post() + { // logout - if($member = Member::currentUser()) $member->logOut(); + if ($member = Member::currentUser()) { + $member->logOut(); + } Config::inst()->update('CommentableItem', 'comments', array( @@ -168,6 +176,5 @@ class CommentingTest extends SapphireTest { ); $this->assertTrue(Commenting::can_member_post('CommentableItem')); - } - + } } diff --git a/tests/CommentsExtensionTest.php b/tests/CommentsExtensionTest.php index f08c901..7c1bf29 100644 --- a/tests/CommentsExtensionTest.php +++ b/tests/CommentsExtensionTest.php @@ -1,6 +1,7 @@ markTestSkipped('TODO'); - } + public function testPopulateDefaults() + { + $this->markTestSkipped('TODO'); + } - public function testUpdateSettingsFields() { + public function testUpdateSettingsFields() + { $this->markTestSkipped('This needs SiteTree installed'); - } + } - public function testGetModerationRequired() { + public function testGetModerationRequired() + { // the 3 options take precedence in this order, executed if true Config::inst()->update('CommentableItem', 'comments', array( @@ -90,10 +96,11 @@ class CommentsExtensionTest extends SapphireTest { 'require_moderation_nonmembers' => false )); $this->assertEquals('None', $item->getModerationRequired()); - } + } - public function testGetCommentsRequireLogin() { - Config::inst()->update('CommentableItem', 'comments', array( + public function testGetCommentsRequireLogin() + { + Config::inst()->update('CommentableItem', 'comments', array( 'require_login_cms' => true )); @@ -115,26 +122,30 @@ class CommentsExtensionTest extends SapphireTest { 'require_login' => true )); $this->assertTrue($item->getCommentsRequireLogin()); + } - } + public function testAllComments() + { + $this->markTestSkipped('TODO'); + } - public function testAllComments() { - $this->markTestSkipped('TODO'); - } + public function testAllVisibleComments() + { + $this->markTestSkipped('TODO'); + } - public function testAllVisibleComments() { - $this->markTestSkipped('TODO'); - } + public function testComments() + { + $this->markTestSkipped('TODO'); + } - public function testComments() { - $this->markTestSkipped('TODO'); - } + public function testGetCommentsEnabled() + { + $this->markTestSkipped('TODO'); + } - public function testGetCommentsEnabled() { - $this->markTestSkipped('TODO'); - } - - public function testGetCommentHolderID() { + public function testGetCommentHolderID() + { $item = $this->objFromFixture('CommentableItem', 'first'); Config::inst()->update('CommentableItem', 'comments', array( 'comments_holder_id' => 'commentid_test1', @@ -145,47 +156,53 @@ class CommentsExtensionTest extends SapphireTest { 'comments_holder_id' => 'commtentid_test_another', )); $this->assertEquals('commtentid_test_another', $item->getCommentHolderID()); - } + } - public function testGetPostingRequiredPermission() { - $this->markTestSkipped('TODO'); - } + public function testGetPostingRequiredPermission() + { + $this->markTestSkipped('TODO'); + } - public function testCanModerateComments() { + public function testCanModerateComments() + { // ensure nobody logged in - if(Member::currentUser()) { Member::currentUser()->logOut(); } + if (Member::currentUser()) { + Member::currentUser()->logOut(); + } - $item = $this->objFromFixture('CommentableItem', 'first'); + $item = $this->objFromFixture('CommentableItem', 'first'); $this->assertFalse($item->canModerateComments()); $this->logInWithPermission('CMS_ACCESS_CommentAdmin'); $this->assertTrue($item->canModerateComments()); + } - } - - public function testGetCommentRSSLink() { - $item = $this->objFromFixture('CommentableItem', 'first'); - $link = $item->getCommentRSSLink(); - $this->assertEquals('/CommentingController/rss', $link); - } + public function testGetCommentRSSLink() + { + $item = $this->objFromFixture('CommentableItem', 'first'); + $link = $item->getCommentRSSLink(); + $this->assertEquals('/CommentingController/rss', $link); + } - public function testGetCommentRSSLinkPage() { - $item = $this->objFromFixture('CommentableItem', 'first'); + public function testGetCommentRSSLinkPage() + { + $item = $this->objFromFixture('CommentableItem', 'first'); $page = $item->getCommentRSSLinkPage(); $this->assertEquals( '/CommentingController/rss/CommentableItem/' . $item->ID, $page ); - } + } - public function testCommentsForm() { + public function testCommentsForm() + { Config::inst()->update('CommentableItem', 'comments', array( 'include_js' => false ) ); - $item = $this->objFromFixture('CommentableItem', 'first'); + $item = $this->objFromFixture('CommentableItem', 'first'); // The comments form is HTML to do assertions by contains $cf = $item->CommentsForm(); @@ -255,13 +272,15 @@ class CommentsExtensionTest extends SapphireTest { ), $backend->get_javascript() ); - } + } - public function testAttachedToSiteTree() { - $this->markTestSkipped('TODO'); - } + public function testAttachedToSiteTree() + { + $this->markTestSkipped('TODO'); + } - public function testPagedComments() { + public function testPagedComments() + { $item = $this->objFromFixture('CommentableItem', 'first'); // Ensure Created times are set, as order not guaranteed if all set to 0 $comments = $item->PagedComments()->sort('ID'); @@ -276,7 +295,7 @@ class CommentsExtensionTest extends SapphireTest { $results = $item->PagedComments()->toArray(); foreach ($results as $result) { - $result->sourceQueryParams = null; + $result->sourceQueryParams = null; } $this->assertEquals( @@ -297,23 +316,26 @@ class CommentsExtensionTest extends SapphireTest { ); $this->assertEquals(4, sizeof($results)); - } + } - public function testGetCommentsOption() { - $this->markTestSkipped('TODO'); - } + public function testGetCommentsOption() + { + $this->markTestSkipped('TODO'); + } - public function testUpdateModerationFields() { - $this->markTestSkipped('TODO'); - } + public function testUpdateModerationFields() + { + $this->markTestSkipped('TODO'); + } - public function testUpdateCMSFields() { + public function testUpdateCMSFields() + { Config::inst()->update('CommentableItem', 'comments', array( 'require_login_cms' => false ) ); $this->logInWithPermission('ADMIN'); - $item = $this->objFromFixture('CommentableItem', 'first'); + $item = $this->objFromFixture('CommentableItem', 'first'); $item->ProvideComments = true; $item->write(); $fields = $item->getCMSFields(); @@ -376,11 +398,12 @@ class CommentsExtensionTest extends SapphireTest { array('ProvideComments', 'CommentsRequireLogin'), $fields ); - } + } - public function testDeprecatedMethods() { + public function testDeprecatedMethods() + { $item = $this->objFromFixture('CommentableItem', 'first'); $methodNames = array( 'getRssLinkPage', @@ -403,7 +426,5 @@ class CommentsExtensionTest extends SapphireTest { } // ooh, $this->setExpectedException('ExpectedException', 'Expected Message'); - } - } diff --git a/tests/CommentsGridFieldActionTest.php b/tests/CommentsGridFieldActionTest.php index 1a82160..c51fbbd 100644 --- a/tests/CommentsGridFieldActionTest.php +++ b/tests/CommentsGridFieldActionTest.php @@ -1,6 +1,7 @@ list = new DataList('GridFieldAction_Delete_Team'); $config = CommentsGridFieldConfig::create()->addComponent(new GridFieldDeleteAction()); @@ -19,7 +21,8 @@ class CommentsGridFieldActionTest extends SapphireTest { $this->form = new Form(new Controller(), 'mockform', new FieldList(array($this->gridField)), new FieldList()); } - public function testAugmentColumns() { + public function testAugmentColumns() + { $action = new CommentsGridFieldAction(); // an entry called 'Actions' is added to the columns array @@ -32,32 +35,36 @@ class CommentsGridFieldActionTest extends SapphireTest { $action->augmentColumns($this->gridField, $columns); $expected = array('Actions'); $this->assertEquals($expected, $columns); - } + } - public function testGetColumnAttributes() { - $action = new CommentsGridFieldAction(); + public function testGetColumnAttributes() + { + $action = new CommentsGridFieldAction(); $record = new Comment(); $attrs = $action->getColumnAttributes($this->gridField, $record, 'Comment'); $this->assertEquals(array('class' => 'col-buttons'), $attrs); - } + } - public function testGetColumnMetadata() { - $action = new CommentsGridFieldAction(); + public function testGetColumnMetadata() + { + $action = new CommentsGridFieldAction(); $result = $action->getColumnMetadata($this->gridField, 'Actions'); $this->assertEquals(array('title' => ''), $result); $result = $action->getColumnMetadata($this->gridField, 'SomethingElse'); $this->assertNull($result); - } + } - public function testGetColumnsHandled() { - $action = new CommentsGridFieldAction(); + public function testGetColumnsHandled() + { + $action = new CommentsGridFieldAction(); $result = $action->getColumnsHandled($this->gridField); $this->assertEquals(array('Actions'), $result); - } + } - public function testGetColumnContent() { + public function testGetColumnContent() + { $this->logInWithPermission('CMS_ACCESS_CommentAdmin'); - $action = new CommentsGridFieldAction(); + $action = new CommentsGridFieldAction(); $record = new Comment(); $record->Name = 'Name of commeter'; $record->Comment = 'This is a comment'; @@ -87,17 +94,19 @@ class CommentsGridFieldActionTest extends SapphireTest { $html = $action->getColumnContent($this->gridField, $record, 'Comment'); $this->assertNotContains($approveAction, $html); $this->assertContains($spamAction, $html); - } + } - public function testGetActions() { - $action = new CommentsGridFieldAction(); + public function testGetActions() + { + $action = new CommentsGridFieldAction(); $result = $action->getActions($this->gridField); $this->assertEquals(array('spam', 'approve'), $result); - } + } - public function testHandleAction() { - $action = new CommentsGridFieldAction(); + public function testHandleAction() + { + $action = new CommentsGridFieldAction(); $record = new Comment(); $record->Name = 'Name of commeter'; $record->Comment = 'This is a comment'; @@ -105,7 +114,7 @@ class CommentsGridFieldActionTest extends SapphireTest { $recordID = $record->ID; $arguments = array('RecordID' => $recordID); $data = array(); - $result = $action->handleAction($this->gridField, 'spam', $arguments, $data ); + $result = $action->handleAction($this->gridField, 'spam', $arguments, $data); $this->assertEquals(200, Controller::curr()->getResponse()->getStatusCode()); $this->assertEquals( 'Comment marked as spam.', @@ -116,7 +125,7 @@ class CommentsGridFieldActionTest extends SapphireTest { $this->assertEquals(1, $record->IsSpam); //getStatusDescription - $result = $action->handleAction($this->gridField, 'approve', $arguments, $data ); + $result = $action->handleAction($this->gridField, 'approve', $arguments, $data); $this->assertEquals(200, Controller::curr()->getResponse()->getStatusCode()); $this->assertEquals( 'Comment approved.', @@ -128,6 +137,5 @@ class CommentsGridFieldActionTest extends SapphireTest { $this->assertEquals(0, $record->IsSpam); error_log(Controller::curr()->getResponse()->getStatusCode()); - } - + } } diff --git a/tests/CommentsGridFieldBulkActionTest.php b/tests/CommentsGridFieldBulkActionTest.php index bfd39c3..ebb0002 100644 --- a/tests/CommentsGridFieldBulkActionTest.php +++ b/tests/CommentsGridFieldBulkActionTest.php @@ -1,12 +1,14 @@ markTestSkipped('TODO'); - } - - public function testApprove() { - $this->markTestSkipped('TODO'); - } +class CommentsGridFieldBulkActionTest extends SapphireTest +{ + public function testSpam() + { + $this->markTestSkipped('TODO'); + } + public function testApprove() + { + $this->markTestSkipped('TODO'); + } } diff --git a/tests/CommentsGridFieldConfigTest.php b/tests/CommentsGridFieldConfigTest.php index d318be4..26a6ad3 100644 --- a/tests/CommentsGridFieldConfigTest.php +++ b/tests/CommentsGridFieldConfigTest.php @@ -1,9 +1,10 @@ markTestSkipped('TODO'); - } - + $this->markTestSkipped('TODO'); + } } diff --git a/tests/CommentsGridFieldTest.php b/tests/CommentsGridFieldTest.php index 0d9d457..cfba15c 100644 --- a/tests/CommentsGridFieldTest.php +++ b/tests/CommentsGridFieldTest.php @@ -1,22 +1,22 @@ Name = 'Fred Bloggs'; - $comment->Comment = 'This is a comment'; - $attr = array(); + $comment->Name = 'Fred Bloggs'; + $comment->Comment = 'This is a comment'; + $attr = array(); - try { + try { $class = new ReflectionClass($gridfield); $method = $class->getMethod('newRow'); $method->setAccessible(true); - } - - catch (ReflectionException $e) { + } catch (ReflectionException $e) { $this->fail($e->getMessage()); } @@ -33,8 +33,5 @@ class CommentsGridFieldTest extends SapphireTest { $params = array(1, 1, $comment, $attr, $comment->Comment); $newRow = $method->invokeArgs($gridfield, $params); $this->assertEquals('This is a comment', $newRow); - - - } - + } } diff --git a/tests/CommentsTest.php b/tests/CommentsTest.php index 8ea2cd0..07c8d84 100644 --- a/tests/CommentsTest.php +++ b/tests/CommentsTest.php @@ -3,405 +3,434 @@ /** * @package comments */ -class CommentsTest extends FunctionalTest { +class CommentsTest extends FunctionalTest +{ - public static $fixture_file = 'comments/tests/CommentsTest.yml'; + public static $fixture_file = 'comments/tests/CommentsTest.yml'; - protected $extraDataObjects = array( - 'CommentableItem', - 'CommentableItemEnabled', - 'CommentableItemDisabled' - ); + protected $extraDataObjects = array( + 'CommentableItem', + 'CommentableItemEnabled', + 'CommentableItemDisabled' + ); - public function setUp() { - parent::setUp(); - Config::nest(); + public function setUp() + { + parent::setUp(); + Config::nest(); - // Set good default values - Config::inst()->update('CommentsExtension', 'comments', array( - 'enabled' => true, - 'enabled_cms' => false, - 'require_login' => false, - 'require_login_cms' => false, - 'required_permission' => false, - 'require_moderation_nonmembers' => false, - 'require_moderation' => false, - 'require_moderation_cms' => false, - 'frontend_moderation' => false, - 'frontend_spam' => false, - )); + // Set good default values + Config::inst()->update('CommentsExtension', 'comments', array( + 'enabled' => true, + 'enabled_cms' => false, + 'require_login' => false, + 'require_login_cms' => false, + 'required_permission' => false, + 'require_moderation_nonmembers' => false, + 'require_moderation' => false, + 'require_moderation_cms' => false, + 'frontend_moderation' => false, + 'frontend_spam' => false, + )); - // Configure this dataobject - Config::inst()->update('CommentableItem', 'comments', array( - 'enabled_cms' => true - )); - } + // Configure this dataobject + Config::inst()->update('CommentableItem', 'comments', array( + 'enabled_cms' => true + )); + } - public function tearDown() { - Config::unnest(); - parent::tearDown(); - } + public function tearDown() + { + Config::unnest(); + parent::tearDown(); + } - public function testCommentsList() { - // comments don't require moderation so unmoderated comments can be - // shown but not spam posts - Config::inst()->update('CommentableItem', 'comments', array( - 'require_moderation_nonmembers' => false, - 'require_moderation' => false, - 'require_moderation_cms' => false, - )); + public function testCommentsList() + { + // comments don't require moderation so unmoderated comments can be + // shown but not spam posts + Config::inst()->update('CommentableItem', 'comments', array( + 'require_moderation_nonmembers' => false, + 'require_moderation' => false, + 'require_moderation_cms' => false, + )); - $item = $this->objFromFixture('CommentableItem', 'spammed'); - $this->assertEquals('None', $item->ModerationRequired); + $item = $this->objFromFixture('CommentableItem', 'spammed'); + $this->assertEquals('None', $item->ModerationRequired); - $this->assertDOSEquals(array( - array('Name' => 'Comment 1'), - array('Name' => 'Comment 3') - ), $item->Comments(), 'Only 2 non spam posts should be shown'); + $this->assertDOSEquals(array( + array('Name' => 'Comment 1'), + array('Name' => 'Comment 3') + ), $item->Comments(), 'Only 2 non spam posts should be shown'); - // when moderated, only moderated, non spam posts should be shown. - Config::inst()->update('CommentableItem', 'comments', array('require_moderation_nonmembers' => true)); - $this->assertEquals('NonMembersOnly', $item->ModerationRequired); + // when moderated, only moderated, non spam posts should be shown. + Config::inst()->update('CommentableItem', 'comments', array('require_moderation_nonmembers' => true)); + $this->assertEquals('NonMembersOnly', $item->ModerationRequired); - // Check that require_moderation overrides this option - Config::inst()->update('CommentableItem', 'comments', array('require_moderation' => true)); - $this->assertEquals('Required', $item->ModerationRequired); + // Check that require_moderation overrides this option + Config::inst()->update('CommentableItem', 'comments', array('require_moderation' => true)); + $this->assertEquals('Required', $item->ModerationRequired); - $this->assertDOSEquals(array( - array('Name' => 'Comment 3') - ), $item->Comments(), 'Only 1 non spam, moderated post should be shown'); - $this->assertEquals(1, $item->Comments()->Count()); + $this->assertDOSEquals(array( + array('Name' => 'Comment 3') + ), $item->Comments(), 'Only 1 non spam, moderated post should be shown'); + $this->assertEquals(1, $item->Comments()->Count()); - // require_moderation_nonmembers still filters out unmoderated comments - Config::inst()->update('CommentableItem', 'comments', array('require_moderation' => false)); - $this->assertEquals(1, $item->Comments()->Count()); + // require_moderation_nonmembers still filters out unmoderated comments + Config::inst()->update('CommentableItem', 'comments', array('require_moderation' => false)); + $this->assertEquals(1, $item->Comments()->Count()); - Config::inst()->update('CommentableItem', 'comments', array('require_moderation_nonmembers' => false)); - $this->assertEquals(2, $item->Comments()->Count()); + Config::inst()->update('CommentableItem', 'comments', array('require_moderation_nonmembers' => false)); + $this->assertEquals(2, $item->Comments()->Count()); - // With unmoderated comments set to display in frontend - Config::inst()->update('CommentableItem', 'comments', array( - 'require_moderation' => true, - 'frontend_moderation' => true - )); - $this->assertEquals(1, $item->Comments()->Count()); + // With unmoderated comments set to display in frontend + Config::inst()->update('CommentableItem', 'comments', array( + 'require_moderation' => true, + 'frontend_moderation' => true + )); + $this->assertEquals(1, $item->Comments()->Count()); - $this->logInWithPermission('ADMIN'); - $this->assertEquals(2, $item->Comments()->Count()); + $this->logInWithPermission('ADMIN'); + $this->assertEquals(2, $item->Comments()->Count()); - // With spam comments set to display in frontend - Config::inst()->update('CommentableItem', 'comments', array( - 'require_moderation' => true, - 'frontend_moderation' => false, - 'frontend_spam' => true, - )); - if($member = Member::currentUser()) $member->logOut(); - $this->assertEquals(1, $item->Comments()->Count()); + // With spam comments set to display in frontend + Config::inst()->update('CommentableItem', 'comments', array( + 'require_moderation' => true, + 'frontend_moderation' => false, + 'frontend_spam' => true, + )); + if ($member = Member::currentUser()) { + $member->logOut(); + } + $this->assertEquals(1, $item->Comments()->Count()); - $this->logInWithPermission('ADMIN'); - $this->assertEquals(2, $item->Comments()->Count()); + $this->logInWithPermission('ADMIN'); + $this->assertEquals(2, $item->Comments()->Count()); - // With spam and unmoderated comments set to display in frontend - Config::inst()->update('CommentableItem', 'comments', array( - 'require_moderation' => true, - 'frontend_moderation' => true, - 'frontend_spam' => true, - )); - if($member = Member::currentUser()) $member->logOut(); - $this->assertEquals(1, $item->Comments()->Count()); + // With spam and unmoderated comments set to display in frontend + Config::inst()->update('CommentableItem', 'comments', array( + 'require_moderation' => true, + 'frontend_moderation' => true, + 'frontend_spam' => true, + )); + if ($member = Member::currentUser()) { + $member->logOut(); + } + $this->assertEquals(1, $item->Comments()->Count()); - $this->logInWithPermission('ADMIN'); - $this->assertEquals(4, $item->Comments()->Count()); - } + $this->logInWithPermission('ADMIN'); + $this->assertEquals(4, $item->Comments()->Count()); + } - /** - * Test moderation options configured via the CMS - */ - public function testCommentCMSModerationList() { - // comments don't require moderation so unmoderated comments can be - // shown but not spam posts - Config::inst()->update('CommentableItem', 'comments', array( - 'require_moderation' => true, - 'require_moderation_cms' => true, - )); + /** + * Test moderation options configured via the CMS + */ + public function testCommentCMSModerationList() + { + // comments don't require moderation so unmoderated comments can be + // shown but not spam posts + Config::inst()->update('CommentableItem', 'comments', array( + 'require_moderation' => true, + 'require_moderation_cms' => true, + )); - $item = $this->objFromFixture('CommentableItem', 'spammed'); - $this->assertEquals('None', $item->ModerationRequired); + $item = $this->objFromFixture('CommentableItem', 'spammed'); + $this->assertEquals('None', $item->ModerationRequired); - $this->assertDOSEquals(array( - array('Name' => 'Comment 1'), - array('Name' => 'Comment 3') - ), $item->Comments(), 'Only 2 non spam posts should be shown'); + $this->assertDOSEquals(array( + array('Name' => 'Comment 1'), + array('Name' => 'Comment 3') + ), $item->Comments(), 'Only 2 non spam posts should be shown'); - // when moderated, only moderated, non spam posts should be shown. - $item->ModerationRequired = 'NonMembersOnly'; - $item->write(); - $this->assertEquals('NonMembersOnly', $item->ModerationRequired); + // when moderated, only moderated, non spam posts should be shown. + $item->ModerationRequired = 'NonMembersOnly'; + $item->write(); + $this->assertEquals('NonMembersOnly', $item->ModerationRequired); - // Check that require_moderation overrides this option - $item->ModerationRequired = 'Required'; - $item->write(); - $this->assertEquals('Required', $item->ModerationRequired); + // Check that require_moderation overrides this option + $item->ModerationRequired = 'Required'; + $item->write(); + $this->assertEquals('Required', $item->ModerationRequired); - $this->assertDOSEquals(array( - array('Name' => 'Comment 3') - ), $item->Comments(), 'Only 1 non spam, moderated post should be shown'); - $this->assertEquals(1, $item->Comments()->Count()); + $this->assertDOSEquals(array( + array('Name' => 'Comment 3') + ), $item->Comments(), 'Only 1 non spam, moderated post should be shown'); + $this->assertEquals(1, $item->Comments()->Count()); - // require_moderation_nonmembers still filters out unmoderated comments - $item->ModerationRequired = 'NonMembersOnly'; - $item->write(); - $this->assertEquals(1, $item->Comments()->Count()); + // require_moderation_nonmembers still filters out unmoderated comments + $item->ModerationRequired = 'NonMembersOnly'; + $item->write(); + $this->assertEquals(1, $item->Comments()->Count()); - $item->ModerationRequired = 'None'; - $item->write(); - $this->assertEquals(2, $item->Comments()->Count()); - } + $item->ModerationRequired = 'None'; + $item->write(); + $this->assertEquals(2, $item->Comments()->Count()); + } - public function testCanPostComment() { - Config::inst()->update('CommentableItem', 'comments', array( - 'require_login' => false, - 'require_login_cms' => false, - 'required_permission' => false, - )); - $item = $this->objFromFixture('CommentableItem', 'first'); - $item2 = $this->objFromFixture('CommentableItem', 'second'); + public function testCanPostComment() + { + Config::inst()->update('CommentableItem', 'comments', array( + 'require_login' => false, + 'require_login_cms' => false, + 'required_permission' => false, + )); + $item = $this->objFromFixture('CommentableItem', 'first'); + $item2 = $this->objFromFixture('CommentableItem', 'second'); - // Test restriction free commenting - if($member = Member::currentUser()) $member->logOut(); - $this->assertFalse($item->CommentsRequireLogin); - $this->assertTrue($item->canPostComment()); + // Test restriction free commenting + if ($member = Member::currentUser()) { + $member->logOut(); + } + $this->assertFalse($item->CommentsRequireLogin); + $this->assertTrue($item->canPostComment()); - // Test permission required to post - Config::inst()->update('CommentableItem', 'comments', array( - 'require_login' => true, - 'required_permission' => 'POSTING_PERMISSION', - )); - $this->assertTrue($item->CommentsRequireLogin); - $this->assertFalse($item->canPostComment()); - $this->logInWithPermission('WRONG_ONE'); - $this->assertFalse($item->canPostComment()); - $this->logInWithPermission('POSTING_PERMISSION'); - $this->assertTrue($item->canPostComment()); - $this->logInWithPermission('ADMIN'); - $this->assertTrue($item->canPostComment()); + // Test permission required to post + Config::inst()->update('CommentableItem', 'comments', array( + 'require_login' => true, + 'required_permission' => 'POSTING_PERMISSION', + )); + $this->assertTrue($item->CommentsRequireLogin); + $this->assertFalse($item->canPostComment()); + $this->logInWithPermission('WRONG_ONE'); + $this->assertFalse($item->canPostComment()); + $this->logInWithPermission('POSTING_PERMISSION'); + $this->assertTrue($item->canPostComment()); + $this->logInWithPermission('ADMIN'); + $this->assertTrue($item->canPostComment()); - // Test require login to post, but not any permissions - Config::inst()->update('CommentableItem', 'comments', array( - 'required_permission' => false, - )); - $this->assertTrue($item->CommentsRequireLogin); - if($member = Member::currentUser()) $member->logOut(); - $this->assertFalse($item->canPostComment()); - $this->logInWithPermission('ANY_PERMISSION'); - $this->assertTrue($item->canPostComment()); + // Test require login to post, but not any permissions + Config::inst()->update('CommentableItem', 'comments', array( + 'required_permission' => false, + )); + $this->assertTrue($item->CommentsRequireLogin); + if ($member = Member::currentUser()) { + $member->logOut(); + } + $this->assertFalse($item->canPostComment()); + $this->logInWithPermission('ANY_PERMISSION'); + $this->assertTrue($item->canPostComment()); - // Test options set via CMS - Config::inst()->update('CommentableItem', 'comments', array( - 'require_login' => true, - 'require_login_cms' => true, - )); - $this->assertFalse($item->CommentsRequireLogin); - $this->assertTrue($item2->CommentsRequireLogin); - if($member = Member::currentUser()) $member->logOut(); - $this->assertTrue($item->canPostComment()); - $this->assertFalse($item2->canPostComment()); + // Test options set via CMS + Config::inst()->update('CommentableItem', 'comments', array( + 'require_login' => true, + 'require_login_cms' => true, + )); + $this->assertFalse($item->CommentsRequireLogin); + $this->assertTrue($item2->CommentsRequireLogin); + if ($member = Member::currentUser()) { + $member->logOut(); + } + $this->assertTrue($item->canPostComment()); + $this->assertFalse($item2->canPostComment()); - // Login grants permission to post - $this->logInWithPermission('ANY_PERMISSION'); - $this->assertTrue($item->canPostComment()); - $this->assertTrue($item2->canPostComment()); + // Login grants permission to post + $this->logInWithPermission('ANY_PERMISSION'); + $this->assertTrue($item->canPostComment()); + $this->assertTrue($item2->canPostComment()); + } + public function testDeleteComment() + { + // Test anonymous user + if ($member = Member::currentUser()) { + $member->logOut(); + } + $comment = $this->objFromFixture('Comment', 'firstComA'); + $commentID = $comment->ID; + $this->assertNull($comment->DeleteLink(), 'No permission to see delete link'); + $delete = $this->get('CommentingController/delete/'.$comment->ID.'?ajax=1'); + $this->assertEquals(403, $delete->getStatusCode()); + $check = DataObject::get_by_id('Comment', $commentID); + $this->assertTrue($check && $check->exists()); - } - public function testDeleteComment() { - // Test anonymous user - if($member = Member::currentUser()) $member->logOut(); - $comment = $this->objFromFixture('Comment', 'firstComA'); - $commentID = $comment->ID; - $this->assertNull($comment->DeleteLink(), 'No permission to see delete link'); - $delete = $this->get('CommentingController/delete/'.$comment->ID.'?ajax=1'); - $this->assertEquals(403, $delete->getStatusCode()); - $check = DataObject::get_by_id('Comment', $commentID); - $this->assertTrue($check && $check->exists()); + // Test non-authenticated user + $this->logInAs('visitor'); + $this->assertNull($comment->DeleteLink(), 'No permission to see delete link'); - // Test non-authenticated user - $this->logInAs('visitor'); - $this->assertNull($comment->DeleteLink(), 'No permission to see delete link'); + // Test authenticated user + $this->logInAs('commentadmin'); + $comment = $this->objFromFixture('Comment', 'firstComA'); + $commentID = $comment->ID; + $adminComment1Link = $comment->DeleteLink(); + $this->assertContains('CommentingController/delete/'.$commentID.'?t=', $adminComment1Link); - // Test authenticated user - $this->logInAs('commentadmin'); - $comment = $this->objFromFixture('Comment', 'firstComA'); - $commentID = $comment->ID; - $adminComment1Link = $comment->DeleteLink(); - $this->assertContains('CommentingController/delete/'.$commentID.'?t=', $adminComment1Link); + // Test that this link can't be shared / XSS exploited + $this->logInAs('commentadmin2'); + $delete = $this->get($adminComment1Link); + $this->assertEquals(400, $delete->getStatusCode()); + $check = DataObject::get_by_id('Comment', $commentID); + $this->assertTrue($check && $check->exists()); - // Test that this link can't be shared / XSS exploited - $this->logInAs('commentadmin2'); - $delete = $this->get($adminComment1Link); - $this->assertEquals(400, $delete->getStatusCode()); - $check = DataObject::get_by_id('Comment', $commentID); - $this->assertTrue($check && $check->exists()); + // Test that this other admin can delete the comment with their own link + $adminComment2Link = $comment->DeleteLink(); + $this->assertNotEquals($adminComment2Link, $adminComment1Link); + $this->autoFollowRedirection = false; + $delete = $this->get($adminComment2Link); + $this->assertEquals(302, $delete->getStatusCode()); + $check = DataObject::get_by_id('Comment', $commentID); + $this->assertFalse($check && $check->exists()); + } - // Test that this other admin can delete the comment with their own link - $adminComment2Link = $comment->DeleteLink(); - $this->assertNotEquals($adminComment2Link, $adminComment1Link); - $this->autoFollowRedirection = false; - $delete = $this->get($adminComment2Link); - $this->assertEquals(302, $delete->getStatusCode()); - $check = DataObject::get_by_id('Comment', $commentID); - $this->assertFalse($check && $check->exists()); - } + public function testSpamComment() + { + // Test anonymous user + if ($member = Member::currentUser()) { + $member->logOut(); + } + $comment = $this->objFromFixture('Comment', 'firstComA'); + $commentID = $comment->ID; + $this->assertNull($comment->SpamLink(), 'No permission to see mark as spam link'); + $spam = $this->get('CommentingController/spam/'.$comment->ID.'?ajax=1'); + $this->assertEquals(403, $spam->getStatusCode()); + $check = DataObject::get_by_id('Comment', $commentID); + $this->assertEquals(0, $check->IsSpam, 'No permission to mark as spam'); - public function testSpamComment() { - // Test anonymous user - if($member = Member::currentUser()) $member->logOut(); - $comment = $this->objFromFixture('Comment', 'firstComA'); - $commentID = $comment->ID; - $this->assertNull($comment->SpamLink(), 'No permission to see mark as spam link'); - $spam = $this->get('CommentingController/spam/'.$comment->ID.'?ajax=1'); - $this->assertEquals(403, $spam->getStatusCode()); - $check = DataObject::get_by_id('Comment', $commentID); - $this->assertEquals(0, $check->IsSpam, 'No permission to mark as spam'); + // Test non-authenticated user + $this->logInAs('visitor'); + $this->assertNull($comment->SpamLink(), 'No permission to see mark as spam link'); - // Test non-authenticated user - $this->logInAs('visitor'); - $this->assertNull($comment->SpamLink(), 'No permission to see mark as spam link'); + // Test authenticated user + $this->logInAs('commentadmin'); + $comment = $this->objFromFixture('Comment', 'firstComA'); + $commentID = $comment->ID; + $adminComment1Link = $comment->SpamLink(); + $this->assertContains('CommentingController/spam/'.$commentID.'?t=', $adminComment1Link); - // Test authenticated user - $this->logInAs('commentadmin'); - $comment = $this->objFromFixture('Comment', 'firstComA'); - $commentID = $comment->ID; - $adminComment1Link = $comment->SpamLink(); - $this->assertContains('CommentingController/spam/'.$commentID.'?t=', $adminComment1Link); + // Test that this link can't be shared / XSS exploited + $this->logInAs('commentadmin2'); + $spam = $this->get($adminComment1Link); + $this->assertEquals(400, $spam->getStatusCode()); + $check = DataObject::get_by_id('Comment', $comment->ID); + $this->assertEquals(0, $check->IsSpam, 'No permission to mark as spam'); - // Test that this link can't be shared / XSS exploited - $this->logInAs('commentadmin2'); - $spam = $this->get($adminComment1Link); - $this->assertEquals(400, $spam->getStatusCode()); - $check = DataObject::get_by_id('Comment', $comment->ID); - $this->assertEquals(0, $check->IsSpam, 'No permission to mark as spam'); + // Test that this other admin can spam the comment with their own link + $adminComment2Link = $comment->SpamLink(); + $this->assertNotEquals($adminComment2Link, $adminComment1Link); + $this->autoFollowRedirection = false; + $spam = $this->get($adminComment2Link); + $this->assertEquals(302, $spam->getStatusCode()); + $check = DataObject::get_by_id('Comment', $commentID); + $this->assertEquals(1, $check->IsSpam); - // Test that this other admin can spam the comment with their own link - $adminComment2Link = $comment->SpamLink(); - $this->assertNotEquals($adminComment2Link, $adminComment1Link); - $this->autoFollowRedirection = false; - $spam = $this->get($adminComment2Link); - $this->assertEquals(302, $spam->getStatusCode()); - $check = DataObject::get_by_id('Comment', $commentID); - $this->assertEquals(1, $check->IsSpam); + // Cannot re-spam spammed comment + $this->assertNull($check->SpamLink()); + } - // Cannot re-spam spammed comment - $this->assertNull($check->SpamLink()); - } + public function testHamComment() + { + // Test anonymous user + if ($member = Member::currentUser()) { + $member->logOut(); + } + $comment = $this->objFromFixture('Comment', 'secondComC'); + $commentID = $comment->ID; + $this->assertNull($comment->HamLink(), 'No permission to see mark as ham link'); + $ham = $this->get('CommentingController/ham/'.$comment->ID.'?ajax=1'); + $this->assertEquals(403, $ham->getStatusCode()); + $check = DataObject::get_by_id('Comment', $commentID); + $this->assertEquals(1, $check->IsSpam, 'No permission to mark as ham'); - public function testHamComment() { - // Test anonymous user - if($member = Member::currentUser()) $member->logOut(); - $comment = $this->objFromFixture('Comment', 'secondComC'); - $commentID = $comment->ID; - $this->assertNull($comment->HamLink(), 'No permission to see mark as ham link'); - $ham = $this->get('CommentingController/ham/'.$comment->ID.'?ajax=1'); - $this->assertEquals(403, $ham->getStatusCode()); - $check = DataObject::get_by_id('Comment', $commentID); - $this->assertEquals(1, $check->IsSpam, 'No permission to mark as ham'); + // Test non-authenticated user + $this->logInAs('visitor'); + $this->assertNull($comment->HamLink(), 'No permission to see mark as ham link'); - // Test non-authenticated user - $this->logInAs('visitor'); - $this->assertNull($comment->HamLink(), 'No permission to see mark as ham link'); + // Test authenticated user + $this->logInAs('commentadmin'); + $comment = $this->objFromFixture('Comment', 'secondComC'); + $commentID = $comment->ID; + $adminComment1Link = $comment->HamLink(); + $this->assertContains('CommentingController/ham/'.$commentID.'?t=', $adminComment1Link); - // Test authenticated user - $this->logInAs('commentadmin'); - $comment = $this->objFromFixture('Comment', 'secondComC'); - $commentID = $comment->ID; - $adminComment1Link = $comment->HamLink(); - $this->assertContains('CommentingController/ham/'.$commentID.'?t=', $adminComment1Link); + // Test that this link can't be shared / XSS exploited + $this->logInAs('commentadmin2'); + $ham = $this->get($adminComment1Link); + $this->assertEquals(400, $ham->getStatusCode()); + $check = DataObject::get_by_id('Comment', $comment->ID); + $this->assertEquals(1, $check->IsSpam, 'No permission to mark as ham'); - // Test that this link can't be shared / XSS exploited - $this->logInAs('commentadmin2'); - $ham = $this->get($adminComment1Link); - $this->assertEquals(400, $ham->getStatusCode()); - $check = DataObject::get_by_id('Comment', $comment->ID); - $this->assertEquals(1, $check->IsSpam, 'No permission to mark as ham'); + // Test that this other admin can ham the comment with their own link + $adminComment2Link = $comment->HamLink(); + $this->assertNotEquals($adminComment2Link, $adminComment1Link); + $this->autoFollowRedirection = false; + $ham = $this->get($adminComment2Link); + $this->assertEquals(302, $ham->getStatusCode()); + $check = DataObject::get_by_id('Comment', $commentID); + $this->assertEquals(0, $check->IsSpam); - // Test that this other admin can ham the comment with their own link - $adminComment2Link = $comment->HamLink(); - $this->assertNotEquals($adminComment2Link, $adminComment1Link); - $this->autoFollowRedirection = false; - $ham = $this->get($adminComment2Link); - $this->assertEquals(302, $ham->getStatusCode()); - $check = DataObject::get_by_id('Comment', $commentID); - $this->assertEquals(0, $check->IsSpam); + // Cannot re-ham hammed comment + $this->assertNull($check->HamLink()); + } - // Cannot re-ham hammed comment - $this->assertNull($check->HamLink()); - } + public function testApproveComment() + { + // Test anonymous user + if ($member = Member::currentUser()) { + $member->logOut(); + } + $comment = $this->objFromFixture('Comment', 'secondComB'); + $commentID = $comment->ID; + $this->assertNull($comment->ApproveLink(), 'No permission to see approve link'); + $approve = $this->get('CommentingController/approve/'.$comment->ID.'?ajax=1'); + $this->assertEquals(403, $approve->getStatusCode()); + $check = DataObject::get_by_id('Comment', $commentID); + $this->assertEquals(0, $check->Moderated, 'No permission to approve'); - public function testApproveComment() { - // Test anonymous user - if($member = Member::currentUser()) $member->logOut(); - $comment = $this->objFromFixture('Comment', 'secondComB'); - $commentID = $comment->ID; - $this->assertNull($comment->ApproveLink(), 'No permission to see approve link'); - $approve = $this->get('CommentingController/approve/'.$comment->ID.'?ajax=1'); - $this->assertEquals(403, $approve->getStatusCode()); - $check = DataObject::get_by_id('Comment', $commentID); - $this->assertEquals(0, $check->Moderated, 'No permission to approve'); + // Test non-authenticated user + $this->logInAs('visitor'); + $this->assertNull($comment->ApproveLink(), 'No permission to see approve link'); - // Test non-authenticated user - $this->logInAs('visitor'); - $this->assertNull($comment->ApproveLink(), 'No permission to see approve link'); + // Test authenticated user + $this->logInAs('commentadmin'); + $comment = $this->objFromFixture('Comment', 'secondComB'); + $commentID = $comment->ID; + $adminComment1Link = $comment->ApproveLink(); + $this->assertContains('CommentingController/approve/'.$commentID.'?t=', $adminComment1Link); - // Test authenticated user - $this->logInAs('commentadmin'); - $comment = $this->objFromFixture('Comment', 'secondComB'); - $commentID = $comment->ID; - $adminComment1Link = $comment->ApproveLink(); - $this->assertContains('CommentingController/approve/'.$commentID.'?t=', $adminComment1Link); + // Test that this link can't be shared / XSS exploited + $this->logInAs('commentadmin2'); + $approve = $this->get($adminComment1Link); + $this->assertEquals(400, $approve->getStatusCode()); + $check = DataObject::get_by_id('Comment', $comment->ID); + $this->assertEquals(0, $check->Moderated, 'No permission to approve'); - // Test that this link can't be shared / XSS exploited - $this->logInAs('commentadmin2'); - $approve = $this->get($adminComment1Link); - $this->assertEquals(400, $approve->getStatusCode()); - $check = DataObject::get_by_id('Comment', $comment->ID); - $this->assertEquals(0, $check->Moderated, 'No permission to approve'); + // Test that this other admin can approve the comment with their own link + $adminComment2Link = $comment->ApproveLink(); + $this->assertNotEquals($adminComment2Link, $adminComment1Link); + $this->autoFollowRedirection = false; + $approve = $this->get($adminComment2Link); + $this->assertEquals(302, $approve->getStatusCode()); + $check = DataObject::get_by_id('Comment', $commentID); + $this->assertEquals(1, $check->Moderated); - // Test that this other admin can approve the comment with their own link - $adminComment2Link = $comment->ApproveLink(); - $this->assertNotEquals($adminComment2Link, $adminComment1Link); - $this->autoFollowRedirection = false; - $approve = $this->get($adminComment2Link); - $this->assertEquals(302, $approve->getStatusCode()); - $check = DataObject::get_by_id('Comment', $commentID); - $this->assertEquals(1, $check->Moderated); + // Cannot re-approve approved comment + $this->assertNull($check->ApproveLink()); + } - // Cannot re-approve approved comment - $this->assertNull($check->ApproveLink()); - } + public function testCommenterURLWrite() + { + $comment = new Comment(); + // We only care about the CommenterURL, so only set that + // Check a http and https URL. Add more test urls here as needed. + $protocols = array( + 'Http', + 'Https', + ); + $url = '://example.com'; - public function testCommenterURLWrite() { - $comment = new Comment(); - // We only care about the CommenterURL, so only set that - // Check a http and https URL. Add more test urls here as needed. - $protocols = array( - 'Http', - 'Https', - ); - $url = '://example.com'; + foreach ($protocols as $protocol) { + $comment->CommenterURL = $protocol . $url; + // The protocol should stay as if, assuming it is valid + $comment->write(); + $this->assertEquals($comment->CommenterURL, $protocol . $url, $protocol . ':// is a valid protocol'); + } + } - foreach($protocols as $protocol) { - $comment->CommenterURL = $protocol . $url; - // The protocol should stay as if, assuming it is valid - $comment->write(); - $this->assertEquals($comment->CommenterURL, $protocol . $url, $protocol . ':// is a valid protocol'); - } - } - - public function testSanitizesWithAllowHtml() { - if(!class_exists('HTMLPurifier')) { - $this->markTestSkipped('HTMLPurifier class not found'); - return; - } + public function testSanitizesWithAllowHtml() + { + if (!class_exists('HTMLPurifier')) { + $this->markTestSkipped('HTMLPurifier class not found'); + return; + } // Add p for paragraph // NOTE: The config method appears to append to the existing array @@ -409,125 +438,127 @@ class CommentsTest extends FunctionalTest { 'html_allowed_elements' => array('p'), )); - // Without HTML allowed - $comment1 = new Comment(); + // Without HTML allowed + $comment1 = new Comment(); $comment1->AllowHtml = false; - $comment1->BaseClass = 'CommentableItem'; - $comment1->Comment = '

my comment

'; - $comment1->write(); - $this->assertEquals( - '

my comment

', - $comment1->Comment, - 'Does not remove HTML tags with html_allowed=false, ' . - 'which is correct behaviour because the HTML will be escaped' - ); + $comment1->BaseClass = 'CommentableItem'; + $comment1->Comment = '

my comment

'; + $comment1->write(); + $this->assertEquals( + '

my comment

', + $comment1->Comment, + 'Does not remove HTML tags with html_allowed=false, ' . + 'which is correct behaviour because the HTML will be escaped' + ); - // With HTML allowed - $comment2 = new Comment(); + // With HTML allowed + $comment2 = new Comment(); $comment2->AllowHtml = true; - $comment2->BaseClass = 'CommentableItem'; - $comment2->Comment = '

my comment

'; - $comment2->write(); - $this->assertEquals( - '

my comment

', - $comment2->Comment, - 'Removes HTML tags which are not on the whitelist' - ); - } + $comment2->BaseClass = 'CommentableItem'; + $comment2->Comment = '

my comment

'; + $comment2->write(); + $this->assertEquals( + '

my comment

', + $comment2->Comment, + 'Removes HTML tags which are not on the whitelist' + ); + } - public function testDefaultTemplateRendersHtmlWithAllowHtml() { - if(!class_exists('HTMLPurifier')) { - $this->markTestSkipped('HTMLPurifier class not found'); - } + public function testDefaultTemplateRendersHtmlWithAllowHtml() + { + if (!class_exists('HTMLPurifier')) { + $this->markTestSkipped('HTMLPurifier class not found'); + } Config::inst()->update('CommentableItem', 'comments', array( 'html_allowed_elements' => array('p'), )); - $item = new CommentableItem(); - $item->write(); + $item = new CommentableItem(); + $item->write(); - // Without HTML allowed - $comment = new Comment(); - $comment->Comment = '

my comment

'; + // Without HTML allowed + $comment = new Comment(); + $comment->Comment = '

my comment

'; $comment->AllowHtml = false; - $comment->ParentID = $item->ID; - $comment->BaseClass = 'CommentableItem'; - $comment->write(); + $comment->ParentID = $item->ID; + $comment->BaseClass = 'CommentableItem'; + $comment->write(); - $html = $item->customise(array('CommentsEnabled' => true))->renderWith('CommentsInterface'); - $this->assertContains( - '<p>my comment</p>', - $html - ); + $html = $item->customise(array('CommentsEnabled' => true))->renderWith('CommentsInterface'); + $this->assertContains( + '<p>my comment</p>', + $html + ); $comment->AllowHtml = true; $comment->write(); - $html = $item->customise(array('CommentsEnabled' => true))->renderWith('CommentsInterface'); - $this->assertContains( - '

my comment

', - $html - ); - - } + $html = $item->customise(array('CommentsEnabled' => true))->renderWith('CommentsInterface'); + $this->assertContains( + '

my comment

', + $html + ); + } - /** - * Tests whether comments are enabled or disabled by default - */ - public function testDefaultEnabled() { - // Ensure values are set via cms (not via config) - Config::inst()->update('CommentableItem', 'comments', array( - 'enabled_cms' => true, - 'require_moderation_cms' => true, - 'require_login_cms' => true - )); + /** + * Tests whether comments are enabled or disabled by default + */ + public function testDefaultEnabled() + { + // Ensure values are set via cms (not via config) + Config::inst()->update('CommentableItem', 'comments', array( + 'enabled_cms' => true, + 'require_moderation_cms' => true, + 'require_login_cms' => true + )); - // With default = true - $obj = new CommentableItem(); - $this->assertTrue((bool)$obj->getCommentsOption('enabled'), "Default setting is enabled"); - $this->assertTrue((bool)$obj->ProvideComments); - $this->assertEquals('None', $obj->ModerationRequired); - $this->assertFalse((bool)$obj->CommentsRequireLogin); + // With default = true + $obj = new CommentableItem(); + $this->assertTrue((bool)$obj->getCommentsOption('enabled'), "Default setting is enabled"); + $this->assertTrue((bool)$obj->ProvideComments); + $this->assertEquals('None', $obj->ModerationRequired); + $this->assertFalse((bool)$obj->CommentsRequireLogin); - $obj = new CommentableItemEnabled(); - $this->assertTrue((bool)$obj->ProvideComments); - $this->assertEquals('Required', $obj->ModerationRequired); - $this->assertTrue((bool)$obj->CommentsRequireLogin); + $obj = new CommentableItemEnabled(); + $this->assertTrue((bool)$obj->ProvideComments); + $this->assertEquals('Required', $obj->ModerationRequired); + $this->assertTrue((bool)$obj->CommentsRequireLogin); - $obj = new CommentableItemDisabled(); - $this->assertFalse((bool)$obj->ProvideComments); - $this->assertEquals('None', $obj->ModerationRequired); - $this->assertFalse((bool)$obj->CommentsRequireLogin); + $obj = new CommentableItemDisabled(); + $this->assertFalse((bool)$obj->ProvideComments); + $this->assertEquals('None', $obj->ModerationRequired); + $this->assertFalse((bool)$obj->CommentsRequireLogin); - // With default = false - // Because of config rules about falsey values, apply config to object directly - Config::inst()->update('CommentableItem', 'comments', array( - 'enabled' => false, - 'require_login' => true, - 'require_moderation' => true - )); - $obj = new CommentableItem(); - $this->assertFalse((bool)$obj->getCommentsOption('enabled'), "Default setting is disabled"); - $this->assertFalse((bool)$obj->ProvideComments); - $this->assertEquals('Required', $obj->ModerationRequired); - $this->assertTrue((bool)$obj->CommentsRequireLogin); + // With default = false + // Because of config rules about falsey values, apply config to object directly + Config::inst()->update('CommentableItem', 'comments', array( + 'enabled' => false, + 'require_login' => true, + 'require_moderation' => true + )); + $obj = new CommentableItem(); + $this->assertFalse((bool)$obj->getCommentsOption('enabled'), "Default setting is disabled"); + $this->assertFalse((bool)$obj->ProvideComments); + $this->assertEquals('Required', $obj->ModerationRequired); + $this->assertTrue((bool)$obj->CommentsRequireLogin); - $obj = new CommentableItemEnabled(); - $this->assertTrue((bool)$obj->ProvideComments); - $this->assertEquals('Required', $obj->ModerationRequired); - $this->assertTrue((bool)$obj->CommentsRequireLogin); + $obj = new CommentableItemEnabled(); + $this->assertTrue((bool)$obj->ProvideComments); + $this->assertEquals('Required', $obj->ModerationRequired); + $this->assertTrue((bool)$obj->CommentsRequireLogin); - $obj = new CommentableItemDisabled(); - $this->assertFalse((bool)$obj->ProvideComments); - $this->assertEquals('None', $obj->ModerationRequired); - $this->assertFalse((bool)$obj->CommentsRequireLogin); - } + $obj = new CommentableItemDisabled(); + $this->assertFalse((bool)$obj->ProvideComments); + $this->assertEquals('None', $obj->ModerationRequired); + $this->assertFalse((bool)$obj->CommentsRequireLogin); + } /* When a parent comment is deleted, remove the children */ - public function testOnBeforeDelete() { + public function testOnBeforeDelete() + { $comment = $this->objFromFixture('Comment', 'firstComA'); $child = new Comment(); @@ -547,11 +578,13 @@ class CommentsTest extends FunctionalTest { $this->assertFalse(DataObject::get_by_id('Comment', $childCommentID)); } - public function testRequireDefaultRecords() { + public function testRequireDefaultRecords() + { $this->markTestSkipped('TODO'); } - public function testLink() { + public function testLink() + { $comment = $this->objFromFixture('Comment', 'thirdComD'); $this->assertEquals('CommentableItem_Controller#comment-'.$comment->ID, $comment->Link()); @@ -563,7 +596,8 @@ class CommentsTest extends FunctionalTest { $this->assertEquals('', $comment->Link()); } - public function testPermalink() { + public function testPermalink() + { $comment = $this->objFromFixture('Comment', 'thirdComD'); $this->assertEquals('comment-' . $comment->ID, $comment->Permalink()); } @@ -571,7 +605,8 @@ class CommentsTest extends FunctionalTest { /* Test field labels in 2 languages */ - public function testFieldLabels() { + public function testFieldLabels() + { $locale = i18n::get_locale(); i18n::set_locale('fr'); $comment = $this->objFromFixture('Comment', 'firstComA'); @@ -619,18 +654,21 @@ class CommentsTest extends FunctionalTest { $this->assertEquals($expected, $labels); } - public function testGetOption() { + public function testGetOption() + { $this->markTestSkipped('TODO'); } - public function testGetParent() { + public function testGetParent() + { $comment = $this->objFromFixture('Comment', 'firstComA'); $item = $this->objFromFixture('CommentableItem', 'first'); $parent = $comment->getParent(); $this->assertEquals($item, $parent); } - public function testGetParentTitle() { + public function testGetParentTitle() + { $comment = $this->objFromFixture('Comment', 'firstComA'); $title = $comment->getParentTitle(); $this->assertEquals('First', $title); @@ -641,21 +679,25 @@ class CommentsTest extends FunctionalTest { $this->assertEquals('', $comment->getParentTitle()); } - public function testGetParentClassName() { + public function testGetParentClassName() + { $comment = $this->objFromFixture('Comment', 'firstComA'); $className = $comment->getParentClassName(); $this->assertEquals('CommentableItem', $className); } - public function testCastingHelper() { + public function testCastingHelper() + { $this->markTestSkipped('TODO'); } - public function testGetEscapedComment() { + public function testGetEscapedComment() + { $this->markTestSkipped('TODO'); } - public function testIsPreview() { + public function testIsPreview() + { $comment = new Comment(); $comment->Name = 'Fred Bloggs'; $comment->Comment = 'this is a test comment'; @@ -664,7 +706,8 @@ class CommentsTest extends FunctionalTest { $this->assertFalse($comment->isPreview()); } - public function testCanCreate() { + public function testCanCreate() + { $comment = $this->objFromFixture('Comment', 'firstComA'); // admin can create - this is always false @@ -676,7 +719,8 @@ class CommentsTest extends FunctionalTest { $this->assertFalse($comment->canCreate()); } - public function testCanView() { + public function testCanView() + { $comment = $this->objFromFixture('Comment', 'firstComA'); // admin can view @@ -692,7 +736,8 @@ class CommentsTest extends FunctionalTest { $this->assertFalse($comment->canView()); } - public function testCanEdit() { + public function testCanEdit() + { $comment = $this->objFromFixture('Comment', 'firstComA'); // admin can edit @@ -708,7 +753,8 @@ class CommentsTest extends FunctionalTest { $this->assertFalse($comment->canEdit()); } - public function testCanDelete() { + public function testCanDelete() + { $comment = $this->objFromFixture('Comment', 'firstComA'); // admin can delete @@ -724,7 +770,8 @@ class CommentsTest extends FunctionalTest { $this->assertFalse($comment->canDelete()); } - public function testGetMember() { + public function testGetMember() + { $this->logInAs('visitor'); $current = Member::currentUser(); $comment = $this->objFromFixture('Comment', 'firstComA'); @@ -743,7 +790,8 @@ class CommentsTest extends FunctionalTest { $this->assertEquals($current, $member); } - public function testGetAuthorName() { + public function testGetAuthorName() + { $comment = $this->objFromFixture('Comment', 'firstComA'); $this->assertEquals( 'FA', @@ -768,11 +816,11 @@ class CommentsTest extends FunctionalTest { $comment->Name = null; $comment->AuthorID = 0; $this->assertNull($comment->getAuthorName()); - } - public function testLinks() { + public function testLinks() + { $comment = $this->objFromFixture('Comment', 'firstComA'); $this->logInAs('commentadmin'); @@ -808,27 +856,31 @@ class CommentsTest extends FunctionalTest { ); } - public function testMarkSpam() { + public function testMarkSpam() + { $comment = $this->objFromFixture('Comment', 'firstComA'); $comment->markSpam(); $this->assertTrue($comment->Moderated); $this->assertTrue($comment->IsSpam); } - public function testMarkApproved() { + public function testMarkApproved() + { $comment = $this->objFromFixture('Comment', 'firstComA'); $comment->markApproved(); $this->assertTrue($comment->Moderated); $this->assertFalse($comment->IsSpam); } - public function testMarkUnapproved() { + public function testMarkUnapproved() + { $comment = $this->objFromFixture('Comment', 'firstComA'); $comment->markApproved(); $this->assertTrue($comment->Moderated); } - public function testSpamClass() { + public function testSpamClass() + { $comment = $this->objFromFixture('Comment', 'firstComA'); $this->assertEquals('notspam', $comment->spamClass()); $comment->Moderated = false; @@ -837,7 +889,8 @@ class CommentsTest extends FunctionalTest { $this->assertEquals('spam', $comment->spamClass()); } - public function testGetTitle() { + public function testGetTitle() + { $comment = $this->objFromFixture('Comment', 'firstComA'); $this->assertEquals( 'Comment by FA on First', @@ -845,7 +898,8 @@ class CommentsTest extends FunctionalTest { ); } - public function testGetCMSFields() { + public function testGetCMSFields() + { $comment = $this->objFromFixture('Comment', 'firstComA'); $fields = $comment->getCMSFields(); $names = array(); @@ -863,7 +917,8 @@ class CommentsTest extends FunctionalTest { $this->assertEquals($expected, $names); } - public function testGetCMSFieldsCommentHasAuthor() { + public function testGetCMSFieldsCommentHasAuthor() + { $member = Member::get()->filter('FirstName', 'visitor')->first(); $comment = $this->objFromFixture('Comment', 'firstComA'); $comment->AuthorID = $member->ID; @@ -886,7 +941,8 @@ class CommentsTest extends FunctionalTest { $this->assertEquals($expected, $names); } - public function testGetCMSFieldsWithParentComment() { + public function testGetCMSFieldsWithParentComment() + { $comment = $this->objFromFixture('Comment', 'firstComA'); $child = new Comment(); @@ -916,7 +972,8 @@ class CommentsTest extends FunctionalTest { } - public function testPurifyHtml() { + public function testPurifyHtml() + { $comment = $this->objFromFixture('Comment', 'firstComA'); $dirtyHTML = '

my comment

'; @@ -926,7 +983,8 @@ class CommentsTest extends FunctionalTest { ); } - public function testGravatar() { + public function testGravatar() + { // Turn gravatars on Config::inst()->update('CommentableItem', 'comments', array( 'use_gravatar' => true @@ -951,7 +1009,8 @@ class CommentsTest extends FunctionalTest { ); } - public function testGetRepliesEnabled() { + public function testGetRepliesEnabled() + { $comment = $this->objFromFixture('Comment', 'firstComA'); Config::inst()->update('CommentableItem', 'comments', array( 'nested_comments' => false @@ -983,11 +1042,10 @@ class CommentsTest extends FunctionalTest { $comment->markApproved(); $this->assertTrue($comment->getRepliesEnabled()); - - } - public function testAllReplies() { + public function testAllReplies() + { Config::inst()->update('CommentableItem', 'comments', array( 'nested_comments' => true, 'nested_depth' => 4 @@ -1018,7 +1076,8 @@ class CommentsTest extends FunctionalTest { $this->assertEquals(0, $comment->allReplies()->count()); } - public function testReplies() { + public function testReplies() + { CommentableItem::add_extension('CommentsExtension'); $this->logInWithPermission('ADMIN'); Config::inst()->update('CommentableItem', 'comments', array( @@ -1085,7 +1144,8 @@ class CommentsTest extends FunctionalTest { CommentableItem::remove_extension('CommentsExtension'); } - public function testPagedReplies() { + public function testPagedReplies() + { Config::inst()->update('CommentableItem', 'comments', array( 'nested_comments' => true, 'nested_depth' => 4, @@ -1111,7 +1171,8 @@ class CommentsTest extends FunctionalTest { $this->assertEquals(0, $comment->PagedReplies()->count()); } - public function testReplyForm() { + public function testReplyForm() + { Config::inst()->update('CommentableItem', 'comments', array( 'nested_comments' => false, 'nested_depth' => 4 @@ -1154,7 +1215,8 @@ class CommentsTest extends FunctionalTest { $this->assertNull($form); } - public function testUpdateDepth() { + public function testUpdateDepth() + { Config::inst()->update('CommentableItem', 'comments', array( 'nested_comments' => true, 'nested_depth' => 4 @@ -1175,34 +1237,39 @@ class CommentsTest extends FunctionalTest { $this->assertEquals(4, $reply3->Depth); } - public function testGetToken() { + public function testGetToken() + { $this->markTestSkipped('TODO'); } - public function testMemberSalt() { + public function testMemberSalt() + { $this->markTestSkipped('TODO'); } - public function testAddToUrl() { + public function testAddToUrl() + { $this->markTestSkipped('TODO'); } - public function testCheckRequest() { + public function testCheckRequest() + { $this->markTestSkipped('TODO'); } - public function testGenerate() { + public function testGenerate() + { $this->markTestSkipped('TODO'); } - protected static function getMethod($name) { + protected static function getMethod($name) + { $class = new ReflectionClass('Comment'); $method = $class->getMethod($name); $method->setAccessible(true); return $method; } - } @@ -1210,67 +1277,83 @@ class CommentsTest extends FunctionalTest { * @package comments * @subpackage tests */ -class CommentableItem extends DataObject implements TestOnly { +class CommentableItem extends DataObject implements TestOnly +{ - private static $db = array( - 'Title' => 'Varchar' - ); + private static $db = array( + 'Title' => 'Varchar' + ); - private static $extensions = array( - 'CommentsExtension' - ); + private static $extensions = array( + 'CommentsExtension' + ); - public function RelativeLink() { - return "CommentableItem_Controller"; - } + public function RelativeLink() + { + return "CommentableItem_Controller"; + } - public function canView($member = null) { + public function canView($member = null) + { return true; } // This is needed for canModerateComments - public function canEdit($member = null) { - if($member instanceof Member) $memberID = $member->ID; - else if(is_numeric($member)) $memberID = $member; - else $memberID = Member::currentUserID(); + public function canEdit($member = null) + { + if ($member instanceof Member) { + $memberID = $member->ID; + } elseif (is_numeric($member)) { + $memberID = $member; + } else { + $memberID = Member::currentUserID(); + } - if($memberID && Permission::checkMember($memberID, array("ADMIN", "CMS_ACCESS_CommentAdmin"))) return true; + if ($memberID && Permission::checkMember($memberID, array("ADMIN", "CMS_ACCESS_CommentAdmin"))) { + return true; + } return false; } - public function Link() { - return $this->RelativeLink(); - } + public function Link() + { + return $this->RelativeLink(); + } - public function AbsoluteLink() { - return Director::absoluteURL($this->RelativeLink()); - } + public function AbsoluteLink() + { + return Director::absoluteURL($this->RelativeLink()); + } } -class CommentableItemEnabled extends CommentableItem { - private static $defaults = array( - 'ProvideComments' => true, - 'ModerationRequired' => 'Required', - 'CommentsRequireLogin' => true - ); +class CommentableItemEnabled extends CommentableItem +{ + private static $defaults = array( + 'ProvideComments' => true, + 'ModerationRequired' => 'Required', + 'CommentsRequireLogin' => true + ); } -class CommentableItemDisabled extends CommentableItem { - private static $defaults = array( - 'ProvideComments' => false, - 'ModerationRequired' => 'None', - 'CommentsRequireLogin' => false - ); +class CommentableItemDisabled extends CommentableItem +{ + private static $defaults = array( + 'ProvideComments' => false, + 'ModerationRequired' => 'None', + 'CommentsRequireLogin' => false + ); } /** * @package comments * @subpackage tests */ -class CommentableItem_Controller extends Controller implements TestOnly { +class CommentableItem_Controller extends Controller implements TestOnly +{ - public function index() { - return CommentableItem::get()->first()->CommentsForm(); - } + public function index() + { + return CommentableItem::get()->first()->CommentsForm(); + } }