I am having trouble accessing an injected service in the constructor of one of my controllers.
Per http://symfony.com/doc/current/service_container/injection_types.html I believe I have done the injection correctly, however when I try to load a view from the controller, I get the following error:
Argument 1 passed to Regions\AnalyticsBundle\Controller\PatternsController::__construct()
must be an instance of Regions\AnalyticsBundle\Controller\PatternCacheService, instance of
Regions\AnalyticsBundle\Service\PatternCacheService given, called
in /var/tmp/symfony/cache/dev/ContainerLoHUcSH/getPatternsControllerService.php on line 9
It seems like the error indicates that the type hinting in the constructor is trying making it look for an instance in the *\Controller\* namespace instead of the *\Services\* namespace - what am I doing wrong or not seeing here?
Details of my setup are as follows...
Symfony 4.1.0, PHP 7.2.5
services.yaml
services:
...
pattern_cache_service:
class: Regions\AnalyticsBundle\Service\PatternCacheService
public: true
Regions\AnalyticsBundle\Controller\PatternsController:
arguments: ['#pattern_cache_service']
Controller:
namespace Regions\AnalyticsBundle\Controller;
class PatternsController extends BaseController
{
private $pcs;
public function __construct(PatternCacheService $pcs)
{
$this->pcs = $pcs;
}
}
You forgot a use in your Controller, making PHP think that your service is in the same namespace as your controller.
<?php
namespace Regions\AnalyticsBundle\Controller;
use Regions\AnalyticsBundle\Service\PatternCacheService;
class PatternsController extends BaseController
{
private $pcs;
public function __construct(PatternCacheService $pcs)
{
$this->pcs = $pcs;
}
}
This was actually raised as part of your error message
Argument 1 passed to Regions\AnalyticsBundle\Controller\PatternsController::__construct()
must be an instance of Regions\AnalyticsBundle\Controller\PatternCacheService
When what you expected was your controller to need an instance of Regions\AnalyticsBundle\Service\PatternCacheService
The class PatternCacheService cannot be found in the namespace Regions\AnalyticsBundle\Controller.
Add an import:
<?php
namespace Regions\AnalyticsBundle\Controller;
use Regions\AnalyticsBundle\Service\PatternCacheService;
class PatternsController extends BaseController
{
private $pcs;
public function __construct(PatternCacheService $pcs)
{
$this->pcs = $pcs;
}
}
For reference, see
http://php.net/manual/en/language.namespaces.importing.php
You don't need a service definition for pattern_cache_service. It should autowire your service if autowire: true is set.
PatternCacheService should be private as you don't want to access it from within container. Suggested practise!
You don't need a service definition for PatternsController either.
Note: You should not use "bundles" anymore in Symfony 4 so I would get rid of AnalyticsBundle.
Note: Better organise your configuration files as show here: Organising route, service and parameter configuration files in symfony 4 applications.
This should suffice:
services.yaml
services:
_defaults:
autowire: true
autoconfigure: true
public: false
App\:
resource: '../src/*'
exclude: '../src/{Entity,....so on .....,Kernel.php}'
App\Controller\:
resource: '../../src/Regions/AnalyticsBundle/Controller'
tags: ['controller.service_arguments']
PatternsController
namespace Regions\AnalyticsBundle\Controller;
use Regions\AnalyticsBundle\Service\PatternCacheService;
class PatternsController
{
private $pcs;
public function __construct(PatternCacheService $pcs)
{
$this->pcs = $pcs;
}
}
I need to pass ZipArchive class as a dependency for one of my class. I hope it is possible to do but no idea how to define in services.yml file.
Any idea please.
I'd instantiate the core php object in the service construct and provide a setter to override this object (ie for testing later on):
services.yml:
app.my_service:
class: AppBundler\Services\MyService
AppBundle\Services\MyService:
namespace AppBundle\Services;
class MyService
{
protected $ziparchive;
public function __construct()
{
$this->ziparchive = new ZipArchive();
}
public function setZipArchive(\ZipArchive $zipArchive)
{
$this->zipArchive = $zipArchive;
return $this;
}
}
You can pass your ZipArchive class as service's argument
First, you need to create service for ZipArchive
services:
lib.ziparchive:
class: Lib\ZipArchive #your ZipArchive Class Namespace
Then you can pass lib.ziparchive to your class service
app.my_service:
class: AppBundler\Services\MyService
arguments: ['lib.ziparchive']
In your MyService Class, you need to create constructor.
namespace AppBundle\Services;
use Lib\ZipArchive
class MyService
{
protected $ziparchive;
public function __construct(ZipArchive $ziparchive)
{
$this->ziparchive = $ziparchive;
}
}
Check more detail for service container
Hope it help.
I am facing one problem I do not know what is a reason of this I add class with location in my project src/ApiMaps/ApiMapBundle with this name space
<?php
namespace ApiMaps\ApiMapService;
class ApiMapService {
private $transport;
public function __construct() {
$this->transport = 'sendmail';
}
// ...
}
when i give in
src/config/service.yml
app.test:
class: ApiMaps\ApiMapService\ApiMapService
arguments: ["#doctrine.orm.entity_manager"]
and when i run it from some other class for example
src/ApiMaps/ApiMapBundle/Command/GetApiCommand.php
class GetApiCommand extends ContainerAwareCommand
{
protected function execute(InputInterface $input, OutputInterface $output)
{
$number = $this->getContainer()->get('app.test');
}
}
it give me error
Fatal error: Class 'ApiMaps\ApiMapService\ApiMapService' not found in D:\xampp\htdocs\ProjectMapApiData\a
pp\cache\dev\appDevDebugProjectContainer.php on line 325
[2016-02-01 08:25:20] php.CRITICAL: Fatal Error: Class 'ApiMaps\ApiMapService\ApiMapService' not found {"
type":1,"file":"D:\xampp\htdocs\ProjectMapApiData\app\cache\dev\appDevDebugProjectContainer.php","
line":325,"level":-1,"stack":[]}
[Symfony\Component\Debug\Exception\ClassNotFoundException]
Attempted to load class "ApiMapService" from namespace "ApiMaps\ApiMapService".
Did you forget a "use" statement for another namespace?
Note--
one thing to mention that when i try to make service from the built-in class of symfony2 classes it does not give me such error. I do know where I need to add the namespace of the class which i recently added with my project that it able to know the class...
You mention that your service in file:
src/ApiMaps/ApiMapBundle
but in config you wrote:
ApiMaps\ApiMapService\ApiMapService.
I think you should house you service in file: src/ApiMaps/ApiMapBundle/ApiMapService/ApiMapService.php,
take namespace: ApiMaps\ApiMapBundle\ApiMapService
and write in config: ApiMaps\ApiMapBundle\ApiMapService\ApiMapService.
Truly believe it'll help you...
I know that this question was asked so many times, but none of answers helped me.
I'm getting exception in Laravel 5
BindingResolutionException in Container.php line 785:
Target [App\Contracts\CustomModelInterface] is not instantiable.
What I've done without success:
Register App\Providers\AppRepositoryProvider in app.php providers
php artisan clear-compiled
Everything works if I replace interfaces on repositories in MyService, but I feel that it's wrong (should it be handled by IoC container?).
Structure:
app
- Contracts
- CustomModelInterface.php
- Models
- CustomModel.php
- Repositories
- CustomModelRepository.php
- Providers
- AppRepositoryProvider.php
- Services
- MyService.php
App\Contracts\CustomModelInterface.php
<?php namespace App\Contracts;
interface CustomModelInterface {
public function get();
}
App\Repositories\CustomModelRepository.php
<?php namespace App\Repositories;
use App\Contracts\CustomModelInterface;
use App\Models\CustomModel;
class CustomModelRepository implements CustomModelInterface {
private $Model;
public function __construct(CustomModel $model) {
$this->Model = $model;
}
public function get() {
return 'result';
}
}
App\Services\MyService.php (Keep business logic / layer between controller and repositories)
<?php namespace App\Services;
use App\Contracts\CustomModelInterface;
class MyService {
private $Model;
public function __construct(CustomModelInterface $customModel) {
$this->Model= $customModel;
}
public function getAll() {
return $this->Model->get();
}
}
App\Providers\AppRepositoryProvider.php
<?php namespace App\Providers;
use Illuminate\Support\ServiceProvider;
class AppRepositoryProvider extends ServiceProvider {
public function boot() {}
public function register() {
$models = array(
'CustomModel'
);
foreach ($models as $idx => $model) {
$this->app->bind("App\Contracts\{$model}Interface", "App\Repositories\{$model}Repository");
}
}
}
My controller looks like:
<?php namespace App\Http\Controllers;
use App\Services\MyService;
class SuperController extends Controller {
private $My;
public function __construct(MyService $myService) {
$this->My = $myService;
}
public function getDetails() {
return $this->My->getAll();
}
}
composer.json
"autoload": {
"classmap": [
"database"
],
"psr-4": {
"App\\": "app/",
"App\\Models\\": "app/Models/",
"App\\Contracts\\": "app/Contracts/",
"App\\Repositories\\": "app/Repositories/"
}
},
Thank you everyone, but problem was in my AppRepositoryProvider. As it's binding exception, then obviously the problem was with binding :)
Correct file is:
<?php namespace App\Providers;
use Illuminate\Support\ServiceProvider;
class AppRepositoryProvider extends ServiceProvider {
public function boot() {}
public function register() {
$models = array(
'CustomModel',
'CustomModel2',
'CustomModel3'
);
foreach ($models as $model) {
$this->app->bind("App\Contracts\\{$model}Interface", "App\Repositories\\{$model}Repository");
}
}
}
Note, that I'm using "App\Contracts\\{$model}Interface" (not escaping "{" symbol) and it generate correct string App\Contracts\CustomModelInterface instead of App\Contracts\{$model}Interface (with unexpected escaping).
Every time I create a new repository/contract pair I make sure I do the following:
check the classes used in the service provider (copy/paste the namespaces)
register a new binding in config/app.php
php artisan optimize
Many hours of useless debugging led me to this short checklist.
For me, I forgot to bind in app->providers->RepositoryServiceProvider
the repository like this in the register method
public function register()
{
$this->app->bind(
\App\Play\Contracts\PatientRepository::class,
\App\Play\Modules\PatientModule::class
);
}
Make sure your RepositoryServiceProvider is registered in AppServiceProvider.
public function register()
{
$this->app->register(RepositoryServiceProvider::class);
}
I got past this error running:
php artisan config:clear
php artisan clear-compiled
php artisan optimize
php artisan config:cache
Related to:
Target is not instantiable. Laravel 5 - App binding service provider
The problem is solved by adding your repository in app/providers/AppServiceProvider
like the example below.
public function register()
{
$this->app->singleton(UserRepository::class, EloquentUser::class);
}
Dont forget the name space
use Test\Repositories\EloquentUser;
use Test\Repositories\UserRepository;
It worked for me
On App\Services\MyService.php you are passing that interface with dependency injection which tries to instantiate that -
public function __construct(CustomModelInterface $customModel) {
$this->Model= $customModel;
}
which is wrong.
Try implement that in that class - class MyService implements CustomModelInterface { and use the function of that interface like -
$this->get();
Or you are using it - class CustomModelRepository implements CustomModelInterface {
So if you do -
public function __construct(CustomModelRepository $customModel) {
$this->Model= $customModel;
}
then also you can access the interface methods.
I've just experienced an issue similar to this and the cause of my error was that I had set $defer to true in the service provider class but I had not implemented the required provides() method.
If you have deferred the creation of your class until it is need rather than it being loaded eagerly, then you need to also implement the provides method which should simply return an array of the classes that the provider provides. In the case of an interface, I believe it should be the name of the interface rather than the concrete class.
E.g.
public method provides(): array
{
return [
MyInterface::class,
];
}
Current documentation: https://laravel.com/docs/5.5/providers#deferred-providers
I hope this helps somebody else.
Don't worry guys. I have a solution to your problem.
I have an example for you.
Step1: php artisan make:repository Repository/Post //By adding this command you can create a repository and eloquent files
Step2: After adding that file you have to add/use this repository in the controller in which you want to use.
for eg: use App\Repositories\Contracts\PostRepository;
Step3: After adding that repo in your controller if you will run the app you will get an error like " Interface is not instantiable". It comes because you have created a repo and used in a controller, but laravel don't know where this repository is register and bind with which eloquent. So that it throws an error.
Step4: To solve this error you have to bind your repo with your eloquent in AppServiceProvider.
E.g:
AppServiceProvider.php file
<?php
namespace App\Providers;
// **Make sure that your repo file path and eloquent path must be correct.**
use App\Repositories\Contracts\PostRepository; // **Use your repository here**
use App\Repositories\Eloquent\EloquentPostRepository; **// Use your eloquent here**
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider {
/**
* Register any application services.
*
* #return void
*/
public function register() {
**// And bind your repository and eloquent here. **
$this->app->bind(PostRepository::class, EloquentPostRepository::class);
}
}
Step5: After binding repo and eloquent you can use all method of repo in your controller. Enjoy.....
Please let me know if you have any query.
execute this command :
composer dump-autoload
this command will remap your laravel autoload classes together with all other vendor's i had same issue before and this did the trick you can use it together with "-o" param for optimization .
Note that this can also be caused by the _constructor on the class being declared private, or otherwise being blocked...
If it cant call the constructor, the binding will fail
I think the problem here is that you don't bind App\Contracts\CustomModelInterface to anything so Laravel tries to create instance of interface.
In App\Providers\AppRepositoryProvider.php you have only:
$models = array(
'Model'
);
but you should have in this array CustomModel also, so it should look like this:
$models = array(
'Model',
'CustomModel',
);
The last thing you do is to use the interface you bound to the repository.
Set it up and try running your laravel app to make sure you get no errors.
In my case I had a mismatch between my repository and interface.
interface UserRepositoryInterface{
public function get($userId);
}
class UserRepository implements UserRepositoryInterface{
public function get(int $userId);
}
As you can see the interface get method does not include a type hint but the UserRepository class' get method has a type hint.
You won't get this error if you immediately start to use your Interface Binding.
register a new binding in config/app.php
In my case I forgot use App\Repositories\UserRepository in App\Providers\AppRepositoryProvider.php
intelephense wasn't complaining and the error-message did not give me any clue, but somehow I found out that it's missing and adding this line did the trick
I had this error, and found out that I should restart the queue because it runs in the job:
php artisan queue:restart
In Symfony2 I get an error:
The autoloader expected class "Website\PublicBundle\Facebook"
to be defined in file
"C:\PHP-XAMPP\htdocs\myProject/src\Website\PublicBundle\Facebook.php".
The file was found but the class was not in it, the class name or
namespace probably has a typo.
500 Internal Server Error - RuntimeException
I cleared cache, restarted Apache and I tried several solutions from similar questions like this, but nothing works.
app/config/config.yml:
services:
facebook:
class: Website\PublicBundle\Facebook
src/Website/PublicBundle/Facebook.php:
namespace Website\PublicBundle\Facebook;
class Facebook {
public function __construct() {
//...
}
}
Your namespace should be
namespace Website\PublicBundle;
Otherwise your class is actually..
Website\PublicBundle\Facebook\Facebook