Laravel abstract class auto injection - laravel-5

Laravel auto injects abstract class , but when there is another parameter with abstract class, Laravel ignore it and hence, getting error.
public interface PostRepository {
public function getPostById($id)
}
class EloquentPost implements PostRepository{
public function getPostById($id){
return Post::find($id);
} }
Its working fine when I use it like:
class Controller PostController {
private $post;
public function __construct(PostRepository $post)
$this->post = $post;
}
But when I use it like
class Controller PostController {
private $post;
public function __construct($someOtherParam, PostRepository $post)
$this->post = $post;
}
then Laravel show error.

Laravel is unable to determine what should be injected as the first parameter to the controller's constructor as you have no type hint for that parameter.
If that $someOtherParam is something that should come in the URL, you will be able to have that injected in controller's action method to which given route points, but not in the constructor.

Related

Can I use a constructor in Laravel's Form Request class?

I'm trying to use a constructor inside my CreateLeadRequest class, but it seems to be failing.
class CreateLeadRequest extends FormRequest
{
private $dealer;
public function __construct() {
parent::__construct();
$this->dealer = Dealer::findOrFail($this->dealer_id);
}
}
$this->dealer_id is coming in as null. I can use it inside prepareForValidation and other functions just fine, so why is it coming in as null inside the constructor?

Laravel contextual binding to be more specific to methods rather then class only

I am trying to understand laravel bind.
let's say, I have UploadFileController.php
Route::post('/upload/images', 'UploadFilesController#uploadImage');
Route::post('/upload/pdf', 'UploadFilesController#uploadPdf');
then in the controller,
class UploadFilesController extends Controller
{
private $uploadServiceInterface;
public function __construct(UploadServiceInterface $uploadServiceInterface)
{
$this->uploadServiceInterface = $uploadServiceInterface;
}
public function uploadImage(Request $request)
{
$this->uploadServiceInterface->store();
}
public function uploadPdf()
{
$this->uploadServiceInterface->store();
}
}
Now, the uploadServiceProvider,
class UploadServiceProvider extends ServiceProvider
{
public function register()
{
$this->app->when(UploadFilesController::class)
->needs(UploadServiceInterface::class)
->give(ImagesUploadService::class);
}
}
Now, I know "when" says that UploadFileController class with uploadService interface will give the imageUploadService but is it possible I make it more specific to function in uploadFileController class, like
$this->app->when(uploadFilesController::uploadImage())
->needs(UploadServiceInterface::class)
->give(ImagesUploadService::class);
then it takes to the imagesUploadService class same for pdf upload class.

Laravel 5.8 dependecy injection - how to inject model to service

I have BooksService class which should be injected by Book model object. Then I want to inject BooksService to BookController. But I dont know ho to do it.
I am getting an error Class App\Model\BookService does not exist. Is it neccesary to register it somewhere? Also I am not sure if I am doing it right. Is it in this code?
BookService
namespace App\Model;
class BookService
{
/** #var Book */
public $books;
// I am not sure if this is ok
public function construct(Book $books)
{
$this->books = $books;
}
public function test()
{
dd($this->books);
}
}
BookController
namespace App\Http\Controllers;
use App\Http\Requests\StoreBook;
use App\Model\Book;
use App\Model\BookService;
use Illuminate\Http\Request;
class BookController extends Controller
{
....
// This throws me an error BookService does not exists
public function create(BookService $bookService)
{
$bookService->test();
return view('book.create');
}
....
}
So the problem is that __contruct() method expects Book facade instance but Laravel does not know what is it. Also Book facade is available from inside the service class so no need to be injected to it.

How do I do the type-hint 'automatic injection' custom class laravel

Below is the EmailNotifier Class
class EmailNotifier
{
public function notify()
{
echo 'Sending payment notification via email' ;
}
}
Below is my AppServiceProvider
class AppServiceProvider extends ServiceProvider
{
public function boot()
{
}
public function register()
{
$this->app->make(App\EmailNotifier::class); // resolve the EmailNotifier Class
}
}
Below is billing class
class Billing
{
protected $notifier;
public function __construct(EmailNotifier $notifier)
{
$this->notifier = $notifier;
}
public function pay()
{
// Process the bill payment
$this->notifier->notify();
}
}
and in my controller I did
$data = new Billing(1);
As you can see I already resolve the EmailNotifier Class at the AppServiceProvider Class but when I call that like the code above, it throws an error said 'must be an instance of EmailNotifier'
and based on the laravel documentation, it's stated that :
you may "type-hint" the dependency in the constructor of a class that
is resolved by the container (for the automatic injection)
how do I achieve automatic injection for the type-hint in laravel ?
Use $data = resolve(Billing::class); instead of $data = new Billing(1); and you can remove $this->app->make(App\EmailNotifier::class); // resolve the EmailNotifier Class from service provider's register method.

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

Resources