From 3236595a24e3d4c62b8b40acaf91285068ad64ed Mon Sep 17 00:00:00 2001 From: gabriel Date: Fri, 1 May 2020 21:49:50 +0100 Subject: [PATCH 1/2] add cutom route functionality, add tests for custom routes, update readme --- README.md | 47 +++++++++++++++++++++++++++++++++ src/Paystack.php | 21 +++++++++++++++ src/Paystack/Helpers/Router.php | 20 ++++++++++++-- tests/Helpers/RouterTest.php | 35 +++++++++++++++++++++++- tests/Mock/CustomRoute.php | 21 +++++++++++++++ tests/PaystackTest.php | 28 ++++++++++++++++++++ 6 files changed, 169 insertions(+), 3 deletions(-) create mode 100644 tests/Mock/CustomRoute.php diff --git a/README.md b/README.md index 88ee071..04507b3 100644 --- a/README.md +++ b/README.md @@ -276,6 +276,53 @@ Add Custom Fields by calling the `withCustomField` function (These will shown on Finally call `build()` to get your JSON metadata string. +### Using Custom Routes + +You can add your custom routes by calling the `useRoutes` method on the paystack object. + +```php + $paystack = new Yabacon\Paystack(SECRET_KEY); + $paystack->useRoutes(["charge" => Charge::class]); + + $paystack->charge->chargeMobileMoney([ + 'email' => 'hey@example.com', + 'reference' => 'trnx_ref', + 'amount' => 50 * 100, + 'currency' => 'GHS', + 'mobile_money' => [ + 'phone' => '5533467', + 'provider' => 'MTN' + ] + ]); +``` +Your custom routes should implement the ```Yabacon\Paystack\Contracts\RouteInterface``` contract + +```php + class Charge implements RouteInterface + { + + public static function root() + { + return '/charge'; + } + + public static function chargeMobileMoney() + { + return [ + RouteInterface::METHOD_KEY => RouteInterface::POST_METHOD, + RouteInterface::ENDPOINT_KEY => Charge::root(), + RouteInterface::PARAMS_KEY => [ + 'email', + 'reference', + 'amount', + 'currency', + 'mobile_money', + ], + ]; + } + } +``` + ## Change log Please see [CHANGELOG](CHANGELOG.md) for more information what has changed recently. diff --git a/src/Paystack.php b/src/Paystack.php index 7367e84..e28facc 100644 --- a/src/Paystack.php +++ b/src/Paystack.php @@ -3,12 +3,14 @@ namespace Yabacon; use \Yabacon\Paystack\Helpers\Router; +use Yabacon\Paystack\Contracts\RouteInterface; use \Yabacon\Paystack\Exception\ValidationException; class Paystack { public $secret_key; public $use_guzzle = false; + public $custom_routes = []; public static $fallback_to_file_get_contents = true; const VERSION="2.1.19"; @@ -25,6 +27,25 @@ public function useGuzzle() $this->use_guzzle = true; } + public function useRoutes(array $routes) + { + foreach ($routes as $route => $class) { + if (! is_string($route)) { + throw new \InvalidArgumentException( + 'Custom routes should map to a route class' + ); + } + + if (! in_array(RouteInterface::class, class_implements($class))) { + throw new \InvalidArgumentException( + 'Custom route class ' . $class . 'should implement ' . RouteInterface::class + ); + } + } + + $this->custom_routes = $routes; + } + public static function disableFileGetContentsFallback() { Paystack::$fallback_to_file_get_contents = false; diff --git a/src/Paystack/Helpers/Router.php b/src/Paystack/Helpers/Router.php index 9ba97a6..1f6db78 100644 --- a/src/Paystack/Helpers/Router.php +++ b/src/Paystack/Helpers/Router.php @@ -53,14 +53,16 @@ public static function singularFor($method) public function __construct($route, $paystackObj) { - if (!in_array($route, Router::$ROUTES)) { + $routes = $this->getAllRoutes($paystackObj); + + if (!in_array($route, $routes)) { throw new ValidationException( "Route '{$route}' does not exist." ); } $this->route = strtolower($route); - $this->route_class = 'Yabacon\\Paystack\\Routes\\' . ucwords($route); + $this->route_class = $this->getRouteClass($paystackObj); $mets = get_class_methods($this->route_class); if (empty($mets)) { @@ -86,4 +88,18 @@ public function __construct($route, $paystackObj) $this->methods[$mtd] = \Closure::bind($mtdFunc, $this, get_class()); } } + + private function getAllRoutes($paystackObj) + { + return array_merge(static::$ROUTES, array_keys($paystackObj->custom_routes)); + } + + private function getRouteClass($paystackObj) + { + try { + return $paystackObj->custom_routes[$this->route]; + } catch (\Exception $execption) { + return 'Yabacon\\Paystack\\Routes\\' . ucwords($this->route); + } + } } diff --git a/tests/Helpers/RouterTest.php b/tests/Helpers/RouterTest.php index bdccceb..84149d5 100644 --- a/tests/Helpers/RouterTest.php +++ b/tests/Helpers/RouterTest.php @@ -1,8 +1,9 @@ assertEmpty(array_diff($singulars, $available)); } + + public function testThatCustomRouteCanBeCalled() + { + $custom_route = ['charge' => CustomRoute::class]; + $p = new Paystack('sk_'); + + $p->useRoutes($custom_route); + + $r = $p->charge; + $reflection_property = new \ReflectionProperty($r, "methods"); + $reflection_property->setAccessible(true); + $methods = $reflection_property->getValue($r); + + $this->assertTrue(in_array("test_route", array_keys($methods))); + $this->assertTrue(is_callable($methods["test_route"])); + } + + public function testThatOriginalRoutesCanBeCalledWhenCustomRouteIsSet() + { + $custom_route = ['charge' => CustomRoute::class]; + $p = new Paystack('sk_'); + + $p->useRoutes($custom_route); + + $r = $p->balance; + $reflection_property = new \ReflectionProperty($r, "methods"); + $reflection_property->setAccessible(true); + $methods = $reflection_property->getValue($r); + + $this->assertTrue(in_array("getList", array_keys($methods))); + $this->assertTrue(is_callable($methods["getList"])); + } } diff --git a/tests/Mock/CustomRoute.php b/tests/Mock/CustomRoute.php new file mode 100644 index 0000000..3fc9a46 --- /dev/null +++ b/tests/Mock/CustomRoute.php @@ -0,0 +1,21 @@ + RouteInterface::GET_METHOD, + RouteInterface::ENDPOINT_KEY => CustomRoute::root(), + ]; + } +} diff --git a/tests/PaystackTest.php b/tests/PaystackTest.php index 752eab0..56cf654 100644 --- a/tests/PaystackTest.php +++ b/tests/PaystackTest.php @@ -3,6 +3,7 @@ use Yabacon\Paystack; use Yabacon\Paystack\Helpers\Router; +use Yabacon\Paystack\Test\Mock\CustomRoute; use \Yabacon\Paystack\Exception\ValidationException; class PaystackTest extends \PHPUnit_Framework_TestCase @@ -73,4 +74,31 @@ public function testFetchWithInvalidParams3() $this->expectException(\InvalidArgumentException::class); $this->assertNull($r->customers(1)); } + + public function testUseRoutes() + { + $custom_routes = ['custom_route' => CustomRoute::class]; + + $r = new Paystack('sk_'); + $r->useRoutes($custom_routes); + $this->assertTrue($r->custom_routes == $custom_routes); + } + + public function testUseRoutesWithInvalidParams1() + { + $custom_routes = ['custom_route']; + $r = new Paystack('sk_'); + $this->expectException(\InvalidArgumentException::class); + $r->useRoutes($custom_routes); + $this->assertNull($r->custom_routes); + } + + public function testUseRoutesWithInvalidParams2() + { + $custom_routes = ['custom_route' => Paystack::class]; + $r = new Paystack('sk_'); + $this->expectException(\InvalidArgumentException::class); + $r->useRoutes($custom_routes); + $this->assertNull($r->custom_routes); + } } From c68484057c33f43217576ab0f3c23f5731ae75ba Mon Sep 17 00:00:00 2001 From: gabriel Date: Mon, 4 May 2020 09:53:52 +0100 Subject: [PATCH 2/2] prevent existing routes from being overshadowed --- src/Paystack.php | 8 +++++++- tests/PaystackTest.php | 9 +++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/Paystack.php b/src/Paystack.php index e28facc..8995b0e 100644 --- a/src/Paystack.php +++ b/src/Paystack.php @@ -3,7 +3,7 @@ namespace Yabacon; use \Yabacon\Paystack\Helpers\Router; -use Yabacon\Paystack\Contracts\RouteInterface; +use \Yabacon\Paystack\Contracts\RouteInterface; use \Yabacon\Paystack\Exception\ValidationException; class Paystack @@ -36,6 +36,12 @@ public function useRoutes(array $routes) ); } + if (in_array($route, Router::$ROUTES)) { + throw new \InvalidArgumentException( + $route . ' is already an existing defined route' + ); + } + if (! in_array(RouteInterface::class, class_implements($class))) { throw new \InvalidArgumentException( 'Custom route class ' . $class . 'should implement ' . RouteInterface::class diff --git a/tests/PaystackTest.php b/tests/PaystackTest.php index 56cf654..33d65c0 100644 --- a/tests/PaystackTest.php +++ b/tests/PaystackTest.php @@ -101,4 +101,13 @@ public function testUseRoutesWithInvalidParams2() $r->useRoutes($custom_routes); $this->assertNull($r->custom_routes); } + + public function testUseRoutesWithInvalidParams3() + { + $custom_routes = ['balance' => CustomRoute::class]; + $r = new Paystack('sk_'); + $this->expectException(\InvalidArgumentException::class); + $r->useRoutes($custom_routes); + $this->assertNull($r->custom_routes); + } }