I want to know if this is a good practice to use my model class in controllers in this way :
public function __construct(Rule $rules)
{
$this->rules = $rules;
}
I do not want to repeat myself in my controllers so I want to know what is the best approach for that
You use Dependency Injection - it is very good practice.
According to documentation:
Dependency injection is a fancy phrase that essentially means this: class dependencies are "injected" into the class via the constructor or, in some cases, "setter" methods.
namespace App\Http\Controllers;
use App\User;
use App\Repositories\UserRepository;
use App\Http\Controllers\Controller;
class UserController extends Controller
{
/**
* The user repository implementation.
*
* #var UserRepository
*/
protected $users;
/**
* Create a new controller instance.
*
* #param UserRepository $users
* #return void
*/
public function __construct(UserRepository $users)
{
$this->users = $users;
}
/**
* Show the profile for the given user.
*
* #param int $id
* #return Response
*/
public function show($id)
{
$user = $this->users->find($id);
return view('user.profile', ['user' => $user]);
}
}
In this example, the UserController needs to retrieve users from a data source. So, we will inject a service that is able to retrieve users. In this context, our UserRepository most likely uses Eloquent to retrieve user information from the database. However, since the repository is injected, we are able to easily swap it out with another implementation. We are also able to easily "mock", or create a dummy implementation of the UserRepository when testing our application.
Read also about Service Container - it is powerful tool:
https://laravel.com/docs/5.6/container
It is a good practice for injecting models in controllers, however, the recommended approach is:
Have a use statement at the top of your controller file
Implement it in the functions that requires access to the model, i would not recommend you do it in your controller
If you have a look at the documentation, you will be able to bind the model directly to your route and eliminate some hassle of Model::find(id) https://laravel.com/docs/5.6/routing#route-model-binding
The constructor approach you presented is recommended in using other classes like repositories, singletons, or whatever functionality you wish to inject, see the docs for more info: https://laravel.com/docs/5.6/container
Hope this helps
Related
In my app I have a service called "LogService" to log events and other items. I basically need to use this on every controller to log events by users. Instead of having to instantiate this service in each controller, I had two thoughts for accomplishing this.
Option 1: Bind the service into the IoC and then resolve it that way
Option 2: Make a master class with the service in it and then extend it for other classes so they come with the service already bound
I have questions for each of these methods:
Option 1: Is this even possible? If so, would it just be with "App::make()" that it would be called? That way doesn't seem to play too well with IDE's
Option 2: I have done this kind of thing in the past but PHPStorm does not seem to recognize the service from the parent object because it is instantiated by "App::make()" and not through the regular dependency injection.
What would be the best course of action?
Thanks!
You can have it both ways, I think the neatest way would be:
1) Have an interface that describes your class, let's call it LogServiceInterface
2) Create a Service Provider that instantiates your class, like so:
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
class LoggerServiceProvider extends ServiceProvider
{
/**
* Register bindings in the container.
*
* #return void
*/
public function register()
{
$this->app->bind(LogServiceInterface::class, function($app)
{
return new LogService();
});
}
}
3) Register this service provider in config/app.ph file:
'providers' => [
// Other Service Providers
App\Providers\LoggerServiceProvider::class,
],
4) Now, in controller you can request the instance of something that implements LoggerServiceInterface straight in the constructor:
(Some controller):
<?php namespace App\Http\Controllers;
use Illuminate\Routing\Controller;
use App\Repositories\OrderRepository;
class OrdersController extends Controller {
/**
* The logger service.
* #var LoggerServiceInterface $loggerService
*/
protected $loggerService;
/**
* Create a controller instance.
*
* #param OrderRepository $orders
* #return void
*/
public function __construct(LoggerServiceInterface $loggerService)
{
$this->loggerService = $loggerService;
}
/**
* Show all of the orders.
*
* #return Response
*/
public function index()
{
// $this->loggerService will be an instance of your LoggerService class that
// is instantiated in your service provider
}
}
This way, you have got an easy way to quickly change the implementation of your service, moreover, Phpstorm can handle this very easily.
You will still be able to use app()->make() to obtain an instance of your service.
This, however, will not be automatically picked up by Phpstorm. But you can help it to understand that, all you need to do is to use #var annotation, see:
/**
* #var LoggerServiceInterface $logger
*/
$logger = app()->make(LoggerServiceInterface::class);
That way, Phpstorm will know what to expect from that $logger object.
To handle some logic of my application I created a Service in App/Services/CarsService.php.
I injected this service in my controller through DependencyInjection like so:
CarsController.php
<?php
namespace App\Http\Controllers;
use App\Services\CarsService;
class CarsController extends Controller
{
/** #var CarsService $carsService */
private $carsService;
/**
* Create a new controller instance.
*
* #param CarsService $carsService
*/
public function __construct(CarsService $carsService)
{
$this->carsService = $carsService;
}
So for example when I want to query all the cars with some parameters provided by the user I do something like this in one of my controller methods:
$cars = $this->carsService->getCars($brand, $type);
This keeps my controller clean and my logic is seperated in a Service, seems pretty good and clean to me.
But my question is actually if this is bad practice to do in Laravel? I imagine that there might be a more "Laravel-y" way to handle this.
You don't want to use a service for that. Inject and use model if you're using Eloquent. Or use repository if you're using Query Builder, raw queries or API. For example:
public function __construct(Car $car)
{
$this->car = $car;
}
$this->car->getByBrandAndType($brand, $type);
If you're asking about is using IoC container a good or a bad practice, it's definitely a good tool to use in any app.
How can i implement laravel contracts and service providers ?
I have a class Cart and its method purchase , the class will of course contain my program structure to which most of my controllers will rely upon.
How can effectively manage dependency injection of this class among other controllers ?
You can simply reference the class as dependency in your controller. It will be instantiated even if you don't use an interface.
<?php
namespace App\Http\Controllers;
use App\Users\Repository as UserRepository;
class UserController extends Controller
{
/**
* The user repository instance.
*/
protected $users;
/**
* Create a new controller instance.
*
* #param UserRepository $users
* #return void
*/
public function __construct(UserRepository $users)
{
$this->users = $users;
}
}
If you were to use an interface just make sure your class implements it and simply call use the bind method from the app instance in any of your service providers.
$this->app->bind(UserRepository::class, EloquentUserRepository::class);
https://laravel.com/docs/5.2/container
https://laravel.com/docs/5.2/providers
I am using Laravel 5.1 and have set up a Repository pattern. I have the concrete implementations of my repos injected into my controllers. I realize that your SUPPOSED to inject the interface but that over complicates my API and doesn't solve my issue. I have a client config that simply contains a string such as '' and I am already using that globally to use model overrides if they exist.
So, for example, if I have client 'yahoo' and they have an override in my Overrides/Yahoo/Models/User.php then it will use this User.php. Whether its an extension of the base User model or a whole new implementation is up to me.
I am trying to do the same thing for my repositories. I want to be able to put an override file in Overrides/Yahoo/Repos/UserRepository.php and on injection it will either use the base User repository or the override if it exists.
Any ideas of how I can accomplish this? I realize that you can inject a repository interface and use a binding but I want to do this globally. If you can tell me how I can abstract that functionality to automatically bind the correct implementation of the interface based on client config I would accept that.
You can resolve your concrete implementation by the configuration you use, but it requires that you use interfaces.
Example configuration (config/client.php):
<?php
return [
'users' => [
'repository' => \App\Overrides\Yahoo\Repos\UserRepository::class,
],
];
In your AppServiceProviders register method:
/**
* Register any application services.
*
* #return void
*/
public function register()
{
$this->app->bind(
UserRepositoryInterface::class,
config('client.users.repository')
);
}
In your Yahoo UserRepository, you can then inject the Yahoo User model directly:
<?php
namespace App\Overrides\Yahoo\Repos;
use App\Repos\UserRepositoryInterface;
use App\Overrides\Yahoo\Models\User;
class UserRepository implements UserRepositoryInterface
{
private $user;
public function __construct(User $user)
{
$this->user = $user;
}
// TODO: Implement UserRepositoryInterface methods
}
Finally, in your UserController you can inject the UserRepositoryInterface and it will bind the concrete implementation based on your configuration:
<?php
namespace App\Http\Controllers;
use App\Repos\UserRepositoryInterface;
class UserController extends Controller
{
private $users;
public function __construct(UserRepositoryInterface $users)
{
$this->users = $users;
}
}
It might seem overkill at first, but once you set up everything it's pretty easy to add new overrides.
You could even create a base concrete implementation of the UserRepository and make every override repository inherit from it. This way you don't have to re-implement all methods required by the interface, but you stay flexible when the user repositories use different database technologies (SQL, MondoDB...)
I've used another class as Dependency Injection is it good to work around or I've messed up the OOP way.
Helper.php
class Helper {
public function getModulePermission($role_id, $module, $type) {
// my work code
}
}
DesignationController.php
use App\Helpers\Helper;
class DesignationController extends Controller {
protected $designation;
protected $helper;
/**
* #param DesignationContract $designation
* #param Helper $helper
*/
public function __construct(DesignationContract $designation, Helper $helper) {
$this->designation = $designation;
$this->helper = $helper;
}
/**
* Display a listing of the resource.
*
* #return Response
*/
public function index(Request $request) {
$permission = $this->helper->getModulePermission($request->id, 'Designation', 'view');
if ($permission) {
return true;
} else {
return view('errors.forbidden');
}
}
So I've a class named Helper which can be accessed within each and every controller for checking permissions but I thought that I've messed up the OOP functionality over here. Is it good to work like it as or I need to create an Interface instead of class
Those are two different OOP concepts. the interface forces whoever class implement it to implement functions stated in the interface (called function signature). So for multiple classes implement the same interface, you will end up with multiple classes implement the same set of functions (wither it is the same function body or not).
The second concept is called, dependency injection or inversion of control in some cases. you inject a class either via class constructor or via setters and you call certain function provided by the injected class. Here you will have the same function called by multiple classes which is good for less modification by using common (injected) class, easier unit-testing (you can mock objects easily), more modular code (you can inject different class if you want different functionality).
So the current situation is good enough but it all depends in what you want to do which stated above.
I don't like the name, it speaks nothing to me or gives me an idea that this class can help me get the permissions of the module. Moreover, with a name like this, one can simply put another method, like lets say Helper::login($id) or you name it, which will instantly break the single responsibility principle (laravel controllers do that anyway).
The injection is relatively OK, perhaps a middleware class would be better place to do that.