diff --git a/src/Common/AbstractAccountGateway.php b/src/Common/AbstractAccountGateway.php new file mode 100644 index 00000000..accc8d27 --- /dev/null +++ b/src/Common/AbstractAccountGateway.php @@ -0,0 +1,71 @@ + + * // Initialize the gateway + * $gateway->initialize(...); + * + * // Get the gateway parameters + * $parameters = $gateway->getParameters(); + * + * // lookup a user by access token + * if ($gateway->supportsFind()) { + * + * } + * + */ +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'); + } +} diff --git a/src/Common/AbstractGateway.php b/src/Common/AbstractGateway.php index adc91bff..e1eb3acb 100755 --- a/src/Common/AbstractGateway.php +++ b/src/Common/AbstractGateway.php @@ -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: - * - * - * 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); - * - * - * @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(); - } } diff --git a/src/Common/AbstractGenericGateway.php b/src/Common/AbstractGenericGateway.php new file mode 100644 index 00000000..a0f086a1 --- /dev/null +++ b/src/Common/AbstractGenericGateway.php @@ -0,0 +1,164 @@ +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: + * + * + * 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); + * + * + * @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(); + } +} diff --git a/src/Common/AbstractUserGateway.php b/src/Common/AbstractUserGateway.php new file mode 100644 index 00000000..4f673667 --- /dev/null +++ b/src/Common/AbstractUserGateway.php @@ -0,0 +1,62 @@ + + * // 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(); + * } + * + */ +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'); + } +} diff --git a/src/Common/GatewayFactory.php b/src/Common/GatewayFactory.php index 0b5ff250..754e9dfa 100644 --- a/src/Common/GatewayFactory.php +++ b/src/Common/GatewayFactory.php @@ -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); } } diff --git a/src/Common/Helper.php b/src/Common/Helper.php index b4d77514..6ed1c641 100644 --- a/src/Common/Helper.php +++ b/src/Common/Helper.php @@ -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; + } } diff --git a/src/Common/Message/AbstractGenericRequest.php b/src/Common/Message/AbstractGenericRequest.php new file mode 100644 index 00000000..3d503c95 --- /dev/null +++ b/src/Common/Message/AbstractGenericRequest.php @@ -0,0 +1,203 @@ + + * 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); + * + * + * Example -- validating and sending a request: + * + * + * 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. + * + * + */ +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; + } +} diff --git a/src/Common/Message/AbstractRequest.php b/src/Common/Message/AbstractRequest.php index 004a7757..08336077 100644 --- a/src/Common/Message/AbstractRequest.php +++ b/src/Common/Message/AbstractRequest.php @@ -1,6 +1,6 @@ * */ -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; - } }