I setup the dependency injection as I felt it should go into my Patient Controller but for some reason it will never execute the dependency on the index function on the last line, it will even return the $request data before it but for some reason will not execute the data in the Patient Repository I attempt to return.
I have attempted to just do:
return (new Patient)->getByAccNumAndDateOrZip($this->client_code, $this->account_number, $this->dob, $this->zip);
Also, keep in mind yes all $requests do have a valid value and do not return a empty or null value.
And still get nothing back....
namespace App\Http\Controllers\api;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
//Repositories
use App\Repositories\Patient;
class PatientController extends Controller {
private $patient;
public function __construct(Patient $patient) {
$this->middleware('auth.client');
$this->patient = $patient;
}
public function index(Request $request) {
//I can do return $request->client_code
//But I can't use this dependency... It's weird...
return $this->patient->getByAccNumAndDateOrZip($request->client_code, $request->account_number, $request->dob, $request->zip);
}
}
I'm expecting to call to my dependency that pulls all the my patients by account number. The dependency is just a standard class with a namespace of App\Repositories it has no set constructor just a couple standard public functions that will take specific variables in the function.
After reviewing the log files in laravel I was able to see that the system was stating that the class name has already been used so I would have to choose something else.
This was suggested by Matt Wohler to check the logs and boy did it help me!
Thanks Again for all the help!
Related
I have two controllers (FirstController, SecondController) that use the same functions, to avoid rewriting them I thought of creating another controller (ThirdController) and subsequently calling the functions through it.
the problem is that if in ThirdController there are relationship query they give me the error that "they don't exist".
example:
User Model
class User extends Authenticatable implements AuthenticatableUserContract
{
use HasFactory, Notifiable;
public function comments(){
return $this->hasMany('App\Models\Comment');
}
ThirdController
class ThirdController extends Controller
{
public static function example($id){
$comments = Comment::find($id)->comments();
return $comments;
}
}
FirstController/SecondController
public function example2(Request $request){
return ThirdController::example($request->id);
When call the route it give me error:
BadMethodCallException: Method Illuminate\Database\Eloquent\Collection::comments does not exist.
my questions are:
Is there any better method instead of creating a third controller?
Is there a solution to this?
p.s. I know I could very well build the queries without exploiting the relationship, but where's the beauty of that? :D
You do not need to create 3rd controller. You can create a class and here you write the query in a function and use this class in controller1 and controller2 by dependency injection.
First thing that's not a best practice to define a static method in one controller and call it in another controller (not recommended way).
Second you're calling Comment::find($id) with comments() relation. you should call a User class, like below snippet:
class ThirdController extends Controller
{
public static function example($id){
$comments = User::find($id)->comments();
return $comments;
}
}
RECOMEND APPROACH:
Creat a one seperate service/repository class in which you'll define a common method i.e. getUserComments() and use it in both or all of three controllers (upto your requirement/needs). By this way you implementations will be on a centric place.
If you want learn about Repository pattern you can get basic idea from: Article#1
I'm trying add dependency injection on User class and after few hours trying, I found this way:
I added this code to App\Models\User class
public function __construct()
{
$this->roleService = resolve(RoleService::class);
}
I've checked $this->roleService value, it work normally, buut when I try to use it in a function:
public function isAdmin() {
return $this->roleService->isAdmin($this->role_id);
}
This function throw an error Call to a member function isAdmin() on null. When I logged $this->roleService, it returned null.
Anyone can solve this?
Create a custom accessor for your model, and get/set the value from there.
public function getRoleServiceAttribute ()
{
if(is_null($this->roleService)){
$this->roleService = resolve(RoleService::class);
}
return $this->roleService;
}
Then you can access the attribute as $this->role_service
Also make sure you declare the $roleService class property as protected, to avoid accidental access as $this->roleService from anywhere else.
Thank for help. I just have referenced answer of an expert. He said that we should not dependency injection in Model class because it will broke project structure. Project should be followed structure: Controller->Service->Repository->Model->Database. So, I'll refactor my code follow it.
I am trying to do a hello world service provider with the new Laravel 5.4.
I have created the following service provider file:
//File: app/TestProvider/TestServiceProvider.php
namespace App\TestProvider;
use Illuminate\Support\ServiceProvider;
class TestServiceProvider extends ServiceProvider
{
/**
* Register bindings in the container.
*
* #return void
*/
public function register()
{
$this->app->bind('Test', function ($app) {
return new Test();
});
}
}
I have created a simple class under the same namespace:
//File: app/TestProvider/Test.php
namespace App\TestProvider;
class Test
{
/**
* Register bindings in the container.
*
* #return void
*/
public function helloWorld()
{
echo "hello world";
}
}
The problem is, this is not registering. The register method is executing as when I put a breaker before the 'bind' method, it executes:
public function register()
{
dd("BREAKER");
$this->app->bind('Test', function ($app) {
return new Test();
});
}
So this outputs "BREAKER" as expected. However if I put the breaker in the closure, nothing happens which suggests for some reason, that 'bind' method isn't being executed??
Any ideas?
EDIT:
Just some further info: I know that the Test class is registered and in the correct namespace as I can do:
dd(new Test());
in the registration method, and it outputs the resource id as expected.
Explanation
The closure provided only runs when the binding is being resolved. That's why it's a closure, it can be saved in the service container and resolved at any time while the program runs.
Solution
To see the resolved binding, create a controller and resolve the class in that controller:
// File: app/Http/Controllers/TestController.php
namespace App\Http\Controllers;
// This isn't the best way, but it works. See the best way below
class TestController extends Controller {
public function index()
{
return \App::make('Test')->helloWorld();
}
}
Of course, don't forget to register the route:
// File: routes/web.php
Route::get('/', 'TestController#index');
The binding will resolve when you hit the homepage.
However, as I said, it's not the best way, so here I prepared a better way. Change the way you register the binding:
// File: app/Providers/TestProvider.php
namespace App\TestProvider;
use Illuminate\Support\ServiceProvider;
use App\TestProvider\Test;
// Better way
class TestServiceProvider extends ServiceProvider
{
/**
* Register bindings in the container.
*
* #return void
*/
public function register()
{
// Note: we bind the exact complete class name!
$this->app->bind(Test::class, function ($app) {
return new Test();
});
}
}
After this change the controller so that it looks like this:
namespace App\Http\Controllers;
use App\TestProvider\Test;
class TestController extends Controller {
/**
* #var Test $test
*/
private $test;
// Let Laravel resolve the dependency on constructing the class
public function __construct(Test $test)
{
$this->test = $test;
}
public function index()
{
return $this->test->helloWorld();
}
}
You will see that the exact same thing happens, but it looks more elegant and avoids conflicts.
Details
Laravel gives only a high level overview of the service container, which doesn't help to learn how it works on the inside. The best way to see that is to go down the call stack.
When you do that, you find that Laravel registers every class in the project in the service container. That means that whether you create a service provider or not, the class will be in the container. How exactly?
When you run php artisan optimize, Laravel creates files that have array with all the classes of the project. When you run the app, after registering everything from the service providers, Laravel registers the rest of the classes from that file.
That means that in your case, if you don't specifically register the Test class, it will still be resolvable. Basically, you only need to register classes that need some specific instructions to be resolved.
So how does Laravel resolve the dependencies?
When you run \App::make(Test::class) or inject dependency via type hinting in the constructor (the "better way" from my solution), Laravel looks for that dependency among the bindings.
When it finds the dependency, it resolves either the closure associated to it or the constructor of the class directly.
When it resolves the constructor directly, it looks for type hints among the constructor parameters and recursively resolves all of them until there's nothing else to resolve.
After that it returns the resolved class.
Of course, bear in mind that for Laravel to analyze the contructor of a class, it needs to be resolved via the service container in the first place. You can't just call $test = new Test(); and expect Laravel to do all the magic :)
Conclusion
This is a rather quick overview of Laravel's service container. The best way for you to learn it is, of course, studying the sources for yourself. It's truly elegant and it uses PHP's functionality to the fullest.
I really hope this shed some light on the service container for you and can help you in the future :)
The closure passed to the bind() method is not executed until you actually attempt to resolve the alias you are binding.
So, if you dd('breaker') inside the closure, this won't actually get executed until Test is resolved (whatever your preferred resolution method is):
Service provider:
// bind the closure to the 'Test' alias
public function register()
{
$this->app->bind('Test', function ($app) {
dd("BREAKER");
return new Test();
});
}
Code that resolve Test alias:
// different ways of resolving the alias out of the container.
// any of these will execute the bound closure.
$test = resolve('Test');
$test = app('Test');
$test = app()->make('Test');
$test = \App::make('Test');
try:
$this->app->bind(Test::class, function ($app) {
return new Test();
});
I have one FrontendController that get all requests from frontend. As all URLs are like:
Route::get('/{slug}', 'FrontendController#index');
I need to use the same controller to get all Entities. My FrontendController looks like this:
use Auth;
use App;
use Cache;
use URL;
use Redirect;
use Session;
use Response;
use App\Country;
use App\I18n;
use App\User;
use App\CMS;
use App\CMSPageContent;
use App\Slugs;
use App\News;
...
...
use App\Http\Controllers\Controller;
I have several questions regarding this:
Are ALL these services injected in each execution of FrontendController. Because maybe I'm loading the entire code and It will make my page load slow.
If answer to previous question is yes, can I load a library only if one function is called?
Is it a good way to solve the slug problem? Because all URLs have one piece only for SEO reasons and I don't know other way to treat the routes.
It varies depending on how you are using the code. For example if you required the Auth login method, but nothing else, it would be a waste of resources to initialise a model or inject the model into that function.
For example say this is a function in my model
public function doSomething()
{
//Do stuff
}
I would like to call this function in my Controller. I have a few options, I could reference the model at the top of my controller
use App\MyModel;
I believe this doesn't actually initiate the model, it acts like a reference, so that when it is called, the system knows where to find it.
I could inject it into my function
public function myControllerFunction(\App\MyModel $model)
{
return $model->doSomething();
}
This uses the most resources due to the model being assigned to the $model variable, which is fine if you need the models eloquent for database actions and its functions. If you require just one function from that model then a static call would use less resources.
In your model make the function static
public static function doSomething()
{
}
Then in your controller you can call it like this
public function myControllerFunction()
{
return \App\MyModel::doSomething();
}
This would use the less resources and would clean up the code a bit as you wouldn't need to keep referencing your uses at the top of the controller
Take a look to that code
<?php
namespace Sestante\SestanteBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use Sestante\SestanteBundle\Model\StrutturaManager;
class MainController extends Controller
{
public function indexAction(Request $request)
{
return $this->render('SestanteSestanteBundle:Main:index.html.twig');
}
public function showLodgingsAction(Request $request)
{
$repo = $this->getDoctrine()->getRepository('SestanteSestanteBundle:Struttura');
$usr = $this->get('security.context')->getToken()->getUser();
$usrId = $usr->getId();
$sm = new StrutturaManager($repo);
$lodgingList = $sm->retrieveLodgingsFromUser($usrId);
return $this->render('SestanteSestanteBundle:Main:showLodgings.html.twig',array('lodgingList' => $lodgingList));
}
}
This is a controller for an application that I've been writing.
Take a look to showLodgingsAction. I've tryied to place all business logic into a model (StrutturaManager) that with a repository (that I've passed directly from controller because, as far I know, they're available only here or via D.I.) query my db, do some elaboration and return a list that I'll render onto a template.
First question: Is this "code separation" good, or exists a better way for do what I'm trying to do?
Second question: suppose that, now, I want to use an object of StrutturaManager type into indexAction. Remember that mine object want a repository. So, have I to declare again, and again, and again, all my object for every controller's action where I want to use them? I suppose that must exist a smarter method but, at the moment, I don't understand which.
Define StrutturaManager as a service and inject the EntityManager into it. This way the manager will have access to repositories you need and controllers won't know about Doctrine nor repositories — which is a good practice.