LARAVEL: How to use Open Close Principle of SOLID principles? - php

I have a following structure to use Open Close Principle
class Payment{
//this is not a model class
// according to OC principle this class should not focus on the implementation
private $paymentInterface;
public function __construct(PaymentInterface $paymentInterface)
{
$this->paymentInterface = $paymentInterface;
}
//so store method does not know which implementation it will get
public function store($request,$id)
{
return $this->paymentInterface->store($request,$id);
}
}
Interface
interface PaymentInterface{
public function store($request,$id = null);
}
Payment Service Class containing implementation
class PaymentService implements PaymentInterface{
public function store($request,$id = null){
//payment store logic is here
}
}
Controller
class PaymentsController extends Controller{
protected $payment;
public function __construct()
{
$this->payment = new Payment(new PaymentService);
}
public function storePayment(PaymentRequest $request, $id)
{
try {
$response = $this->payment->store($request,$id);
return redirect()->route($this->route.'.index')->with($response['status'],$response['message']);
} catch (\Exception $e) {
return $this->vendorDashboard($e);
}
}
}
My question is:
Is it correct approach to use Open-Close-Principle ?
Using above code I can tell controller that I can use PaymentService class for the implementation.
$payment = new Payment(new PaymentService);
return $payment->store($request,$id);
If later I want to make a payment in different way e.g. make a payment through invoice then I can create new controller, write new implementation in new class e.g. InvoicePaymentService and tell Payment class to use InvoicePaymentService as implementation
$payment = new Payment(new InvoicePaymentService);
return $payment->store($request,$id);
OR
$payment = new Payment(new PayPalPaymentService);
return $payment->store($request,$id);
OR
$payment = new Payment(new AliPayPaymentService);
return $payment->store($request,$id);
I know I can bind Interface with a class through a service provider but if I want to implement a different payment implementation then I will not be able to change the class, right ?
If I am doing it in wrong way please let me know.

This is what service container stands for. You should use contextual binding
Assuming you have an interface: FooInterface
And you have two concrete implementations: GoodFoo and BadFoo
In order to inject different implementations to controllers (or other classes) you must tell it to laravel.
$this->app->when(GoodController::class)
->needs(FooInterface::class)
->give(function () {
return new GoodFoo();
});
$this->app->when(BadController::class)
->needs(FooInterface::class)
->give(function () {
return new BadFoo();
});
And controllers should be:
class GoodController extends Controller
{
protected $foo;
public function __construct(FooInterface $foo)
{
$this->foo = $foo;
}
}
class BadController extends Controller
{
protected $foo;
public function __construct(FooInterface $foo)
{
$this->foo = $foo;
}
}
Please note that most of the time laravel promotes bad software design principles and it rather hard to practise SOLID principles in laravel.

Related

What's the difference between Laravel automatic injection and manually specifying the dependencies in the constructor body?

I'm using a Repository pattern in my Laravel project. This pattern is not really explained in the official documentation, except for this snippet:
You may type-hint a repository defined by your application in a controller's constructor. The repository will automatically be resolved and injected into the class.
This is my code, in accordance with the documentation:
class CategoriesController extends Controller
{
protected $repo;
public function __construct(CategoriesRepository $repo)
{
$this->repo = $repo;
}
I've type-hinted the CategoriesRepository so it gets automatically loaded by the Service Container.
However, if I directly create a new instance of the CategoriesController class (without using the Service Container), I have to specify that I need a new instance of the CategoriesRepository too, like this:
$example = new CategoriesController(new CategoriesRepository());
Now, let's suppose I write the following code.
class CategoriesController extends Controller
{
protected $repo;
public function __construct()
{
$this->repo = new CategoriesRepository();
}
This way, I don't have to load the class through the Service Container, nor call it by passing a new instance of CategoriesRepository as the argument, because it's automatically created inside of the constructor.
So, my question is: would this be bad practice? What's the difference between type-hinting as a parameter and creating a new instance inside of the constructor?
Here's the beauty of dependency injection:
Complex initialization
class MyController {
public function __construct(A $a) { }
}
class A {
public function __construct(B $b) { }
}
class B {
public function __construct(C $c) { }
}
class C {
public function __construct(D $d) { }
}
class D {
public function __construct() { }
}
Now you can ask laravel to create that class for you e.g:
$controller = make(MyController::class);
or you can do:
$controller = new MyController(new A(new B(new C(new D())))));
In addition you can specify more complex rules on how to create the variables:
app()->bind(D::class, function ($app) {
$d = new D();
$d->setValueOfSomething($app->make(AnotherClass::class));
return $d;
});
Testing
That's one advantage of dependency injection over manual creation of things. Another is unit testing:
public function testSomeFunctionOfC() {
$this->app->bind(D::class, function () {
$dMock = $this->createMock(D::class);
});
$c = make(C::class);
}
Now when you create C the class D will be the mocked class instead which you can ensure works according to your specification.

Best method for handling multiple interface implementations?

Unfortunately I'm stuck here.
Consider the following rudimentary examples:
interface ChargeInterface
{
public function charge($amount);
}
class BraintreeCharge implements ChargeInterface
{
public function charge($amount)
{
// braintree logic here
}
}
class StripeCharge implements ChargeInterface
{
public function charge($amount)
{
// stripe logic here
}
}
So there's an interface for charging a payment method, and there are, in this example, two concrete classes which implement the interface.
I'd like to be able to decide on runtime which implementation should be used. So I thought I'd achieve this with custom factory classes:
class PaymentFactory
{
public static $implementation;
public static function charge()
{
return $implementation::charge();
}
}
class StripeFactory
{
public static function charge()
{
return new StripeCharge();
}
}
class BraintreeFactory
{
public static function charge()
{
return new BraintreeCharge();
}
}
Than I could just use the factories:
PaymentFactory::$implemention = StripeFactory::class;
$payments = PaymentFactory::charge();
$payments->charge(100);
Another idea was to use a singleton based logic:
class PaymentFactory extends Singleton
{
protected $implementation;
// Singleton logic missing in this example
public function useImplementation($class)
{
$this->implementation = $class;
}
public function getImplementation()
{
return $this->implementation;
}
public static function charge()
{
$instance = self::getInstance();
return new $instance->getImplementation();
}
}
Later ...
PaymentFactory::getInstance()->useImplementation(StripeCharge::class);
$payments = PaymentFactory::charge();
$payments->charge(100);
Do you've any suggestions regarding best practices here?
I think I'd favour the first one, since the real implementation consists of more than just one class per package, as outlined in the example.
Also it seems to me, this would be the more cleaner way.

OO, MVC and Observer pattern not working as expected

In my class, we made a simple application using MVC with the observer pattern in Java and it works. The view cannot call any methods from the model that are not included in the (Observable) interface and vice versa.
I am quite a fan of PHP and decided to make the same (simplified) example in PHP. I noticed that even though I am using an interface and passing the reference of the model as an interface, the view can still call every method inside the model, rendering the entire pattern useless.
Is there something I overlooked or is this not possible in PHP?
The PHP code (every reference, method, etc is the exact same as in the Java application) :
class App
{
public function __construct()
{
$model = new Model();
$controller = new Controller($model);
}
}
class Model implements Observable
{
private $view;
private $count = 1;
public function __construct()
{
echo 'Model created. <br>';
}
public function registrate(Observer $view)
{
$this->view = $view;
echo 'Model: view is registered. <br>';
}
public function addOne()
{
$this->count += 1;
$this->view->modelChanged($this);
}
public function getCounter()
{
return $this->count;
}
public function getMessage()
{
return 'The view should not be able to call this method.';
}
}
class Controller
{
private $view;
private $model;
public function __construct(Model $model)
{
echo 'Controller created. <br>';
$this->model = $model;
$this->view = new View($this->model);
$this->model->addOne();
}
}
class View implements Observer
{
public function __construct(Observable $model)
{
echo 'View created. <br>';
$model->registrate($this);
}
public function modelChanged(Observable $model)
{
// Should only be able to call method "getCounter()"
echo $model->getMessage();
}
}
interface Observable
{
public function registrate(Observer $view);
public function getCounter();
}
interface Observer
{
public function modelChanged(Observable $model);
}
The output, if you run this is:
Model created.
Controller created.
View created.
Model: view is registered.
The view should not be able to call this method. As you can see, the view can call a method of the model that is not declared inside the Observable interface.
How is this possible and why does this not work in PHP like it does in Java?
Well of course the view can call every method you've defined on the model: All the methods are public, which means they're callable from anywhere. Just define them as protected or private instead...
Of course, that'd limit the ways in which you can use the model in other components (such as the controller). To get around that problem, a simple fix would be to create a wrapper, which you can wrap around the model when you pass it to the view:
class View implements Observable
{
public function __construct(ViewObservable $model)
{
//do stuff here
}
}
//Wrapper:
class ViewObservable
{
/**
* #var Model
*/
protected $payload = null;
public class __construct(Observable $model)
{
$this->payload = $model;
}
public function getCounter()
{
return $this->payload->getCounter();
}
}
But really, you might want to rethink a thing or 2. It's good to use interfaces, but it doesn't make a lot of sense (to me at least) to have all components in an MVC architecture implement the same interface. All components have different jobs to perform, and therefore should have different interface requirements.

Can I reuse decorators?

Can I reuse decorators?
I have a ClientDecorator to decorate an entity that has a reference of a client, this decorator gets the client on database on call getClient (before it gets decorated, this method returns the clientId, after being decorated, it returns an instance of Client).
Okay, but, I've some other entities that can be decorated with the same decorator, for example, I have another table named questions, this table has a reference pointing to a client that has asked a question, and I have another table named schedules, that has a reference of a client.
By the way, I can decorate question and schedule with ClientDecorator.
But, I have an QuestionDecorator too; this guy decorates an Answer, etc.
How I can do this abstraction, so I can reuse decorators whenever I want?
I've tried to create ClientDecorable, QuestionDecorable interfaces, but have made no progress.
You can always instance the decorator class passing parameters to the constructor that will tell it how it should behave or what class it should impersonate. You don't really have to declare your decorator as an extension of another class.
PHP classes support magic methods that make it possible to forward calls to the class your object is impersonating, just as if it was extending it with extends.
For instance:
class Client
{
public function getId() { return 123; }
}
class Decorator
{
private $instance = null;
public function __construct($class)
{
$this->instance = new $class();
}
public function __call($method, $params) // magic method
{
return call_user_func_array(array($this->instance, $method), $params);
}
}
$object = Decorator('Client');
echo $object->getId(); // 123
The magic method __call() will be invoked when you try to access a method that doesn't belong to the class Decorator. The same can be done with properties by using the magic methods __get() and __set().
That's a really tricky problem. I could find a solution, but it is kind of McGiver style... Works for PHP 5.4+ (yes, traits).
<?php
interface Decorable
{
public function getTarget();
}
interface ClientDecorable extends Decorable
{
public function getClient();
}
interface LogDecorable extends Decorable
{
public function getLog();
}
abstract class AbstractDecorator implements Decorable
{
private $target;
public function __construct(ClientDecorable $target)
{
$this->target = $target;
}
public function getTarget()
{
// I'll be able to access the leaf node of my decorator single way 'tree'
return $this->target->getTarget();
}
public function __call($method, $args) {
$reflected = new ReflectionClass($this->target);
if ($reflected->hasMethod($method)) {
return call_user_func_array([$this->target, $method], $args);
}
}
}
class ClientDecorator extends AbstractDecorator implements ClientDecorable
{
public function __construct(Decorable $target) {
if (! $target->getTarget() instanceof ClientDecorable) {
throw new Exception('Must be an instance de ClientDecorable');
}
parent::__construct($target);
}
public function getClient()
{
return new Client($this->getTarget()->getClient());
}
}
class LogDecorator extends AbstractDecorator implements LogDecorable
{
public function __construct(Decorable $target) {
if (! $target->getTarget() instanceof LogDecorable) {
throw new Exception('Must be an instance de LogDecorable');
}
parent::__construct($target);
}
public function getLog()
{
return new Log($this->getTarget()->getLog());
}
}
abstract class AbstractTarget implements Decorable
{
// this does the trick
public function getTarget() { return $this; }
}
trait ClientDecorableTrait {
public function getClient()
{
return $this->client;
}
}
trait LogDecorableTrait {
public function getLog()
{
return $this->log;
}
}
class Payment extends AbstractTarget implements ClientDecorable, LogDecorable
{
use ClientDecorableTrait;
use LogDecorableTrait;
private $client = 1;
private $log = 101;
}
class Sale extends AbstractTarget implements ClientDecorable
{
use ClientDecorableTrait;
private $client = 2;
}
class Client
{
// ...
}
class Log
{
// ...
}
$sale = new Sale();
var_dump($sale->getClient());
$saleDec = new ClientDecorator($sale);
var_dump($saleDec->getClient());
$payment = new Payment();
var_dump($payment->getClient());
$paymentDec = new ClientDecorator($payment);
var_dump($paymentDec->getClient());
var_dump($paymentDec->getLog());
$paymentDecTwice = new LogDecorator($paymentDec);
var_dump($paymentDecTwice->getLog());
$saleDecTwice = new LogDecorator($saleDec); // will throw an exception
This is just a skeleton, a real world implementation must be tricky. I think you'd better keep your decorators separated...

What's the best way to implement a factory method for an extended class?

Consider the following code:
class Vehicle {
/**
* Create a new instance of Vehicle
*
* #return Vehicle
*/
public static function create(){
return eval( "return new " . get_called_class() . '();' );
// return self(); would always return Vehicle reg ardless
}
public function drive(){
echo "I am a Vehicle!";
}
}
class Bus extends Vehicle {
public function drive(){
parent::drive();
echo "\nSpecifically, a bus!";
}
}
class Car extends Vehicle {
public function drive(){
parent::drive();
echo "\nSpecifically, a car!";
}
}
// Drive a car
Car::create()->drive();
// Drive a bus
Bus::create()->drive();
I've implemented a factory "create" method in the Vehicle class that allows me to get an instance of the class that I want to use.
I tried using "return new self();" but that always returns an instance of Vehicle, so I resorted to using eval.
question: Is there a non-eval way to implement the create() method so that:
it returns an instance of the class you're using
it doesn't require implementing create() on each of the extending classes
Use static instead of self, e.g.
<?php
class Vehicle {
public static function create(){
return new static();
}
public function drive(){
echo "I am a Vehicle!";
}
}
class Bus extends Vehicle {
public function drive(){
parent::drive();
echo "\nSpecifically, a bus!";
}
}
$b = Bus::create();
$b->drive();
prints
I am a Vehicle!
Specifically, a bus!
(VolkerK beat me, but this has a slight variation)
Wait, why do you need to eval() at all? Wouldn't:
public static function create() {
$class = get_called_class();
return new $class();
}
work?
The best way is to move the factory method out of the concrete type and into a factory class of it's own. You can then not only handle this more easily but you can also replace the factory with another factory easily.
I assume you know how inheritance with objects work, so you don't have to deal with anything static which is less straight forward and starts to stand in someones way pretty fast.

Categories