Created
May 17, 2012 06:12
-
-
Save frankmullenger/2716899 to your computer and use it in GitHub Desktop.
Payment Module Outlines
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/* | |
* Payment | |
* ==================================================== | |
*/ | |
Payment::set_supported_methods(array( | |
'ChequePayment' => 'Cheque Or Pay On Site', | |
'PayPalPayment' => 'Pay Pal' | |
)); | |
if (Director::isLive()) { | |
Payment_Controller::set_environment('live'); | |
//TODO set PayPalPayment live API details | |
} | |
else if (Director::isDev()) { | |
Payment_Controller::set_environment('dev'); | |
//TODO set PayPalPayment sandbox account API details | |
} | |
else if (strpos($_SERVER['REQUEST_URI'], '/dev/tests') !== false) { //Unit testing | |
Payment_Controller::set_environment('test'); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
class OrderPage extends Page { | |
} | |
/** | |
* Represents a page with a form which a user fills out to process payment | |
*/ | |
class OrderPage_Controller extends Page_Controller { | |
function OrderForm() { | |
$fields = new FieldList(); | |
//Get form fields for payment methods | |
$paymentFields = Payment::combined_form_fields(); //Perhaps a nicer way of doing this? | |
$fields->push($paymentFields); | |
$actions = new FieldList( | |
new FormAction('ProcessOrder', 'Proceed to pay') | |
); | |
$validator = new OrderFormValidator(); | |
return new Form($this, 'OrderForm', $fields, $actions, $validator); | |
} | |
function ProcessOrder($data, $form) { | |
//What is the payment method? Find out from $data? | |
//What is the environment? How to choose Production / Sandbox / Mock? Factory pattern appropriate? | |
//$payment = new PayPalPayment_Gateway(); | |
//$paymentController = new PayPalPayment_Controller_Sandbox($payment); | |
$paymentClassName = $data['PaymentMethod']; | |
$paymentController = new PaymentFactory($paymentClassName); | |
$paymentProcessor = new PaymentProcessor($paymentController); | |
$result = $paymentProcessor->processPayment($data); | |
//If instant payment success | |
if ($result->isSuccess()) { | |
} | |
//If payment is being processed | |
//e.g gateway payment process redirected to another website (PayPal, DPS) | |
if ($result->isProcessing()) { | |
} | |
//If payment failed | |
if (!$result->isSuccess() && !$result->isProcessing()) { | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
class Payment { | |
const STATUS_SUCCESS = 1; | |
const STATUS_PROCESSING = 0; | |
const STATUS_FAILURE = -1; | |
/** | |
* Both Member and Object are optional. | |
* Object to represent object being paid for e.g: an order | |
* | |
* @var Array | |
*/ | |
public static $has_one = array( | |
'Member' => 'Member', | |
'Object' => 'Object' | |
); | |
} | |
class Payment_Controller extends Controller { | |
private static $environment; | |
/** | |
* Inject Payment | |
* | |
* @param Payment $payment | |
*/ | |
public function __construct(Payment $payment = null) { | |
//DI here | |
} | |
public static function set_environment(String $env) { | |
//Bounds checking on $env - one of: live / dev / test | |
//similar to Director::set_environment_type() | |
self::$environment = $env; | |
} | |
public static function environment() { | |
return self::$environment; | |
} | |
} | |
interface Payment_Controller_Interface { | |
public function getFormFields(); | |
public function getFormRequirements(); | |
public function processRequest(); | |
public function processResponse(); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
class PaymentFactory { | |
/** | |
* Map the environment to controller naming convention | |
* | |
* @see Director::set_environment_type() | |
* @var Array | |
*/ | |
private $envMapping = array( | |
'live' => '_Production', | |
'dev' => '_Sandbox', | |
'test' => '_Mock' | |
); | |
/** | |
* Create payment controller with payment injected into it. | |
* | |
* @param String $className Payment class name | |
* @param String $environment Environment | |
* @return Payment_Controller | |
*/ | |
public function __construct(String $paymentClassName, String $environment = null) { | |
//Create Payment class from className, bounds check that $className is typeof Payment | |
$payment = class_exists($paymentClassName) ? new $paymentClassName() : null; | |
//TODO the code below to create the Payment_Controller is a bit nasty, and while it would work for the circumstance: | |
//PayPalPayment has controller PayPalPayment_Controller_(Production/Sandbox/Mock) | |
//the circumstance: | |
//PayPalPayment_Gateway has controller PayPalPayment_Controller_(Production/Sandbox/Mock) | |
//is a bit of an unusual binding. | |
// | |
//We could use a convention like this but also provide a way to set the name of the corresponding Payment_Controller | |
//class in the Payment class so that strict naming conventions do not need to be adhered to. | |
//Create Payment_Controller from className and environment | |
if (!$environment) { | |
$environment = PaymentController::environment(); | |
} | |
$controllerSuffix = self::$envMapping[$environment]; | |
//TODO use mapping for env to controller naming convention to create controller class | |
$paymentControllerClassName = $className . '_Controller' . $controllerSuffix; | |
$paymentController = new $paymentControllerClassName($payment); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
class PaymentProcessor { | |
public function __construct(Payment_Controller $paymentController) { | |
//DI here | |
} | |
/** | |
* Process payment using injected payment controller. | |
* | |
* @param Array $data Form data | |
* @return PaymentProcessor_Result | |
*/ | |
function processPayment(Array $data) { | |
$payment = $this->paymentController->processRequest($data); | |
if ($payment->isSuccess()) { | |
return new PaymentProcessor_Success; | |
} | |
if ($payment->isProcessing()) { | |
return new PaymentProcessor_Processing; | |
} | |
if ($payment->isFailed()) { | |
return new PaymentProcessor_Failure; | |
} | |
} | |
} | |
abstract class PaymentProcessor_Result { | |
protected $value; | |
function __construct($value = null) { | |
$this->value = $value; | |
} | |
function getValue() { | |
return $this->value; | |
} | |
abstract function isSuccess(); | |
abstract function isProcessing(); | |
} | |
class PaymentProcessor_Success extends PaymentProcessor_Result { | |
function isSuccess() { | |
return true; | |
} | |
function isProcessing() { | |
return false; | |
} | |
} | |
class PaymentProcessor_Processing extends PaymentProcessor_Result { | |
function isSuccess() { | |
return false; | |
} | |
function isProcessing() { | |
return true; | |
} | |
} | |
class PaymentProcessor_Failure extends PaymentProcessor_Result { | |
function isSuccess() { | |
return false; | |
} | |
function isProcessing() { | |
return false; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
class PayPalPayment extends Payment { | |
} | |
class PayPalPayment_Gateway extends PayPalPayment { | |
/** | |
* Gets fields for processing via gateway e.g: fields required for PayPal API | |
* | |
* @return FieldList | |
*/ | |
public function getFormFields() { | |
} | |
public function getFormRequirements() { | |
} | |
} | |
class PayPalPayment_Merchant extends PayPalPayment { | |
/** | |
* Gets fields for processing credit card on site e.g: CreditCardField, month, year, cvv fields | |
* | |
* @return FieldList | |
*/ | |
public function getFormFields() { | |
} | |
public function getFormRequirements() { | |
} | |
} | |
class PayPalPayment_Controller extends Payment_Controller implements Payment_Controller_Interface { | |
public function getFormFields() { | |
return $this->Payment->getFormFields(); | |
} | |
/** | |
* Getting required fields, perhaps there is a better approach? | |
* Need to set rules for Validator on OrderPage::OrderForm() | |
* Maybe wait until form validation GSOC work completed? | |
*/ | |
public function getFormRequirements() { | |
} | |
public function processRequest() { | |
} | |
public function processResponse() { | |
} | |
} | |
class PayPalPayment_Controller_Production extends Payment_Controller { | |
/** | |
* Not sure what to return here | |
* | |
* @param Array $data | |
* @return Payment | |
*/ | |
public function processRequest(Array $data) { | |
if ($this->Payment instanceof PayPalPayment_Gateway) { | |
//send data to API with production account details | |
//save Payment with status 'processing' | |
} | |
if ($this->Payment instanceof PayPalPayment_Merchant) { | |
//save data to DB | |
} | |
//Maybe return Payment object? | |
return $this->Payment; | |
} | |
public function processResponse() { | |
} | |
} | |
class PayPalPayment_Controller_Sandbox extends Payment_Controller { | |
/** | |
* Probably pretty much identical to PayPalPayment_Controller_Production::processRequest() | |
* TODO find a way to keep this DRY - shared parent class? | |
*/ | |
public function processRequest(Array $data) { | |
//If payment gateway, send data to API with sandbox account details | |
//If payment merchant, save data | |
} | |
public function processResponse() { | |
} | |
} | |
class PayPalPayment_Controller_Mock extends Payment_Controller { | |
public function processRequest(Array $data) { | |
//If payment gateway, redirect to processResponse() with mocked HTTP response from gateway | |
//If payment merchant, save data | |
} | |
public function processResponse() { | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Class and ER diagram for this can be found here:
http://www.lucidchart.com/invitations/accept/4fb4603a-bc40-46dd-9740-3dfb0a7b1932