Laravel dependency injection without relying on the controller - laravel

I'm trying to figure out how to inject a dependency into a class in Laravel.
My structure:
SimpleController extends BaseController
{
public function example(SimpleModel $model, SimpleValidationRequest $request)
{
$result = $model->doStuff()
return $this->makeResponse($result);
}
}
SimpleModel extends Model
{
public function doStuff(ComplexService $service)
{
$service->doComplexLogic($this);
}
}
I have registered the ComplexService in my own service provider:
class AppServiceProvider extends ServiceProvider
{
public function register()
{
$this->app->singleton(ComplexService::class);
}
}
I want to inject the service straight into the simpleModel's doStuff method, without having to inject it into the controller and then into the model. We're busy moving a monolithic application to Laravel and have service classes that contain all the complex business logic. Much of the logic is shared between different classes, so a controller method might call a model that calls a service that ends up making 4 or 5 calls to other services, and I want to be able to inject another service into any method that needs it without having to send it down from the controller all the way through to the bottom method that might need it.
Is there a way to do this? I have been looking online but everything I've found has required me to inject the service into the controller and then sending it through the application from there, which I want to avoid.

You can simply call the singleton inside the method via the app() helper
SimpleModel extends Model
{
public function doStuff(ComplexService $service)
{
app()->singleton(ComplexService::class)->doComplexLogic($this);
}
}
or recover the singleton by injecting it in the model via it's __construct() method.

Related

Service layer in laravel 5.7

I have gone through the Laravel documentation and found that every request follows the Middle layer -> Controller layer -> Resource Layer flow.
But for my project I have a huge business processing logic which needs to be written. So, I am looking for a service layer option where execution control will be passed from Controller and then service layer will do the processing logic along with database fetch. But I didn't find anything linked with service layer part in artisan.
So, can you suggest me how can I implement a service layer in my project?
What about creating a Services folder under app/, and use Controllers dependency injections?
It would be something like this:
MyService.php
<?php
namespace App\Services;
use App\Models\Bar;
class MyService
{
public function foo(Bar $bar)
{
// do things
}
}
MyController.php
<?php
namespace App\Http\Controllers;
use App\Services\MyService;
use App\Models\Bar;
class MyController extends Controller
{
protected $myService;
public function __construct(MyService $myService)
{
$this->myService = $myService;
}
public function handleRequest(Bar $bar)
{
$this->myService->foo($bar);
}
}

How to use different method of a controller in laravel application

In my laravel application i should use some create and update method of some controller in another controller
According to my search is not a good thing to call a method from controller in another
I cant see the why don't call a controller method in another controller
I'm doing this way :
class Controller extends BaseController
{
protected $variable;
public function __construct()
{
$this->variable = "Hello";
}
}
and
class ClientController extends Controller
{
public function __construct()
{
parent::__construct();
}
}
The __constructor is a magic method of class. It calls when you trying to create instance of class. So there is no way to use constructor without creating an instance or extendeding from another class. If you have a common code in different classes there a best way to use traits. thats give you an opportunity to include your trait and use methods ,making your code beutiful , flexible , readable following principes DRY,KISS.
you can create a base class with constructor and extend other controller of it
or you can put your code in to Http\Controllers\controller.php ('main controllers constructor')
also you can use trait

Laravel: use extended controller or Traits or something else?

To maintain my Laravel application and save myself from a lot of duplicate code I have made the following solution:
BaseController
class BaseController extends Controller
{
public function get($id){
return $this->baseService->get($id);
}
public function getAll(){
return $this->baseService->getAll();
}
}
BaseService
class BaseService
{
protected $model;
public function __construct($model){
$this->model = $model;
}
public function get($id){
return response()->json($this->model->where('id', $id)->first());
}
public function getAll()
{
return $this->model->get();
}
}
MyController
class MyController extends BaseController
{
protected $model;
protected $baseService;
public function __construct(){
$this->model= new Model();
$this->baseService = new BaseService($this->model);
}
/**
* This controller has all the functionality from BaseController now
*/
}
What I'm wondering if this is a good method. Should I stick with this or should I use a different approach? I've heard about Traits but not sure if they are doing the same thing. It's Laravel 5.5 I'm using.
Yes, traits are used to move methods out of a controller regularly. A good example that the Laravel framework uses is the ThrottlesLogin trait. Take a look at https://github.com/laravel/framework/blob/5.5/src/Illuminate/Foundation/Auth/ThrottlesLogins.php#L20
to see how the methods are moved outside of a controller but can be still accessed by importing the trait using the use keyword.
While traits would work for your use case I wouldn't use them here for the functionality you are looking for. I would use the repository pattern. It would better separate your code and make it more reusable.
Take a look at https://bosnadev.com/2015/03/07/using-repository-pattern-in-laravel-5/ for more information on the repository pattern. Basically, you would separate your code into a separate repository and use Laravel's built in IoC to inject the repository into your controller.
MyController
class MyController extends Controller
{
protected $repo;
public function __construct(MyRepository $myRepository)
{
$this->repo = $myRepository;
}
public function index()
{
$myStuff = $this->repo->all();
}
// you can also inject the repository directly in the controller
// actions.
// look at https://laravel.com/docs/5.5/controllers#dependency-injection-and-controllers
public function other(MyRepository $repo)
{
$myStuff = $repo->all();
}
}
This is the perfect use case for a Trait. Traits are intended for reusable functions. They're super simple to implement, and won't take more than a few minutes to change what you have.
Here is a great article on them: https://www.conetix.com.au/blog/simple-guide-using-traits-laravel-5

Issue in creating REST Service using laravel

We are trying to develop an Android app that required a REST API to show data from web server.
We tried to use Laravel resource to create REST service like below:
Route::resource('list', 'ListController');
namespace App\Http\Controllers;
use mymodel
class ListController extends Controller
{
public function getShow($id)
{
$Jsondata=list($id);
return $JsonData;
}
}
But it's not working as expected need some token key or some other authentication and authorization need to know how to set.
We should utilize the Repository / Gateway design pattern:
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 we 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 we 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 our User web controller. This controller talks to our 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.
Number one is that what is not working? if you mean that the response is not showing then its because your function actually doesn't even seem to be going any where, and number two are you new to Laravel?
Okay if this is what you have:
namespace App\Http\Controllers;
use mymodel;
class ListController extends Controller
{
public function getShow($id)
{
$Jsondata=list($id); return $JsonData;
}
}
Then I can be safe to say a lot of things is wrong.
To my understanding using Route::resource('list', 'ListController'); in your routes file creates show, edit, update and destroy paths, and also expects to see these functions too (I have not proven this to the core though) but thats my understanding.
so you can simply start laravel life by doing having your routes with
Route::get('list', 'ListController#show')
Then change your ListController to something like this:
namespace App\Http\Controllers;
use mymodel;
class ListController extends Controller
{
public function show($id)
{
$jsonData= ['my' => 'json data'];
return $jsonData;
}
}
If this works for you, then cool else so many thing might already be wrong with your setup.
Note: you might need to take your time to learn to use laravel from the documentation page. If API is your interest then try DIngo api. Also try to learn to use markup :)
Hope this helps :)

Declare value ONCE to use in multiple controller methods - Laravel 5.2

I currently have to declare my Stripe api key in every controller method that will make an api call to Stripe. For example
public function __construct()
{
\Stripe\Stripe::setApiKey(env('STRIPE_KEY'));
}
public function addCard()
{
Stripe::setApiKey(env('STRIPE_KEY'));
}
public function updateCard()
{
Stripe::setApiKey(env('STRIPE_KEY'));
}
public function deleteCard()
{
Stripe::setApiKey(env('STRIPE_KEY'));
}
This is getting very annoying as I have more than 10 methods that are doing this. My question is, is there a way i can declare the key somewhere ONCE and not have to call it in every controller method?
Yep, I'd do it in your AppServiceProvider. You'll find this at app/Providers/AppServiceProvider.php.
Stick it in the register method:
public function register()
{
Stripe::setApiKey(env('STRIPE_KEY'));
}
That will run during bootstrap for every request.
Alternatively you could set this in the constructor for your Controller. This would cause it to run for all actions in this one controller only.
class PaymentController extends Controller {
public function __construct() {
Stripe::setApiKey(env('STRIPE_KEY'));
}
public function addCard() {
...
I'd argue this is less desirable, your service providers should primarily be responsible for wiring up your dependencies. Up to you.

Resources