Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding support for user and account gateways #209

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 71 additions & 0 deletions src/Common/AbstractAccountGateway.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
<?php
/**
* Base Account Gateway class
*/
namespace Omnipay\Common;

/**
* Base user gateway class
*
* This abstract class should be extended by all account gatways
* throughout the Omnipay system. It enforces implementation of
* the GatewayInterface interface and defines a few common attributes
* and methods that all gateways should have.
*
* Example:
*
* <code>
* // Initialize the gateway
* $gateway->initialize(...);
*
* // Get the gateway parameters
* $parameters = $gateway->getParameters();
*
* // lookup a user by access token
* if ($gateway->supportsFind()) {
*
* }
* </code>
*/
abstract class AbstractAccountGateway extends AbstractGateway
{
/**
* Supports Find
*
* @return string
*/
public function supportsFind()
{
return method_exists($this, 'find');
}

/**
* Supports create
*
* @return string
*/
public function supportsCreate()
{
return method_exists($this, 'create');
}

/**
* Supports Modify
*
* @return string
*/
public function supportsModify()
{
return method_exists($this, 'modify');
}

/**
* Supports Delete
*
* @return string
*/
public function supportsDelete()
{
return method_exists($this, 'delete');
}
}
157 changes: 1 addition & 156 deletions src/Common/AbstractGateway.php
Original file line number Diff line number Diff line change
@@ -5,11 +5,6 @@

namespace Omnipay\Common;

use Omnipay\Common\Http\Client;
use Omnipay\Common\Http\ClientInterface;
use Symfony\Component\HttpFoundation\ParameterBag;
use Symfony\Component\HttpFoundation\Request as HttpRequest;

/**
* Base payment gateway class
*
@@ -41,92 +36,8 @@
* For further code examples see the *omnipay-example* repository on github.
*
*/
abstract class AbstractGateway implements GatewayInterface
abstract class AbstractGateway extends AbstractGenericGateway
{
use ParametersTrait;

/**
* @var ClientInterface
*/
protected $httpClient;

/**
* @var \Symfony\Component\HttpFoundation\Request
*/
protected $httpRequest;

/**
* Create a new gateway instance
*
* @param ClientInterface $httpClient A HTTP client to make API calls with
* @param HttpRequest $httpRequest A Symfony HTTP request object
*/
public function __construct(ClientInterface $httpClient = null, HttpRequest $httpRequest = null)
{
$this->httpClient = $httpClient ?: $this->getDefaultHttpClient();
$this->httpRequest = $httpRequest ?: $this->getDefaultHttpRequest();
$this->initialize();
}

/**
* Get the short name of the Gateway
*
* @return string
*/
public function getShortName()
{
return Helper::getGatewayShortName(get_class($this));
}

/**
* Initialize this gateway with default parameters
*
* @param array $parameters
* @return $this
*/
public function initialize(array $parameters = array())
{
$this->parameters = new ParameterBag;

// set default parameters
foreach ($this->getDefaultParameters() as $key => $value) {
if (is_array($value)) {
$this->parameters->set($key, reset($value));
} else {
$this->parameters->set($key, $value);
}
}

Helper::initialize($this, $parameters);

return $this;
}

/**
* @return array
*/
public function getDefaultParameters()
{
return array();
}

/**
* @return boolean
*/
public function getTestMode()
{
return $this->getParameter('testMode');
}

/**
* @param boolean $value
* @return $this
*/
public function setTestMode($value)
{
return $this->setParameter('testMode', $value);
}

/**
* @return string
*/
@@ -224,16 +135,6 @@ public function supportsVoid()
return method_exists($this, 'void');
}

/**
* Supports AcceptNotification
*
* @return boolean True if this gateway supports the acceptNotification() method
*/
public function supportsAcceptNotification()
{
return method_exists($this, 'acceptNotification');
}

/**
* Supports CreateCard
*
@@ -263,60 +164,4 @@ public function supportsUpdateCard()
{
return method_exists($this, 'updateCard');
}

/**
* Create and initialize a request object
*
* This function is usually used to create objects of type
* Omnipay\Common\Message\AbstractRequest (or a non-abstract subclass of it)
* and initialise them with using existing parameters from this gateway.
*
* Example:
*
* <code>
* class MyRequest extends \Omnipay\Common\Message\AbstractRequest {};
*
* class MyGateway extends \Omnipay\Common\AbstractGateway {
* function myRequest($parameters) {
* $this->createRequest('MyRequest', $parameters);
* }
* }
*
* // Create the gateway object
* $gw = Omnipay::create('MyGateway');
*
* // Create the request object
* $myRequest = $gw->myRequest($someParameters);
* </code>
*
* @param string $class The request class name
* @param array $parameters
* @return \Omnipay\Common\Message\AbstractRequest
*/
protected function createRequest($class, array $parameters)
{
$obj = new $class($this->httpClient, $this->httpRequest);

return $obj->initialize(array_replace($this->getParameters(), $parameters));
}

/**
* Get the global default HTTP client.
*
* @return ClientInterface
*/
protected function getDefaultHttpClient()
{
return new Client();
}

/**
* Get the global default HTTP request.
*
* @return HttpRequest
*/
protected function getDefaultHttpRequest()
{
return HttpRequest::createFromGlobals();
}
}
164 changes: 164 additions & 0 deletions src/Common/AbstractGenericGateway.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
<?php
/**
* Base generic gateway class
*/
namespace Omnipay\Common;

use Omnipay\Common\Http\Client;
use Omnipay\Common\Http\ClientInterface;
use Symfony\Component\HttpFoundation\ParameterBag;
use Symfony\Component\HttpFoundation\Request as HttpRequest;

abstract class AbstractGenericGateway implements GatewayInterface
{

use ParametersTrait;

/**
* @var ClientInterface
*/
protected $httpClient;

/**
* @var \Symfony\Component\HttpFoundation\Request
*/
protected $httpRequest;

/**
* Create a new gateway instance
*
* @param ClientInterface $httpClient A HTTP client to make API calls with
* @param HttpRequest $httpRequest A Symfony HTTP request object
*/
public function __construct(ClientInterface $httpClient = null, HttpRequest $httpRequest = null)
{
$this->httpClient = $httpClient ?: $this->getDefaultHttpClient();
$this->httpRequest = $httpRequest ?: $this->getDefaultHttpRequest();
$this->initialize();
}

/**
* Get the short name of the Gateway
*
* @return string
*/
public function getShortName()
{
return Helper::getGatewayShortName(get_class($this));
}

/**
* Initialize this gateway with default parameters
*
* @param array $parameters
* @return $this
*/
public function initialize(array $parameters = array())
{
$this->parameters = new ParameterBag;

// set default parameters
foreach ($this->getDefaultParameters() as $key => $value) {
if (is_array($value)) {
$this->parameters->set($key, reset($value));
} else {
$this->parameters->set($key, $value);
}
}

Helper::initialize($this, $parameters);

return $this;
}

/**
* @return array
*/
public function getDefaultParameters()
{
return array();
}

/**
* @return boolean
*/
public function getTestMode()
{
return $this->getParameter('testMode');
}

/**
* @param boolean $value
* @return $this
*/
public function setTestMode($value)
{
return $this->setParameter('testMode', $value);
}

/**
* Supports AcceptNotification
*
* @return boolean True if this gateway supports the acceptNotification() method
*/
public function supportsAcceptNotification()
{
return method_exists($this, 'acceptNotification');
}

/**
* Create and initialize a request object
*
* This function is usually used to create objects of type
* Omnipay\Common\Message\AbstractRequest (or a non-abstract subclass of it)
* and initialise them with using existing parameters from this gateway.
*
* Example:
*
* <code>
* class MyRequest extends \Omnipay\Common\Message\AbstractRequest {};
*
* class MyGateway extends \Omnipay\Common\AbstractGateway {
* function myRequest($parameters) {
* $this->createRequest('MyRequest', $parameters);
* }
* }
*
* // Create the gateway object
* $gw = Omnipay::create('MyGateway');
*
* // Create the request object
* $myRequest = $gw->myRequest($someParameters);
* </code>
*
* @param string $class The request class name
* @param array $parameters
* @return \Omnipay\Common\Message\AbstractRequest
*/
protected function createRequest($class, array $parameters)
{
$obj = new $class($this->httpClient, $this->httpRequest);

return $obj->initialize(array_replace($this->getParameters(), $parameters));
}

/**
* Get the global default HTTP client.
*
* @return ClientInterface
*/
protected function getDefaultHttpClient()
{
return new Client();
}

/**
* Get the global default HTTP request.
*
* @return HttpRequest
*/
protected function getDefaultHttpRequest()
{
return HttpRequest::createFromGlobals();
}
}
62 changes: 62 additions & 0 deletions src/Common/AbstractUserGateway.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
<?php
/**
* Base User Gateway class
*/
namespace Omnipay\Common;

/**
* Base user gateway class
*
* This abstract class should be extended by all user gatways
* throughout the Omnipay system. It enforces implementation of
* the GatewayInterface interface and defines a few common attributes
* and methods that all gateways should have.
*
* Example:
*
* <code>
* // Initialize the gateway
* $gateway->initialize(...);
*
* // Get the gateway parameters
* $parameters = $gateway->getParameters();
*
* // lookup a user by access token
* if ($gateway->supportsLookUp()) {
* $request = $gateway->lookUp();
* $response = $request->send();
* }
* </code>
*/
abstract class AbstractUserGateway extends AbstractGenericGateway
{
/**
* Supports LookUp
*
* @return boolean Tru if this gateway has the lookUp() method
*/
public function supportsFind()
{
return method_exists($this, 'find');
}

/**
* Supports modify
*
* @return boolean True if this gateway has the modify() method
*/
public function supportsModify()
{
return method_exists($this, 'modify');
}

/**
* Supports register
*
* @return boolean True if this gateway has the register() method
*/
public function supportsRegister()
{
return method_exists($this, 'register');
}
}
85 changes: 82 additions & 3 deletions src/Common/GatewayFactory.php
Original file line number Diff line number Diff line change
@@ -79,12 +79,91 @@ public function register($className)
*/
public function create($class, ClientInterface $httpClient = null, HttpRequest $httpRequest = null)
{
$class = Helper::getGatewayClassName($class);
return self::resolveClass(
$class,
'getGatewayClassName',
$httpClient,
$httpRequest
);
}

/**
* Alias for the create method
* @param string $class Gateway name
* @param ClientInterface|null $httpClient A HTTP Client implementation
* @param HttpRequest|null $httpRequest A Symfony HTTP Request implementation
* @return GatewayInterface An object of class $class is created and returned
*/
public function payment($class, ClientInterface $httpClient = null, HttpRequest $httpRequest = null)
{
return $this->create($class, $httpClient, $httpRequest);
}

/**
* Create a new account gateway instance
*
* @param string $class Gateway name
* @param ClientInterface|null $httpClient A HTTP Client implementation
* @param HttpRequest|null $httpRequest A Symfony HTTP Request implementation
* @return AccountGatewayInterface An object of class $class is created and returned
*/
public function account($class, ClientInterface $httpClient = null, HttpRequest $httpRequest = null)
{
return self::resolveClass(
$class,
'getAccountGatewayClassName',
$httpClient,
$httpRequest
);
}

/**
* Create a new user gateway instance
*
* @param string $class Gateway name
* @param ClientInterface|null $httpClient A HTTP Client implementation
* @param HttpRequest|null $httpRequest A Symfony HTTP Request implementation
* @return AccountGatewayInterface An object of class $class is created and returned
*/
public function user($class, ClientInterface $httpClient = null, HttpRequest $httpRequest = null)
{
return self::resolveClass(
$class,
'getUserGatewayClassName',
$httpClient,
$httpRequest
);
}

/**
* Resolves a class shortname by implementing a helper method to get
* the full class name, checking that the class exists, and passing
* the rest off to create the class
* @param string $class Gateway name
* @param string $helperMethod the helper method to get the full class name
* @param ClientInterface|null $httpClient A HTTP Client implementation
* @param HttpRequest|null $httpRequest A Symfony HTTP Request implementation
* @return object the new class, what ever it might be
*/
// phpcs:ignore
protected static function resolveClass($class, $helperMethod, ClientInterface $httpClient = null, HttpRequest $httpRequest = null)
{
$class = Helper::$helperMethod($class);
self::checkClassExists($class);

return new $class($httpClient, $httpRequest);
}

/**
* Checks that fully resolved class name exists
* @param string $class the classname to check
* @throws RuntimeException if the class does not exist
* @return void
*/
protected static function checkClassExists($class)
{
if (!class_exists($class)) {
throw new RuntimeException("Class '$class' not found");
}

return new $class($httpClient, $httpRequest);
}
}
128 changes: 128 additions & 0 deletions src/Common/Helper.php
Original file line number Diff line number Diff line change
@@ -15,6 +15,20 @@
*/
class Helper
{
/**
* Sets the account gateway suffix so that a namespace might
* look like '\Omnipay\Test\Account\Gateway'
* @var string
*/
protected static $accountNamespaceSuffix = 'Account';

/**
* Sets the user gateway suffix so that a namespace might
* look like '\Omnipay\Test\User\Gateway'
* @var string
*/
protected static $userNamespaceSuffix = 'User';

/**
* Convert a string to camelCase. Strings already in camelCase will not be harmed.
*
@@ -139,4 +153,118 @@ public static function getGatewayClassName($shortName)

return '\\Omnipay\\'.$shortName.'Gateway';
}

/**
* Gets the gateway name for account processes
*
* @param string $shortName the short gateway name
* @return string the full namespaced gateway class name
*/
public static function getAccountGatewayClassName($shortName)
{
return self::gatewayClassNameModify(
self::getGatewayClassName($shortName),
self::$accountNamespaceSuffix
);
}

/**
* Gets the gateway name for user processes
*
* @param string $shortName the short gateway name
* @return string the full namespaced gateway class name
*/
public static function getUserGatewayClassName($shortName)
{
return self::gatewayClassNameModify(
self::getGatewayClassName($shortName),
self::$userNamespaceSuffix
);
}

/**
* Appends to the namespace of the gateway class name
*
* @param string $classname the full classname
* @param string $appendWith what to add to the classname just before \\Gateway
* @return string
*/
public static function gatewayClassNameModify($classname, $appendWith = '')
{
$replaceWith = '\\Gateway';
if (!empty($appendWith)) {
$replaceWith = '\\' . $appendWith . $replaceWith;
}

return preg_replace('/\\\Gateway/', $replaceWith, $classname);
}

/**
* gets the shortname for an account gateway
*
* @param string $className the full classname
* @return string
*/
public static function getAccountGatewayShortName($className)
{
return self::replaceGatewaySuffix(
$className,
self::$accountNamespaceSuffix
);
}

/**
* Get's the shortname for a user gateway
*
* @param string $className the full classname
* @return string
*/
public static function getUserGatewayShortName($className)
{
return self::replaceGatewaySuffix(
$className,
self::$userNamespaceSuffix
);
}

/**
* Replaces the gateway suffix if one had been appended with gatewayClassNameModify
*
* @param string $classname the full classname
* @param string $appended the string that had been added to the classname just before \\Gateway
* @return string
*/
public static function replaceGatewaySuffix($className, $appended = '')
{
// trim any leading backslashes
$testClassName = ltrim($className, '\\');

$suffix = '\\Gateway';

if (!empty($appended)) {
// first add our
if (0 !== strpos($appended, '\\')) {
$appended = '\\' . $appended;
}

$suffix = $appended . $suffix;
}

if (0 === strpos($testClassName, 'Omnipay\\')) {
return trim(
str_replace(
'\\',
'_',
substr(
$testClassName,
8,
-(strlen($suffix))
)
),
'_'
);
}

return $className;
}
}
203 changes: 203 additions & 0 deletions src/Common/Message/AbstractGenericRequest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,203 @@
<?php
/**
* Abstract request class
*/
namespace Omnipay\Common\Message;

use Omnipay\Common\Exception\RuntimeException;
use Omnipay\Common\Helper;
use Omnipay\Common\Http\Client;
use Omnipay\Common\Http\ClientInterface;
use Omnipay\Common\ParametersTrait;
use Symfony\Component\HttpFoundation\ParameterBag;
use Symfony\Component\HttpFoundation\Request as HttpRequest;

/**
* Abstract Payment Request
*
* This abstract class implements RequestInterface and defines a basic
* set of functions that all Omnipay Requests are intended to include.
*
* Requests of this class are usually created using the createRequest
* function of the gateway and then actioned using methods within this
* class or a class that extends this class.
*
* Example -- creating a request:
*
* <code>
* class MyRequest extends \Omnipay\Common\Message\AbstractRequest {};
*
* class MyGateway extends \Omnipay\Common\AbstractGateway {
* function myRequest($parameters) {
* $this->createRequest('MyRequest', $parameters);
* }
* }
*
* // Create the gateway object
* $gw = Omnipay::create('MyGateway');
*
* // Create the request object
* $myRequest = $gw->myRequest($someParameters);
* </code>
*
* Example -- validating and sending a request:
*
* <code>
* try {
* $myRequest->validate();
* $myResponse = $myRequest->send();
* } catch (InvalidRequestException $e) {
* print "Something went wrong: " . $e->getMessage() . "\n";
* }
* // now do something with the $myResponse object, test for success, etc.
* </code>
*
*/
abstract class AbstractGenericRequest implements RequestInterface
{
use ParametersTrait {
setParameter as traitSetParameter;
}

/**
* The request client.
*
* @var ClientInterface
*/
protected $httpClient;

/**
* The HTTP request object.
*
* @var \Symfony\Component\HttpFoundation\Request
*/
protected $httpRequest;

/**
* An associated ResponseInterface.
*
* @var ResponseInterface
*/
protected $response;

/**
* Create a new Request
*
* @param ClientInterface $httpClient A HTTP client to make API calls with
* @param HttpRequest $httpRequest A Symfony HTTP request object
*/
public function __construct(ClientInterface $httpClient, HttpRequest $httpRequest)
{
$this->httpClient = $httpClient;
$this->httpRequest = $httpRequest;
$this->initialize();
}

/**
* Initialize the object with parameters.
*
* If any unknown parameters passed, they will be ignored.
*
* @param array $parameters An associative array of parameters
*
* @return $this
* @throws RuntimeException
*/
public function initialize(array $parameters = array())
{
if (null !== $this->response) {
throw new RuntimeException('Request cannot be modified after it has been sent!');
}

$this->parameters = new ParameterBag;

Helper::initialize($this, $parameters);

return $this;
}

/**
* Set a single parameter
*
* @param string $key The parameter key
* @param mixed $value The value to set
* @return $this
* @throws RuntimeException if a request parameter is modified after the request has been sent.
*/
protected function setParameter($key, $value)
{
if (null !== $this->response) {
throw new RuntimeException('Request cannot be modified after it has been sent!');
}

return $this->traitSetParameter($key, $value);
}

/**
* Gets the test mode of the request from the gateway.
*
* @return boolean
*/
public function getTestMode()
{
return $this->getParameter('testMode');
}

/**
* Sets the test mode of the request.
*
* @param boolean $value True for test mode on.
* @return $this
*/
public function setTestMode($value)
{
return $this->setParameter('testMode', $value);
}

/**
* Get the request description.
*
* @return string
*/
public function getDescription()
{
return $this->getParameter('description');
}

/**
* Sets the request description.
*
* @param string $value
* @return $this
*/
public function setDescription($value)
{
return $this->setParameter('description', $value);
}

/**
* Send the request
*
* @return ResponseInterface
*/
public function send()
{
$data = $this->getData();

return $this->sendData($data);
}

/**
* Get the associated Response.
*
* @return ResponseInterface
*/
public function getResponse()
{
if (null === $this->response) {
throw new RuntimeException('You must call send() before accessing the Response!');
}

return $this->response;
}
}
160 changes: 4 additions & 156 deletions src/Common/Message/AbstractRequest.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?php
/**
* Abstract Request
* Abstract Payment Request
*/

namespace Omnipay\Common\Message;
@@ -12,18 +12,11 @@
use Money\Number;
use Money\Parser\DecimalMoneyParser;
use Omnipay\Common\CreditCard;
use Omnipay\Common\Exception\InvalidRequestException;
use Omnipay\Common\Exception\RuntimeException;
use Omnipay\Common\Helper;
use Omnipay\Common\Http\Client;
use Omnipay\Common\Http\ClientInterface;
use Omnipay\Common\ItemBag;
use Omnipay\Common\ParametersTrait;
use Symfony\Component\HttpFoundation\ParameterBag;
use Symfony\Component\HttpFoundation\Request as HttpRequest;
use Omnipay\Common\Exception\InvalidRequestException;

/**
* Abstract Request
* Abstract Payment Request
*
* This abstract class implements RequestInterface and defines a basic
* set of functions that all Omnipay Requests are intended to include.
@@ -63,32 +56,8 @@
* </code>
*
*/
abstract class AbstractRequest implements RequestInterface
abstract class AbstractRequest extends AbstractGenericRequest
{
use ParametersTrait {
setParameter as traitSetParameter;
}

/**
* The request client.
*
* @var ClientInterface
*/
protected $httpClient;

/**
* The HTTP request object.
*
* @var \Symfony\Component\HttpFoundation\Request
*/
protected $httpRequest;

/**
* An associated ResponseInterface.
*
* @var ResponseInterface
*/
protected $response;

/**
* @var ISOCurrencies
@@ -105,80 +74,6 @@ abstract class AbstractRequest implements RequestInterface
*/
protected $negativeAmountAllowed = false;

/**
* Create a new Request
*
* @param ClientInterface $httpClient A HTTP client to make API calls with
* @param HttpRequest $httpRequest A Symfony HTTP request object
*/
public function __construct(ClientInterface $httpClient, HttpRequest $httpRequest)
{
$this->httpClient = $httpClient;
$this->httpRequest = $httpRequest;
$this->initialize();
}

/**
* Initialize the object with parameters.
*
* If any unknown parameters passed, they will be ignored.
*
* @param array $parameters An associative array of parameters
*
* @return $this
* @throws RuntimeException
*/
public function initialize(array $parameters = array())
{
if (null !== $this->response) {
throw new RuntimeException('Request cannot be modified after it has been sent!');
}

$this->parameters = new ParameterBag;

Helper::initialize($this, $parameters);

return $this;
}

/**
* Set a single parameter
*
* @param string $key The parameter key
* @param mixed $value The value to set
* @return $this
* @throws RuntimeException if a request parameter is modified after the request has been sent.
*/
protected function setParameter($key, $value)
{
if (null !== $this->response) {
throw new RuntimeException('Request cannot be modified after it has been sent!');
}

return $this->traitSetParameter($key, $value);
}

/**
* Gets the test mode of the request from the gateway.
*
* @return boolean
*/
public function getTestMode()
{
return $this->getParameter('testMode');
}

/**
* Sets the test mode of the request.
*
* @param boolean $value True for test mode on.
* @return $this
*/
public function setTestMode($value)
{
return $this->setParameter('testMode', $value);
}

/**
* Get the card.
*
@@ -445,27 +340,6 @@ public function formatCurrency($amount)
return $formatter->format($money);
}

/**
* Get the request description.
*
* @return string
*/
public function getDescription()
{
return $this->getParameter('description');
}

/**
* Sets the request description.
*
* @param string $value
* @return $this
*/
public function setDescription($value)
{
return $this->setParameter('description', $value);
}

/**
* Get the transaction ID.
*
@@ -675,30 +549,4 @@ public function setPaymentMethod($value)
{
return $this->setParameter('paymentMethod', $value);
}

/**
* Send the request
*
* @return ResponseInterface
*/
public function send()
{
$data = $this->getData();

return $this->sendData($data);
}

/**
* Get the associated Response.
*
* @return ResponseInterface
*/
public function getResponse()
{
if (null === $this->response) {
throw new RuntimeException('You must call send() before accessing the Response!');
}

return $this->response;
}
}