Skip to content

Commit

Permalink
Merge branch 'vote-abstraction' of https://github.com/TomSpeak/silver…
Browse files Browse the repository at this point in the history
…stripe-polls into TomSpeak-vote-abstraction

fixes #20

Conflicts:
	Readme.md
	code/Poll.php
  • Loading branch information
tomspeak committed Jan 27, 2014
2 parents 052c0d7 + 459f27e commit 595373c
Show file tree
Hide file tree
Showing 9 changed files with 118 additions and 40 deletions.
13 changes: 11 additions & 2 deletions Readme.md
Expand Up @@ -16,7 +16,7 @@ master: SilverStripe 3.0.x

## Features

- Each visitor, determined by browser cookie, can only vote once
- By default, each visitor, determined by browser cookie, can only vote once
- Uses [Google chart API](http://code.google.com/apis/chart/)
- Supports single and multiple-choice polls

Expand Down Expand Up @@ -116,7 +116,7 @@ default setup:
$Poll.Description
<% end_if %>

<% if $Poll.isVoted %>
<% if $Poll.hasVoted %>
$Chart
<% else %>
$DefaultForm
Expand Down Expand Up @@ -183,3 +183,12 @@ Object::add_extension('PollForm', 'PollFormDecorator');
Finally, for a full control of the poll form and the results subclass the PollForm - you can then create form-specific
templates or work on the basis of redefining the **getChart** method. This way you can also create multiple parallel
presentation layers for the polls.

#### Custom Vote Handling

Using the Vote_Backend we can define our own vote handler. The votehandler takes care of storing votes and the logic of
whether a user has voted before.

See `DatabaseVoteHandler` for an example.


2 changes: 2 additions & 0 deletions _config.php
@@ -1 +1,3 @@
<?php

Deprecation::notification_version('0.2', 'polls');
42 changes: 42 additions & 0 deletions code/CookieVoteHandler.php
@@ -0,0 +1,42 @@
<?php

/**
* Default vote handler.
*
* If a user votes for a poll and Cookie is stored on their computer which assigns
* that they have voted for a particular poll ID
*
*/
class CookieVoteHandler extends Vote_Backend {

const COOKIE_PREFIX = 'SSPoll_';

/**
* Generates a cookie to indicate the user has voted on the poll.
*/
public function markAsVoted() {
Cookie::set(self::COOKIE_PREFIX . $this->getPoll()->ID, 1);
}

/**
* Checks to see if the user can vote. Verified by checking whether or not
* the user has voted before. Which is the only limitation of this
* cookie based implementation.
*
* @return bool
*/
public function canVote() {
return !$this->hasVoted();
}

/**
* Checks to see if the user has a cookie set which is generated when
* they vote on a poll
*
* @return bool
*/
public function hasVoted() {
return (bool) Cookie::get(self::COOKIE_PREFIX . $this->getPoll()->ID);
}

}
61 changes: 27 additions & 34 deletions code/Poll.php
Expand Up @@ -38,6 +38,16 @@ class Poll extends DataObject implements PermissionProvider {

static $default_sort = 'Created DESC';

private static $vote_handler_class = 'CookieVoteHandler';

public $voteHandler;

public function __construct($record = null, $isSingleton = false, $model = null) {
parent::__construct($record, $isSingleton, $model);
//create the voteHandler
$this->voteHandler = Injector::inst()->create(self::config()->get('vote_handler_class'), $this);
}

function getCMSFields() {

if($this->ID != 0) {
Expand Down Expand Up @@ -114,34 +124,12 @@ function getCMSFields() {
return $fields;
}

/**
* Returns the number of total votes, the sum of all votes from {@link PollChoice}s' votes
* TODO: rewrite as Aggregate, so it uses in-built cache?
*
* @return int
*/
private $_getTotalVotesCache;

function getTotalVotes($useCache = true) {
if (!isset($_getTotalVotesCache) || !$useCache) {
$_getTotalVotesCache = $this->Choices()->sum('Votes');
}

return $_getTotalVotesCache;
function getTotalVotes() {
return $this->Choices()->sum('Votes');
}

/**
* Find out what is the maximum amount of votes received for one of the options.
* TODO: rewrite as Aggregate, so it uses in-built cache?
*/
private $_getMaxVotesCache;

function getMaxVotes($useCache = true) {
if (!isset($_getMaxVotesCache) || !$useCache) {
$_getMaxVotesCache = $this->Choices()->max('Votes');
}

return $_getMaxVotesCache;
function getMaxVotes() {
return $this->Choices()->max('Votes');
}

/**
Expand All @@ -157,15 +145,16 @@ function markAsVoted() {
* @param integer
* @return bool
*/
function hasVoted() {
return $this->voteHandler->hasVoted();
}

/**
* @deprecated
*/
function isVoted() {
$cookie = Cookie::get(self::COOKIE_PREFIX . $this->ID);

if($cookie) {
return true;
}
else {
return false;
}
Deprecation::notice('0.1', "isVoted has been deprecated, please use hasVoted");
return $this->hasVoted();
}

/**
Expand Down Expand Up @@ -199,4 +188,8 @@ public function canEdit($member = null) {
public function canDelete($member = null) {
return Permission::check('MANAGE_POLLS', 'any', $member);
}

public function canVote() {
return $this->voteHandler->canVote();
}
}
2 changes: 1 addition & 1 deletion code/PollChoice.php
Expand Up @@ -49,7 +49,7 @@ function getCMSFields() {
function addVote() {
$poll = $this->Poll();

if($poll && !$poll->isVoted()) {
if($poll && !$poll->hasVoted()) {
$this->Votes++;
$this->write();
}
Expand Down
2 changes: 1 addition & 1 deletion code/PollForm.php
Expand Up @@ -129,7 +129,7 @@ function isForcedDisplay() {
* Collate the information from PollForm and Poll to figure out if the results should be shown.
*/
function getShouldShowResults() {
return $this->poll->isVoted() || $this->isForcedDisplay();
return $this->poll->hasVoted() || $this->isForcedDisplay();
}

/**
Expand Down
32 changes: 32 additions & 0 deletions code/Vote_Backend.php
@@ -0,0 +1,32 @@
<?php
/**
* A base class to allow hooking into the polling functionality
*
* @abstract
*
* @author Tom Speak <@tomspeak>
* @author Dan Hensby <@dhensby>
*/
abstract class Vote_Backend {

protected $poll;

public function __construct($poll) {
$this->setPoll($poll);
}

abstract function hasVoted();

abstract function canVote();

abstract function markAsVoted();

public function setPoll(Poll $poll) {
$this->poll = $poll;
}

public function getPoll() {
return $this->poll;
}

}
2 changes: 1 addition & 1 deletion tests/unit/PollChoiceTest.php
Expand Up @@ -23,7 +23,7 @@ function testAddVote() {
$choice = $this->ObjFromFixture('PollChoice', 'android');
$choice->addVote();
// This cannot be tested this way as it relies on cookies.
// $this->assertTrue($choice->Poll()->isVoted());
// $this->assertTrue($choice->Poll()->hasVoted());
$this->assertEquals($choice->Votes, 81, 'Vote count incremented');
}
}
Expand Down
2 changes: 1 addition & 1 deletion tests/unit/PollTest.php
Expand Up @@ -56,7 +56,7 @@ function testMarkAsVoted() {
/*
$mobilePoll = $this->ObjFromFixture('Poll', 'mobile-poll');
$mobilePoll->markAsVoted();
$this->assertTrue($mobilePoll->isVoted());
$this->assertTrue($mobilePoll->hasVoted());
*/
}
}

0 comments on commit 595373c

Please sign in to comment.