Laravel: Service/Repository Pattern and duplicating code - php

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.

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.

Building Classes to Abstract Functionality of API

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.

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) 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 ......
}
}
...

How to make a REST API first web application in Laravel

I want to make an API first application in Laravel. I don't know what is the best approach to do this, I will explain what I am trying to do, but please feel free to give answers how to do this in a different way.
I don't want all my frontend to be written in javascript and parse the JSON output of the API with angular.js or something similar. I want my Laravel application to produce the HTML views. I am trying to go down the road of having two controllers one on for the API and one for the web. For the show User action my routes.php looks like this:
# the web controller
Route::controller('user', 'WebUserController');
# the api controller
Route::group(array('prefix' => 'api'), function() {
Route::resource('user', 'UserController');
});
So /user will take me to WebUserController and /api/user will take me to the UserController. Now I want to put all my logic in the API UserController, and call its actions from the WebUserController. Here is the code for both of them:
class UserController extends BaseController
{
public function show($id)
{
$user = User::find($id);
return Response::json(array('success'=>true,'user'=>$user->toArray()));
}
}
class WebUserController extends UserController
{
public function getView($id)
{
# call the show method of the API's User Controller
$response = $this->show($id);
return View::make('user.view')->with('data', $response->getData());
}
}
In the WebUserController I am able to get the json content of the response with getData(), but I am not able to get the headers and status code (they are protected properties of Illuminate\Http\JsonResponse).
I think that my approach might not be the best, so I am open to suggestions how to make this app.
EDIT: The question how to get the headers and status of the response has been answered by Drew Lewis, but I still think that there might be a better way how to design this
You should utilize the Repository / Gateway design pattern: please see the answers here.
For example, when dealing with the User model, first create a User Repository. The only responsibility of the user repository is to communicate with the database (performing CRUD operations). This User Repository extends a common base repository and implements an interface containing all methods you require:
class EloquentUserRepository extends BaseRepository implements UserRepository
{
public function __construct(User $user) {
$this->user = $user;
}
public function all() {
return $this->user->all();
}
public function get($id){}
public function create(array $data){}
public function update(array $data){}
public function delete($id){}
// Any other methods you need go here (getRecent, deleteWhere, etc)
}
Then, create a service provider, which binds your user repository interface to your eloquent user repository. Whenever you require the user repository (by resolving it through the IoC container or injecting the dependency in the constructor), Laravel automatically gives you an instance of the Eloquent user repository you just created. This is so that, if you change ORMs to something other than eloquent, you can simply change this service provider and no other changes to your codebase are required:
use Illuminate\Support\ServiceProvider;
class RepositoryServiceProvider extends ServiceProvider {
public function register() {
$this->app->bind(
'lib\Repositories\UserRepository', // Assuming you used these
'lib\Repositories\EloquentUserRepository' // namespaces
);
}
}
Next, create a User Gateway, who's purpose is to talk to any number of repositories and perform any business logic of your application:
use lib\Repositories\UserRepository;
class UserGateway {
protected $userRepository;
public function __construct(UserRepository $userRepository) {
$this->userRepository = $userRepository;
}
public function createUser(array $input)
{
// perform any sort of validation first
return $this->userRepository->create($input);
}
}
Finally, create your User web controller. This controller talks to your User Gateway:
class UserController extends BaseController
{
public function __construct(UserGatway $userGateway)
{
$this->userGateway = $userGateway;
}
public function create()
{
$user = $this->userGateway->createUser(Input::all());
}
}
By structuring the design of your application in this way, you get several benefits: you achieve a very clear separation of concerns, since your application will be adhering to the Single Responsibility Principle (by separating your business logic from your database logic) . This enables you to perform unit and integration testing in a much easier manner, makes your controllers as slim as possible, as well as allowing you to easily swap out Eloquent for any other database if you desire in the future.
For example, if changing from Eloquent to Mongo, the only things you need to change are the service provider binding as well as creating a MongoUserRepository which implements the UserRepository interface. This is because the repository is the only thing talking to your database - it has no knowledge of anything else. Therefore, the new MongoUserRepository might look something like:
class MongoUserRepository extends BaseRepository implements UserRepository
{
public function __construct(MongoUser $user) {
$this->user = $user;
}
public function all() {
// Retrieve all users from the mongo db
}
...
}
And the service provider will now bind the UserRepository interface to the new MongoUserRepository:
$this->app->bind(
'lib\Repositories\UserRepository',
'lib\Repositories\MongoUserRepository'
);
Throughout all your gateways you have been referencing the UserRepository, so by making this change you're essentially telling Laravel to use the new MongoUserRepository instead of the older Eloquent one. No other changes are required.
You should be use Repository for this design.
Example -
//UserRepository Class
class UserRepository {
public function getById($id)
{
return User::find($id);
}
}
// WebUser Controller
class WebUserController extends BaseController {
protected $user;
public function __construct(UserRepository $user)
{
$this->user = $user;
}
public function show($id)
{
return View::make('user.view')->with('data', $this->user->getById($id));
}
}
// APIUser Controller
class UserController extends BaseController {
protected $user;
public function __construct(UserRepository $user)
{
$this->user = $user;
}
public function show($id)
{
$data =>$this->user->getById($id);
return Response::json(array('success'=>true,'user'= $data->toArray()));
}
}
Checkout Laravel's RESTful controllers:
http://laravel.com/docs/controllers#restful-controllers
Their docs do a pretty good job.
But even better is this tutorial:
http://code.tutsplus.com/tutorials/laravel-4-a-start-at-a-restful-api-updated--net-29785
This is a video by Jeffrey Way he is one of the better Laravel developers. In this tutorial he is connecting a BackboneJS application to a RESTful service that he sets up in Laravel. It doesn't get any better then this. I can write you a lot of boilerplate, but just learn it by watching a nice video and having a coffee. ;)
https://www.youtube.com/watch?v=uykzCfu1RiQ
I have a response to the problem you are having with the Response.
You can get the headers, status code and data from the Response.
// your data
$response->getData();
// the status code of the Response
$response->getStatusCode();
// array of headers
$response->headers->all();
// array of headers with preserved case
$response->headers->allPreserveCase();
$response->headers is a Symfony\Component\HttpFoundation\ResponseHeaderBag which inherits from Symfony\Component\HttpFoundation\HeaderBag
I would also recommend using a repository.
Attempting to call one controller from another would be falling into a pattern called HMVC (Hierarchical model–view–controller).
This means that your entire application relies on lower modules.
In this case, your API would serve as a repository for your data (which isn't the worst thing in the world at first).
However, when you then modify the structure of how data is returned in your API, everything else relying on it would have to know how to respond.
Say you wanted to have authorization checks to see if a logged in user should be able to see the details of a returned user and there was an error.
In the API, you would return a Response object with a 403 forbidden code and some meta data.
Your HTML controller would have to know how to handle this.
Contrast this to a repository which could throw an exception.
public function findById ($id)
{
$user = User::findOrFail($id);
if (Auth::user->hasAccessTo($user)) {
return $user;
} else {
throw new UnauthorizedAccessException('you do not have sufficient access to this resource');
}
}
And your API controller would look more like this:
public function show($id)
{
try {
return $this->user->findById($id);
} catch (UnauthorizedAccessException $e) {
$message = $e->getMessage();
return Response::json('403', ['meta' => ['message' => $message]]));
}
}
Your HTML controller would then look like this:
public function show($id)
{
try {
$user = $this->user->findById($id);
} catch (UnauthorizedAccessException $e) {
Session::flash('error', $e->getMessage());
// Redirect wherever you would like
return Response::redirect('/');
}
}
This gives you very reusable code and let's you change your controller implementations independently without worry of changing the other's behavior.
I wrote more on how to implement the repository pattern in this post: you can ignore the interface and skip right to the implementations if you would like.

Categories