I am getting error:
GitHubApp::__construct() must be an instance of App\Project\Repositories\GitProviderRepository
I thought Laravel does some kind of magic when it come to __construct() so i don't have to inject it into new GitHubApp();?
use App\Project\Repositories\GitProviderRepository;
class GitHubApp
{
private $gitProviderRepository;
public function __construct(GitProviderRepository $gitProviderRepository)
{
$this->gitProviderRepository = $gitProviderRepository;
}
}
In other class:
return new GitHubApp();
When calling new GithubApp(), you relied on yourself to build the GithubApp instance, Laravel does not responsible for building that instance.
You have to let Laravel resolve the dependencies for you. There are numbers of way to achieve this:
Using App facade:
App::make(GithubApp::class);
Using app() helper method:
app(GithubApp::class);
Or using the resolve() helper method:
resolve(GithubApp::class);
Behind the scene, your class type and its dependencies will be resolved and instantiated by the Illuminate\Container\Container class (the parent class of Application). Specifically by the make() and build() methods.
Hope this help! :)
You can try as:
return app(GitHubApp::class);
or
return app()->make(GitHubApp::class)
It is done by the powerful IoC container of Laravel to resolve classes without any configuration.
When a type is not bound in the container, it will use PHP's Reflection facilities to inspect the class and read the constructor's type-hints. Using this information, the container can automatically build an instance of the class.
Docs
Related
I'm trying to implement a simple DI in a pure OOP application. I wanted to use Dependency injection to manage many services ( Database, RequestValidator, Cache etc. ). I have read many blogs and liked this one from tech-tajawal but I could not really understand where should I include the container that tech-tajawal wrote. Can someone please show me how to do it?
I want it clean and thus want to use constructor based injection. So If I have a class, let's say AbstractBaseController which will inject a dependency called Request, so I will write:
php:
<?php
namespace src\controllers;
use system\middlewares\Request as Request;
abstract class AbstractBaseController {
private $request;
public function __construct(Request $request) {
$this->request = $request;
return $this;
}
}
But this simply throws
Fatal error: Uncaught TypeError: Argument 1 passed to src\controllers\AbstractBaseController::__construct() must be an instance of system\middlewares\Request, none given`
I think the container from tech-tajawal has to be included in my project root someway but I don't know how.
Please excuse my naivety here as I always was framework dependent.
You should instantiate your container at the very beggining of your application (think of a bootstrap class, or even at the top of index.php itself, considering a very simplistic application), because you will need the container to be ready before all the subsequent instantiations of services.
The only other thing that could probably be executed before the container instantiation are those related to configuration, because those are usually needed for the container to work properly (configuration parameters, PSR-4 autoloading configuration, etc).
For example, suppose that you have a class called MyController that extends the abstract class AbstractBaseController.
Then, on index.php, for example, you could instantiate your container and your controller:
//index.php
$container = new Container();
$controller = $container->get('namespace\of\MyController');
$controller->render();
When you do that, all the dependencies from the constructor would be handled by the autowiring module of your container library.
In a real life application, the instantiation of a controller would be usually handled inside a router, which maps URL addresses, methods and parameters to different classes to be loaded by the container.
One rule of thumb with autowiring, is that you can never call new namespace\of\MyController() directly anymore, because instantiating it manually would require you to pass each of the constructor dependencies (so you are not really using the autowiring feature). The right way to instantiate it is always by using $container->get('namespace\of\MyController').
I have been struggling a bit to understand how can I make use of the Container that gives me access to the parameters located at config/parameters.yml.
The problem in my hands is I created some custom Exceptions and I created a library that slacks me every time one of those exceptions is triggered. For that, I need to send the container to the Logger in order to be able to pull those through within the library.
But I am failing to be able to grab a hold on the container. I have an idea it needs to be injected and that I could achieve such in the config/services.yml but I am failing to understand how.
So far this is what I have come to achieve:
My Custom Exception Parent
Because all exceptions extend from the parent, they will all trigger the Logger. And it is at this point I need the container to exist:
abstract class CriticalLogAlertException extends \RuntimeException
{
protected $logger;
public function __construct ($message = "", $code = 0, Throwable $previous = NULL)
{
parent::__construct($message, $code, $previous);
Log::critical(
$this->message,
[],
AbstractCredentialsFactory::YAML_TYPE,
'PARAMETERS CONTAINER ACCESS NEEDS TO BE ADDED HERE'
);
}
abstract public function generateMessage($message) : string;
}
What I though was on creating on this class a method setContainer() that I could use in my config/services.yml:
public function setContainer(ContainerInterface $container)
{
$this->container - $container;
}
So at this point I could create a property in the abstract class and use that to pass it to the library as it would be already available at class execution. Though I am not too certain this is achievable or correct;
My config/services.yml
Below is the code I added to my services container:
ExceptionContainer:
class: AppBundle\Exception\CriticalLogAlertException
calls:
- [ setContainer,[ #service_container ] ]
Could someone help me understanding if it something I am missing or misunderstanding in order to set it available?
NOTE: If there is anything else required to better understand my problem, please let me know so I can update my question :)
Thank you in advance!
Sooo, this took me a while but I had to dive deeper in order to understand, which meant to go through some fights and research before being able to start understanding it a bit better.
Was left for a while even though I got it working a while back, but for those wondering the same and new to the process let me share a bit :)
Because I was instantiating the exceptions with throw new meant I had direct access to the __construct method. This meant, if my exception was expecting a ContainerInterface I had to provide one.
Now, two case scenarious could work with this.
1. Injection
With Injection I can autowire the requirements either by using an available service (which we can check with below command);
php bin/console debug:autowiring
Or, if injecting a custom class, I needed to specify where, which and what it provides at services.yml
An possible example of what I am refering to add to services.yml can be seen below:
TestException:
class: AppBundle\Exception\TerminationAmlkyc
arguments: ['#service_container']
public: true
2. Instantiation
In my case, I either transferred the ContainerInterface whenever I needed it for a new class or was able to Instanciated as I referenced above.
Because my origin was through a ContainerAwareCommand I could make use of $this->getContainer() to retrieve it and then pass it to the exceptions whenever needed.
throw new TestException($this->getContainer())
Bit of a long winded question, but here goes. I'm a little confused regarding some of the documentation for the service container in Laravel 5.1. I'll explain my current understanding of the container first, and then explain where my confusion has arisen.
So, I'm fairly sure I understand the process of registering a binding with the service container. To quote the documentation, you register a binding using the bind method, passing the class or interface name that we wish to register along with a Closure that returns an instance of the class:
$this->app->bind('HelpSpot\API', function ($app) {
return new HelpSpot\API($app['HttpClient']);
});
Now, in the Laravel 5.0 docs, that's actually stated slightly differently:
A Closure resolver is registered in the container with a key (typically the class name) and a Closure that returns some value.
So, in Laravel 5.0, it seems you were able to bind some class, say FooBar to a key that, while recommended to be the class name, could be something different, so for example:
$this->app->bind('myfoobarclass', function($app) {
return new FooBar($app['SomethingElse']);
});
And then later you could resolve the class using:
$fooBar = $this->app->make('myfoobarclass');
However, this would remove your ability ro resolve that class using type hinting, which I'm guessing is why the docs for 5.1 states specifically to use the class name. However, in the section on Facades (http://laravel.com/docs/5.1/facades#facade-class-reference), they list the facades along with their "service container binding key", which is different to their class name. Does this mean you can't resolve these facades using type hinting? Why would they register their bindings as something other than their class name? Or is this documentation simply out of date?
If anyone could shed some light on the reasons behind this inconsistency that would be amazing, thanks in advance.
You normally bind implementations to interfaces. So instead of adding something to the service container by the name of the class, you would instead use the name of an interface it implements instead:
$this->app->bind('App\HttpClientInterface', function ($app) {
return new \Guzzle\HttpClient;
});
You can then type-hint the HttpClientInterface interface in your application, and instead get the bound GuzzleHttpClient instance. This allows you to swap your implementations out in one place without having to re-write your application code.
You’re not restricted to using fully-qualified class/interface names, you can use arbitrary strings as key names if you wish:
$this->app->bind('http.client', function () {
return new \Guzzle\HttpClient;
});
But you can’t type-hint on these; this is where you would use the app()->make('http.client') method instead.
In regards to the Façade Class Reference section of the Laravel documentation, there are two ways of resolving the services in your app.
You can type-hint on the value in the Class column, i.e. Illuminate\Contracts\Hashing\Hasher
Alternatively, you can use what’s in the Service Container Binding column with the app()->make('hash') method. These are just “aliases” for the class name.
Hope this helps!
Laravel 5 offers automatic dependency resolving if I type-hint the needed class/interface. But how should they be instantiated? Example:
public function __construct(Dependency $dependency) {
$this->dependency = $dependency;
}
And then, in another method, I'd like to create two instances, like this:
$one = new Dependency(1);
$two = new Dependency(2);
What is the most flexible and test-friendly way to do this?
Excuse my poor joke, but it depends.
It looks like you have misunderstood the dependency resolving a little bit.
In your example the property 'dependency' allready contains an instantiated object. If you need two different instances within another method you may instantiate them there, inject a container or use a factory. It depends on your needs.
a very short introduction to laravel dependency resolving
The automatic dependency resolving in laravel is provided by the service container and it is used to deliver an (allready) instantiated object. The resolved object must be binded to service container. The best way to do this is via service providers. Within the register method of a service provider you are able to do your bindings
$this->app->bind('Dependency', function ($app) {
return new Dependency();
});
In this example the container will return a new instance every time it is called.
If you need the same instance every time you may bind a singleton
$this->app->singleton('Dependency', function ($app) {
return new Dependency();
});
I am currently building an MVC application in PHP (not using any frameworks). I am using yadif (https://github.com/beberlei/yadif) for dependency injection.
I would like to build a login module. It should be able to use adapters, for example one might be able to set that logins are authenticated using the MySql database or some LDAP directory. This setting would be done in the admin area and is stored in a database.
I imagine that I would have an abstract adapter:
<?php
abstract AbstractLoginAdapter{
abstract function login($username, $pass){}
}
I would then just implement adapters like so:
<?php
MySQLLoginAdapter extends AbstractLoginAdapter{
public function login($username, $pass){
//do stuff
}
}
That's all nice and well, but how do I create an instance of the adapter? Usually, dependencies would be injected using yadif via the constructor:
<?php
class loginController{
private $_adapter;
public function __construct(AbstractLoginAdapter $adapter){
$this->_adapter = $adapter;
}
}
However, since I don't know which concrete adapter will be injected, I can't set that in a configuration before hand. Yadif allows me to create a configuration which I then need to pass to the container:
$builder = new Yadif_Builder();
$builder->bind("loginController")
->to("loginController")
->args($SelectedLoginAdapter);
Since the application uses a front controller, a DI container is created there. It then creates a routing object etc.
In light of this, should I pass a reference of that container down to the loginController object, and then use that container to instantiate my adapter?
Or should I instantiate a new container within my loginController object and then just load in an instance of the adapter?
I would do the first: pass a reference down to your controller. You'll want to use a single Dependency Injector Container (DIC) in your application. You don't want to create a new DIC whenever you need access to it. That would lead to duplication of objects stored in the DIC.
I know this is how Symfony 2 does it. All controllers (and many other classes) implement the ContainerAware interface. That interface has a single method setContainer() that is used to pass down a reference to the DIC.
I don't know about your specific DI tool but from a DI point of view you would be specifying which type to use. The container itself is responsible for instantiating a new instance (and possibly of all the dependencies of that type as well) of the configured type.
The benefit of DI in your example would be that you could deploy exactly the same code with a different configuration with 1 installation using LDAP and the other using MySQL authentication.
Refactor type hinting ("AbstractLoginAdapter") to ("MySQLLoginAdapter").
If you call abstract class method in the new __CLASS__ // Fatal Error.