Skip to content

Commit

Permalink
API: Use config / extension APIs
Browse files Browse the repository at this point in the history
Overhaul of spam protection to use an extension on Form rather than the SpamProtectorManager. More fluent interface and easier to replace the built in spam protection api with an alternative.
  • Loading branch information
wilr committed Feb 10, 2014
1 parent 28b57be commit 440e30b
Show file tree
Hide file tree
Showing 14 changed files with 297 additions and 235 deletions.
8 changes: 0 additions & 8 deletions CHANGELOG

This file was deleted.

106 changes: 101 additions & 5 deletions README.md
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -14,12 +14,108 @@ SilverStripe 3.0.0 or greater


## Documentation ## Documentation


See docs/ This module provides a generic, consistent API for adding spam protection to
your SilverStripe Forms. This does not provide any spam protection out of the
box, for that, you must also download one of the spam protection
implementations. Currently available options are:


## Installation Instructions * [Mollom](https://github.com/silverstripe/silverstripe-mollom)
* [Recaptcha](https://github.com/chillu/silverstripe-recaptcha)
* [MathSpamProtection](https://github.com/silverstripe/silverstripe-mathspamprotection)


See docs/Install As a developer you can also provide your own protector by creating a class which
implements the `SpamProtector` interface. More on that below.


## Usage Overview ## Configuring


See docs/Install After installing this module and a protector of your choice (i.e mollom) you'll
need to rebuild your database through `dev/build` and set the default protector
via SilverStripe's config system. This will update any Form instances that have
spam protection hooks with that protector.

*mysite/_config/spamprotection.yml*

---
name: spamprotection
---
FormSpamProtectionExtension:
default_spam_protector: MollomSpamProtector

To add spam protection to your form instance call `enableSpamProtection`.

// your existing form code
$form = new Form( .. );
$form->enableSpamProtection();

The logic to perform the actual spam validation is controlled by each of the
individual `SpamProtector` implementation since they each require a different
implementation client side or server side.

### Options

`enableSpamProtection` takes a hash of optional configuration values.

$form->enableSpamProtection(array(
'protector' => 'MathSpamProtector',
'name' => 'Captcha'
));

Options to configure are:

*`protector`* a class name string or class instance which implements
`SpamProtector`. Defaults to your
`FormSpamProtectionExtension.default_spam_protector` value.

*`name`* the form field name argument for the Captcha. Defaults to `Catcha`.
*`title`* title of the Captcha form field. Defaults to `''`
*`mapping`* an array mapping of the Form fields to the standardized list of
field names. The list of standardized fields to pass to the spam protector are:

title
body
contextUrl
contextTitle
authorName
authorMail
authorUrl
authorIp
authorId

## Defining your own `SpamProtector`

Any class that implements `SpamProtector` and the `getFormField()` method can
be set as the spam protector. The `getFormField()` method returns the
`FormField` to be inserted into the `Form`. The `FormField` returned should be
in charge of the validation process.

<?php

class CustomSpamProtector implements SpamProtector {

public function getFormField($name = null, $title = null, $value = null) {
// CaptchaField is a imagined class which has some functionality.
// See silverstripe-mollom module for an example.
return new CaptchaField($name, $title, $value);
}
}


## Using Spam Protection with User Forms

This module provides an EditableSpamProtectionField wrapper which you can add
to your UserForm instances. After installing this module and running /dev/build
to rebuild the database, your Form Builder interface will have an option for
`Spam Protection Field`. The type of spam protection used will be based on your
currently selected SpamProtector instance.

## Releasing code with Spam Protection support

Spam protection is useful to provide but in some cases we do not want to require
the developer to use spam protection. In that case, modules can provide the
following pattern

$form = new Form(..);

if($form->hasExtension('FormSpamProtectionExtension')) {
$form->enableSpamProtection();
}
10 changes: 1 addition & 9 deletions _config.php
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -8,12 +8,4 @@
* *
* @package spamprotection * @package spamprotection
*/ */

Deprecation::notification_version('1.1', 'spamprotection');
/**
* If the comments module is installed then add the spam protection module
* to the comments form via this extension.
*
* Place this line in your mysite/_config.php
*/

// CommentingController::add_extension('CommentSpamProtection');
6 changes: 6 additions & 0 deletions _config/spamprotection.yml
Original file line number Original file line Diff line number Diff line change
@@ -0,0 +1,6 @@
---
name: spamprotection
---
Form:
extensions:
- FormSpamProtectionExtension
19 changes: 9 additions & 10 deletions code/EditableSpamProtectionField.php
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -6,38 +6,37 @@
* *
* @package spamprotection * @package spamprotection
*/ */
if(class_exists('EditableFormField')){ if(class_exists('EditableFormField')) {

class EditableSpamProtectionField extends EditableFormField { class EditableSpamProtectionField extends EditableFormField {


static $singular_name = 'Spam Protection Field'; static $singular_name = 'Spam Protection Field';


static $plural_name = 'Spam Protection Fields'; static $plural_name = 'Spam Protection Fields';


function getFormField() { public function getFormField() {
if($protector = SpamProtectorManager::get_spam_protector()) { if($protector = Config::inst()->get('FormSpamProtectionExtension', 'default_spam_protector')) {
if($protector) { $protector = Injector::inst()->create($protector);
$protector = new $protector();


return $protector->getFormField($this->Name, $this->Title, null); return $protector->getFormField($this->Name, $this->Title, null);
}
} }


return false; return false;
} }


function getFieldValidationOptions() { public function getFieldValidationOptions() {
return new FieldList(); return new FieldList();
} }


function getRequired() { public function getRequired() {
return false; return false;
} }


public function Icon() { public function Icon() {
return 'spamprotection/images/' . strtolower($this->class) . '.png'; return 'spamprotection/images/' . strtolower($this->class) . '.png';
} }


function showInReports() { public function showInReports() {
return false; return false;
} }
} }
Expand Down
23 changes: 0 additions & 23 deletions code/SpamProtector.php

This file was deleted.

34 changes: 0 additions & 34 deletions code/SpamProtectorField.php

This file was deleted.

99 changes: 20 additions & 79 deletions code/SpamProtectorManager.php
Original file line number Original file line Diff line number Diff line change
@@ -1,97 +1,38 @@
<?php <?php


/** /**
* This class is responsible for setting an system-wide spam protector field
* and add the protecter field to a form.
*
* @package spamprotection * @package spamprotection
*
* @deprecated 1.0
*/ */


class SpamProtectorManager { class SpamProtectorManager {


/**
* Current Spam Protector used on the site
*
* @var SpamProtector
*/
private static $spam_protector = null; private static $spam_protector = null;


/**
* Set the name of the spam protecter class
*
* @param String the name of protecter field class
*/
public static function set_spam_protector($protector) { public static function set_spam_protector($protector) {
Deprecation::notice('1.1',
'SpamProtectorManager::set_spam_protector() is deprecated. '.
'Use the new config system. FormSpamProtectorExtension.default_spam_protector'
);

self::$spam_protector = $protector; self::$spam_protector = $protector;
} }


/**
* Get the name of the spam protector class
*/
public static function get_spam_protector() { public static function get_spam_protector() {
Deprecation::notice('1.1',
'SpamProtectorManager::get_spam_protector() is deprecated'.
'Use the new config system. FormSpamProtectorExtension.default_spam_protector');

return self::$spam_protector; return self::$spam_protector;
} }


/** public static function update_form($form, $before = null, $fieldsToSpamServiceMapping = array(), $title = null, $rightTitle = null) {
* Add the spam protector field to a form Deprecation::notice('1.1',
* @param Form the form that the protecter field added into 'SpamProtectorManager::update_form is deprecated'.
* @param string the name of the field that the protecter field will be added in front of 'Please use $form->enableSpamProtection() for adding spamprotection'
* @param array an associative array );
* with the name of the spam web service's field, for example post_title, post_body, author_name
* and a string of field names return $form->enableSpamProtection();
* @param String Title for the captcha field
* @param String RightTitle for the captcha field
* @return SpamProtector object on success or null if the spamprotector class is not found
* also null if spamprotectorfield creation fails.
*/
static function update_form($form, $before = null, $fieldsToSpamServiceMapping = array(), $title = null, $rightTitle = null) {
$protectorClass = self::get_spam_protector();

// Don't update if no protector is set
if(!$protectorClass) return false;

if(!class_exists($protectorClass)) {
return user_error("Spam Protector class '$protectorClass' does not exist. Please define a valid Spam Protector", E_USER_WARNING);
}

try {
$protector = new $protectorClass();
$field = $protector->getFormField("Captcha", $title, null);
$field->setForm($form);
if ($rightTitle) $field->setRightTitle($rightTitle);

if($field) {
// update the mapping
$field->setFieldMapping($fieldsToSpamServiceMapping);

// add the form field
if($before && $form->Fields()->fieldByName($before)) {
$form->Fields()->insertBefore($field, $before);
}
else {
$form->Fields()->push($field);
}
}

} catch (Exception $e) {
return user_error("SpamProtectorManager::update_form(): '$protectorClass' is not correctly set up. " . $e, E_USER_WARNING);
}
}

/**
* Send Feedback to the Spam Protection. The level of feedback
* will depend on the Protector class.
*
* @param DataObject The Object which you want to send feedback about. Must have a
* SessionID field.
* @param String Feedback on the $object usually 'spam' or 'ham' for non spam entries
*/
static function send_feedback($object, $feedback) {
$protectorClass = self::get_spam_protector();

if(!$protectorClass) return false;

$protector = new $protectorClass();
return $protector->sendFeedback($object, $feedback);
} }
} }
Loading

0 comments on commit 440e30b

Please sign in to comment.