Building Classes to Abstract Functionality of API - php

I'm looking at building a set of classes to handle interactions with various similar but competing APIs. A good illustration of this would be for credit card processing. I want a class with methods like charge() or refund() that the application developer uses, independent of who the merchant processor is. Then I want to be able to build classes that handle the interaction with the specific merchant processor API.
So I might have one that interacts with the Stripe API, another for Authorize.Net, etc. Then some sort of master or wrapper class that abstracts the API specifics from the application developer.
In the past, I've done this with a wrapper class, where I created a class for each API using the same methods (with their respective API interactions), and then a wrapper class that is used in the application. A usage example might look like this:
$merchant = new Merchant( 'Stripe' );
$merchant->set_credentials( 'api_user', 'api_password' );
$merchant->set_cc( '4111-1111-1111-1111' );
$merchant->set_exp( '0121' );
$merchant->set_amount( 100.00 );
$merchant->charge();
Instantiating this class with the value "Stripe" would mean that behind the scenes this class is passing the workload off to the appropriate class to handle this interaction.
My goals are to:
Abstract the API from the application developer from having to know
anything about the specific processor, other than the name (so they can
create an instance of the class), or having to make any code changes if the
processor changes.
As I end up needing to support more merchant processors, be able to drop in
new classes to handle interactions with their API.
Is a wrapper class the way to do this, or does PHP provide other more efficient mechanisms for handling this type of setup?

I would create an interface for your internal API, one implementation per external processor, and a factory class to create the right instance.
Code Example (PHP 7.1):
interface MerchantInterface {
public function set_credentials(string $username, string $password);
public function set_cc(string $number);
public function set_exp(string $number);
public function set_amount(float $amount);
public function charge();
}
class StripeMerchant implements MerchantInterface {
public function set_credentials(string $username, string $password) {}
public function set_cc(string $number) {}
public function set_exp(string $number) {}
public function set_amount(float $amount) {}
public function charge() {}
}
class AuthorizeNetMerchant implements MerchantInterface {
public function set_credentials(string $username, string $password) {}
public function set_cc(string $number) {}
public function set_exp(string $number) {}
public function set_amount(float $amount) {}
public function charge() {}
}
class MerchantFactory {
public const MERCHANT_STRIPE = 'Stripe';
public const MERCHANT_AUTHORIZE_NET = 'Authorize.Net';
public static function create(string $merchant): MerchantInterface {
switch ($merchant) {
case self::MERCHANT_STRIPE:
return new StripeMerchant();
case self::MERCHANT_AUTHORIZE_NET:
return new AuthorizeNetMerchant();
default:
throw new Exception('Unexpected Merchant');
}
}
}
$stripeMerchant = MerchantFactory::create(MerchantFactory::MERCHANT_STRIPE);
$authorizeNetMerchant = MerchantFactory::create(MerchantFactory::MERCHANT_AUTHORIZE_NET);
Depending on your requirements, you could also use the builder pattern instead of a factory to create your different instances. The builder would take care of your setters. That might be useful if you have many optional parameters (does not seem to be the case here) or you want to make your Merchants immutable.

Related

Symfony 4 multiple injections of HTTP Client to split into an abstract class and two separate classes

My class was always running on one HTTP client injection but then there become a need for another which has uses different base_uri so I assumed that it can be used like written underneath.
public function __construct(string $key, HttpClientInterface $client, HttpClientInterface $secondClient)
{
$this->key = $key;
$this->client = $client;
$this->secondClient = $secondClient;
}
Same class also has some methods that are used for certain calculations.
public function method1()
{
$this->makeRequest($this->client, []);
}
public function method2()
{
$this->makeRequest($this->secondClient, []);
}
I was advised to create an abstract class and then another two classes like Client1 and Client2 that extend that abstract class.
My idea of that is that the abstract would look something like this:
abstract class AbstractClientClass
{
protected $key;
protected $client;
public function __construct($key, HttpClientInterface $client)
{
$this->key = $key;
$this->client = $client;
}
public function makeRequest($data): ResponseInterface
{
return $this->client->request(...);
}
}
So I assume method1 would go to Client1 class and the same with method2 and Client2 class. But does it make sense to name it a client anymore? And is this really the right way?
Also, how would I use these clients in my main class? Would I just instantiate both of them in construct method? Any suggestions or related documentation that could help me?
You don't really explain what are the conditions for the switch from one client to another. You must SOMEHOW know whether to use one, or the other. How do you know?
If the only moment you do know whether to use client1 or client2 is at runtime then well.. create an if.
if($condition1){ $client1->...} else{ $client2-> }
I would probably inject both clients into your own custom class ClientFactory.php
and give that client factory the knowledge how to decide when to use which
Assuming you CAN KNOW whether to use client1 or client2 from the $request data then do it like so
e.g.
class SomeController{
public function index(ClientFactory $cf, Request $request){
$client = $cf->getClient($request->toArray() /* if that works */);
}
you'd need to define the ClientFactory as a service as well I guess to be able to inject it.

Is having multiple services in constructor and service using repository a good way?

I would like to know If having multiple services injected in controllers constructor is wrong? Is there a way to make it more cleaner?
Example (UserController):
public function __construct(
UserService $userService, NewsService $newsService, PaginateService $paginateService, GroupsService $groupsService, HolidaysService $holidaysService,
CalendarService $calendarService
)
{
parent::__construct();
$this->userService = $userService;
$this->newsService = $newsService;
$this->paginateService = $paginateService;
$this->groupsService = $groupsService;
$this->holidaysService = $holidaysService;
$this->calendarService = $calendarService;
}
In addition to that I also would like to know if it is good to have service in which I inject the repository - for example: I have UserService and in constrcutor I'm injecting the UserRepository.
Example (UserService):
class UserService {
protected $userRepository;
function __construct(UserRespository $userRepository) {
$this->userRepository = $userRepository;
}
public function getUsers() {
$this->userRepository->getAllUsers();
}
}
I personally like to follow a pattern whereby a controller doesn't have any custom methods. Thus you end up with lots of very thin controllers and ultimately will prevent your above situation (one controller dependant on a large number of services).
so I would break up those services into controller use cases
with generic resource methods like index update store create edit destroy.
Another pattern I like to follow is using the app helper instead of injecting dependancies into the constructor.
so you can use app(calendarService::class)->method()
This results in less code and less stuff to forget.

Laravel: Service/Repository Pattern and duplicating code

In my project I have decided to use the Service Pattern (Possibly with the Repository Pattern) to deal with the business logic in my application. I have for example a Client model which represents a customer and a corresponding ClientService that is responsible for client-specific business logic.
class ClientService extends Service implements ClientServiceContract
{
public function create(array $attributes)
{
// Create a new client...
}
public function doSomethingElse(Client $client)
{
// Do something else
}
}
Say for example I have another service UserService, which is similar to the ClientService above in that it has methods to create and do other things to User models.
Now on my site, imagine that I have a form that someone can fill in to register their interest in becoming a client. In my back end system I would like to create a button that takes a client's interest record ClientInterest and creates a Client, a User, associates the two and finally sends an e-mail to the new user with the details.
Where, when using the service pattern would it be best to put this logic?
I have considered:
Create a service and method ClientInterestService::createClientAndUser(...) which would use the ClientService and UserService classes to create the Client and User instances and then carry out the association before triggering an event which sends the email. This approach means that I'm not duplicating code, however I'm coupling classes together and I'm breaking some SOLID principles. I'm not sure but I have a feeling this wouldn't be great for testing either.
As described above, create a service class and method to carry out the logic, but instead of using the other two services I would write the logic to create the Client and User instances, carry out the association and trigger the event to send the email. This approach feels nicer, my code is more loosely coupled and I'm not breaking any SOLID principles, however, I'm potentially duplicating code.
Simply put the logic that I would have had in ClientInterestService::createClientAndUser(...) in my controller. Doing this would mean that I have business logic in my controller which kind of defeats the point of having services.
I think if you break this down into smaller steps you can achieve DRY architecture. The steps I'm seeing are:
Create Client
Create User
Associate (via pivot table, junction table etc)
Email
To avoid having the dreaded duplicate code you'd create a method around each of these in your service class or classes. You'd then create an action encapsulating all of the steps involved based around these methods.
Don't be scared to implement things outside of your service class - this doesn't mean it is outside of your service layer.
I see registering client interest as an action. You follow synchronous steps to achieve your desired action. So based on methods like creating a user, client etc we can build an action to register client interest, like so:
<?php
class ClientService {
public function addAction(IAction $action)
{
return $action->process();
}
public function createUser() {} // business logic for creating a user.
public function createClient() {} // business logic for creating a client.
public function createAssociation() {} // business logic for creating an association.
}
interface IAction {
public function process();
}
class RegisterClientInterestAction implements IAction {
protected $client;
public function __construct(ClientService $client)
{
$this->client = $client;
}
public function process()
{
$this->createUser()->createClient()->createAssociation();
}
private function createUser() {} // interact with your client service to call the method $client->createUser()
private function createClient() {} // interact with your client service to call the method $client->createClient()
private function createAssociation() {} // interact with your client service to call the method $client->createAssociation()
}
//USAGE
$service = new ClientService;
$results = $service->addAction(new RegisterClientInterestAction($service));
?>
By doing it this way you are able to utilise the createUser etc methods in a new action but without duplicating the code. By having the addAction on the service class you are still executing the business logic inside of your service layer.
If two or more services are required, I'd take a slightly different approach by moving where I would execute the action.
In terms of handling more than one service you can use DI within the constructor of your action.
Like this:
<?php
class Service {
public function addAction(IAction $action)
{
return $action->process();
}
// Other stuff for a base service...
}
class UserService extends Service {
public function createUser() {} // business logic for creating a user.
}
class ClientService extends Service {
public function createClient() {} // business logic for creating a client.
public function createAssociation() {} // business logic for creating an association.
}
interface IAction {
public function process();
}
class RegisterClientInterestAction implements IAction {
protected $client;
protected $service;
public function __construct(ClientService $client, UserService $user)
{
$this->user = $user;
$this->client = $client;
}
public function process()
{
$this->createUser()->createClient()->createAssociation();
}
private function createUser() {} // interact with your user service to call the method $client->createUser()
private function createClient() {} // interact with your client service to call the method $client->createClient()
private function createAssociation() {} // interact with your client service to call the method $client->createAssociation()
}
//USAGE
$service = new Service;
$results = $service->addAction(new RegisterClientInterestAction(new ClientService, new UserService));
?>
What feels best for me is your proposed solution of #2.
What I like to do is build out the two service classes and see what the duplication there is, then refactor/extract any duplication to another class. This way all classes are very testable and you have the least chance of breaking any SOLID principles.

(Laravel) Dynamic dependency injection for interface, based on user input

I am currently facing a very interesting dilemma with my architecture and implementation.
I have an interface called ServiceInterface which have a method called execute()
Then I have two different implementations for this interface: Service1 and Service2, which implements the execute method properly.
I have a controller called MainController and this controller has a "type-hint" for the ServiceInterface (dependency injection), it means that both, Service1 and Service2, can be called as resolution for that dependency injection.
Now the fun part:
I do not know which of those implementations to use (Service1 or Service2) because I just know if I can use one or other based on a user input from a previous step.
It means the user choose a service and based on that value I know if a can use Service1 or Service2.
I am currently solving the dependency injection using a session value, so depending of the value I return an instance or other, BUT I really think that it is not a good way to do it.
Please, let me know if you faced something similar and, how do you solve it, or what can I do to achieve this in the right way.
Thanks in advance. Please let me know if further information is required.
Finally, after some days of researching and thinking a lot about the best approach for this, using Laravel, I finally solved it.
I have to say that this was especially difficult in Laravel 5.2 because, in this version, the Session middleware only is executed in the controllers used in a route, it means that if for some reason I used a controller (not linked for a rote) and try to get access to the session it is not going to be possible.
So, because I cannot use the session, I decided to use URL parameters. Here you have the solution approach; I hope some of you found it useful.
so, you have an interface:
interface Service
{
public function execute();
}
Then a couple of implementations for the interface:
Service one:
class ServiceOne implements Service
{
public function execute()
{
.......
}
}
Service two.
class ServiceTwo implements Service
{
public function execute()
{
.......
}
}
The interesting part is that I have a controller with a function with a dependency with the Service interface. Still, I need to resolve it dynamically to ServiceOne or ServiceTwo based on user input. So:
The controller
class MyController extends Controller
{
public function index(Service $service, ServiceRequest $request)
{
$service->execute();
.......
}
}
Please note that ServiceRequest, validated that the request already have the parameter that we need to resolve the dependency (call it 'service_name')
Now, in the AppServiceProvider we can resolve the dependency in this way:
class AppServiceProvider extends ServiceProvider
{
public function boot()
{
}
public function register()
{
//This specific dependency is going to be resolved only if
//the request has the service_name field stablished
if(Request::has('service_name'))
{
//Obtaining the name of the service to be used (class name)
$className = $this->resolveClassName(Request::get('service_name')));
$this->app->bind('Including\The\Namespace\For\Service', $className);
}
}
protected function resolveClassName($className)
{
$resolver = new Resolver($className);
$className = $resolver->resolveDependencyName();
return $className;
}
}
So now all the responsibility is for the Resolver class. This class basically use the parameter passed to the constructor to return the full name (with namespace) of the class that is going to be used as an implementation of the Service interface:
class Resolver
{
protected $name;
public function __construct($className)
{
$this->name = $className;
}
public function resolveDependencyName()
{
//This is just an example, you can use whatever as 'service_one'
if($this->name === 'service_one')
{
return Full\Namespace\For\Class\Implementation\ServiceOne::class;
}
if($this->name === 'service_two')
{
return Full\Namespace\For\Class\Implementation\ServiceTwo::class;
}
//If none, so throw an exception because the dependency can not be resolved
throw new ResolverException;
}
}
Well, I really hope it helps some of you.
Best wishes!
---------- EDIT -----------
I just realize that it is not a good idea to use the request data directly inside the container of Laravel. It really is going to cause some trouble in the long term.
The best way is to directly register all the possible instances supported (serviceone and servicetwo) and then resolve one of them directly from a controller or a middleware, so then is the controller "who decides" what service to use (from all the available) based on the input from the request.
In the end, it works at the same, but it is going to allow you to work more naturally.
I have to say thanks to rizqi, a user from the questions channel of the slack chat of Laravel.
He personally created a golden article about this. Please read it because it solves this issue completely and in a very right way.
laravel registry pattern
The fact that you define that your controller works with ServiceInterface is ok
If you have to choose the concrete implementation of the service basing on a previous step (that, as i've understood, happens in a previous request) storing the value in session or in database is right too, as you have no alternative: to choose the implementation you have to know the value of the input
The important point is to 'isolate' the resolution of the concrete implementation from the input value in one place: for example create a method that takes this value as a parameter and returns the concrete implementation of the service from the value:
public function getServiceImplementation($input_val)
{
switch($input_val)
{
case 1 : return new Service1();
case 2 : return new Service2();
}
}
and in your controller:
public function controllerMethod()
{
//create and assign the service implementation
$this->service = ( new ServiceChooser() )->getServiceImplementation( Session::get('input_val') );
}
In this example i've used a different class to store the method, but you can place the method in the controller or use a Simple Factory pattern, depending on where the service should be resolved in your application
It's an interesting problem. I'm currently using Laravel 5.5 and have been mulling it over. I also want my service provider to return a specific class (implementing an interface) based upon user input. I think it's better to manually pass the input from the controller so it's easier to see what's going on. I would also store the possible values of the class names in the config.
So based upon the Service classes and interface you've defined above i came up with this:
/config/services.php
return [
'classes': [
'service1' => 'Service1',
'service2' => 'Service2',
]
]
/app/Http/Controllers/MainController.php
public function index(ServiceRequest $request)
{
$service = app()->makeWith(ServiceInterface::class, ['service'=>$request->get('service)]);
// ... do something with your service
}
/app/Http/Requests/ServiceRequest.php
public function rules(): array
$availableServices = array_keys(config('services.classes'));
return [
'service' => [
'required',
Rule::in($availableServices)
]
];
}
/app/Providers/CustomServiceProvider.php
class CustomServiceProvider extends ServiceProvider
{
public function boot() {}
public function register()
{
// Parameters are passed from the controller action
$this->app->bind(
ServiceInterface::class,
function($app, $parameters) {
$serviceConfigKey = $parameters['service'];
$className = '\\App\\Services\\' . config('services.classes.' . $serviceConfigKey);
return new $className;
}
);
}
}
This way we can validate the input to ensure we are passing a valid service, then the controller handles passing the input from the Request object into the ServiceProvider. I just think when it comes to maintaining this code it will be clear what is going on as opposed to using the request object directly in the ServiceProvider.
PS Remember to register the CustomServiceProvider!
I find the best way to deal with this is using a factory pattern. You can create a class say ServiceFactory and it has a single method create() it can accept an argument which is used to dynamically choose which concrete class to instantiate.
It has a case statement based on the argument.
It will use App::make(ServiceOne::class) or App::make(ServiceTwo::class).depending on which one is required.
You are then able to inject this into your controller (or service which depends on the factory).
You can then mock it in a service unit test.
Recently, I had to implement a similar logic where I was to implement a method to perform mobile top-ups for multiple networks in our application. So, I decided to implement the logic using Factory and Bridge pattern. Factory to create an instance of the concrete Service class based on the user input, and then, the Bridge pattern to set closely related classes into separate hierarchies and route the request to the respective class.
In the controller's method, both Factory and Service classes are injected. The TopUpServiceFactory's create method creates an object of the concrete class. The TopUpService class then routes the request to that concrete class method.
class TopUpController extends Controller
{
public function topUp(Request $request, TopUpServiceFactoryInterface $serviceFactory, TopUpServiceInterface $topUpService)
{
$serviceFactory->create($request->networkCode);
$topUpService->TopUp($request->all());
}
}
The TopUpServiceFactoryInterface and TopUpServiceInterface are bound to TopUpServiceFactory and TopUpService concrete Classes respectively in Service Container.
class AppServiceProvider extends ServiceProvider
{
public function register()
{
$this->app->bind(TopUpServiceFactoryInterface::class, TopUpServiceFactory::class);
$this->app->bind(TopUpServiceInterface::class, TopUpService::class);
}
}
The create method accepts user input and creates an object of the respective class based on the user input.
class TopUpServiceFactory implements TopUpServiceFactoryInterface
{
public function create(string $networkCode)
{
switch ($networkCode) {
case 'network1':
app()->bind(NetworkServiceInterface::class, Network1Service::class);
break;
case 'network2':
app()->bind(NetworkServiceInterface::class, Network2Service::class);
break;
default:
app()->bind(NetworkServiceInterface::class, DefaultNetworkService::class);
break;
}
}
}
The Service Class then picks the object of NetworkService Class and forwards the request.
class TopUpService implements TopUpServiceInterface
{
public function topUp(array $requestParams)
{
$networkService = app()->get(NetworkServiceInterface::class);
$networkService->topUp($requestParams);
}
}
All network's concrete classes implement a common interface NetworkServiceInterface, which is used to inject dependency dynamically, implementing Liskov Substitution Principle
class Network1Service implements NetworkServiceInterface
{
public function topUp(array $requestParam)
{
Process Topup ......
}
}
class Network2Service implements NetworkServiceInterface
{
public function topUp(array $requestParam)
{
Process Topup ......
}
}
...

Making one interface overwrite a method it inherits from another interface in PHP

Is there a way in PHP to overwrite a method declared by one interface in an interface extending that interface?
The Example:
I'm probably doing something wrong, but here is what I have:
interface iVendor{
public function __construct($vendors_no = null);
public function getName();
public function getVendors_no();
public function getZip();
public function getCountryCode();
public function setName($name);
public function setVendors_no($vendors_no);
public function setZip($zip);
public function setCountryCode($countryCode);
}
interface iShipper extends iVendor{
public function __construct($vendors_no = null, $shipment = null);
public function getTransitTime($shipment = null);
public function getTransitCost($shipment = null);
public function getCurrentShipment();
public function setCurrentShipment($shipment);
public function getStatus($shipment = null);
}
Normally in PHP, when you extend something, you can overwrite any method contained therein (right?). However, when one interface extends another, it won't let you. Unless I'm thinking about this wrong... When I implement the iShipper interface, I don't have to make the Shipper object extend the Vendor object (that implements the iVendor interface). I just say:
class FedEx implements iShipper{}
and make FedEx implement all of the methods from iVendor and iShipper. However, I need the __construct functions in iVendor and iShipper to be unique. I know I could take out the $shipment = null, but then it wouldn't be as convenient to create Shippers (by just passing in the vendors_no and the shipment while instantiating).
Anyone know how to make this work? My fallback is to have to set the shipment by calling $shipper->setShipment($shipment); on the Shipper after I instantiate it, but I'm hoping for a way to get around having to do that...
A little more explanation for the curious:
The FedEx Object has methods that go to the FedEx site (using cURL) and gets an estimate for the Shipment in question. I have a UPS Object, a BAXGlobal Object, a Conway Object, etc. Each one has COMPLETELY different methods for actually getting the shipping estimate, but all the system needs to know is that they are a "shipper" and that the methods listed in the interface are callable on them (so it can treat them all exactly the same, and loop through them in a "shippers" array calling getTransitX() to find the best shipper for a shipment).
Each "Shipper" is also a "Vendor" though, and is treated as such in other parts of the system (getting and putting in the DB, etc. Our data design is a pile of crap, so FedEx is stored right alongside companies like Dunder Mifflin in the "Vendors" table, which means it gets to have all the properties of every other Vendor, but needs the extra properties and methods supplied by iShipper).
#cmcculloh Yeah, in Java you don't define constructors in Interfaces. This allows you to both extend interfaces and also have a class that implements multiple interfaces (both allowed, and very useful in many cases) without worrying about having to satisfy a particular constructor.
EDIT:
Here's my new model:
A. Each interface no longer has a constructor method.
B. All Shippers (UPS, FedEx, etc) now implement iShipper (which extends iVendor) and extend the abstract class Shipper (which has all common non-abstract methods for shippers defined in it, getName(), getZip() etc).
C. Each Shipper has it's own unique _construct method which overwrites the abstract __construct($vendors_no = null, $shipment = null) method contained in Shipper (I don't remember why I'm allowing those to be optional now though. I'd have to go back through my documentation...).
So:
interface iVendor{
public function getName();
public function getVendors_no();
public function getZip();
public function getCountryCode();
public function setName($name);
public function setVendors_no($vendors_no);
public function setZip($zip);
public function setCountryCode($countryCode);
}
interface iShipper extends iVendor{
public function getTransitTime($shipment = null);
public function getTransitCost($shipment = null);
public function getCurrentShipment();
public function setCurrentShipment($shipment);
public function getStatus($shipment = null);
}
abstract class Shipper implements iShipper{
abstract public function __construct($vendors_no = null, $shipment = null);
//a bunch of non-abstract common methods...
}
class FedEx extends Shipper implements iShipper{
public function __construct($vendors_no = null, $shipment = null){
//a bunch of setup code...
}
//all my FedEx specific methods...
}
Thanks for the help!
ps. since I have now added this to "your" answer, if there is something about it you don't like/think should be different, feel free to change it...
You could drop off the constructor and just put them in each individual class. Then what you have is each class has its own __construct, which is probably the same depending on if it is a shipper or vendor. If you want to only have those constructs defined once I don't think you want to go down that route.
What I think you want to do is make an abstract class that implements vendor, and one that implements shipper. There you could define the constructors differently.
abstract class Vendor implements iVendor {
public function __construct() {
whatever();
}
}
abstract class Shipper implements iShipper {
public function __construct() {
something();
}
}

Categories