Error:
BindingResolutionException in Container.php line 887:
Target [App\Helpers\Contracts\AccessTokenInterface] is not instantiable.
Route:
Route::get('/', 'LoginController#handleProviderCallback');
Controller:
namespace App\Http\Controllers;
use App\Helpers\Contracts\AccessTokenInterface;
class LoginController extends Controller
{
public function handleProviderCallback(AccessTokenInterface $accessTokenInstance)
{
return $accessTokenInstance->getSomething();
}
}
Provider:
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use App\Helpers\Contracts\AccessTokenInterface;
use AccessToken;
class TokenServiceProvider extends ServiceProvider
{
protected $defer = true;
public function boot()
{
//
}
public function register()
{
$this->app->bind(AccessTokenInterface::class, function(){
return new AccessToken();
});
}
}
Helper:
namespace App\Helpers;
use App\Helpers\Contracts\AccessTokenInterface;
class AccessToken implements AccessTokenInterface
{
protected $something;
public function setSomething()
{
$something = 100;
}
public function __construct()
{
$this->setSomething();
}
public function getSomething(){
return $something;
}
Interface:
namespace App\Helpers\Contracts;
Interface AccessTokenInterface
{
public function getSomething();
public function setSomething();
}
I have registered Provider in providers and AccessToken in aliases for Helper.
I have read some stackoverflow answers but can't find solution. I am new to this.
Where I am going wrong?
Write in your config/app.php
'providers' => [
...
App\Providers\TokenServiceProvider::class,
...
]
Hope it help you :)
Related
I have this code
Controller
<?php
namespace App\Exchange\Helpers;
use App\Contracts\Exchange\Notification;
class Locker
{
protected $notification;
public function __construct(Notification $notification)
{
$this->notification = $notification;
}
public function index()
{
return $this->notification->sendMessage('test');
}
Interface
<?php
namespace App\Contracts\Exchange;
interface Notification
{
public function sendMessage($message);
}
File Kernel.php
namespace App\Providers;
use App\Contracts\Exchange\Notification;
use App\Exchange\Helpers\Notification\Telegram;
use Illuminate\Http\Request;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
/**
* Register any application services.
*
* #return void
*/
public function register()
{
$this->app->bind(Notification::class, function (){
return new Telegram(env('TELEGRAM_EXCHANGE_TOKEN'), env('TELEGRAM_EXCHANGE_CHAT_ID'));
});
}
If I try to use new Locker(); I get a TypeError error: Too few arguments to function App\Exchange\Helpers\Locker::__construct(), 0 passed in Psy Shell code on line 1 and exactly 1 expected
Your controller should extend Illuminate\Routing\Controller in order for dependency injection to work. Or just refactor your __construct method using app helper:
<?php
namespace App\Exchange\Helpers;
use App\Contracts\Exchange\Notification;
class Locker
{
protected $notification;
public function __construct()
{
$this->notification = app(Notification::class);
}
public function index()
{
return $this->notification->sendMessage('test');
}
}
In my Laravel9 project, I have many controllers that have similar functions like:
TestController.php
namespace App\Http\Controllers\Api;
use App\Contracts\TestInterface;
use App\Http\Controllers\Controller;
class TestController extends Controller
{
public function __construct(
private TestInterface $testService,
private $moduleName = 'Test Name',
) {}
public function index()
{
$tests = $this->testService->index();
$response = response([
'message' => __('Read' . $this->moduleName . 'successfully'),
'data' => $tests,
], 200);
return $response;
}
}
Test1Controller.php
namespace App\Http\Controllers\Api;
use App\Contracts\Test1Interface;
use App\Http\Controllers\Controller;
class Test1Controller extends ApiController
{
public function __construct(
private Test1Interface $test1Service,
private $moduleName = 'Test Name 1',
) {}
public function index()
{
$test1s = $this->test1Service->index();
$response = response([
'message' => __('Read' . $this->moduleName . 'successfully'),
'data' => $test1s,
], 200);
return $response;
}
}
So I modified them into:
TestController.php
namespace App\Http\Controllers\Api;
use App\Contracts\TestInterface;
use App\Http\Controllers\Api\ApiController;
class TestController extends ApiController
{
protected function service()
{
return TestInterface::class;
}
}
Test1Controller.php
namespace App\Http\Controllers\Api;
use App\Contracts\Test1Interface;
use App\Http\Controllers\Api\ApiController;
class Test1Controller extends ApiController
{
protected function service()
{
return Test1Interface::class;
}
}
ApiController.php
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
abstract class ApiController extends Controller
{
private $serviceClass;
public function __construct()
{
$this->serviceClass = $this->service();
}
abstract protected function service();
public function index()
{
return $this->serviceClass::index();
}
}
TestInterface.php
namespace App\Contracts;
interface TestInterface extends BaseInterface
{
}
BaseInterface.php
namespace App\Contracts;
interface BaseInterface
{
public function index();
}
Then I bind interfaces into services in AppServiceProvider.php, like:
$this->app->bind('App\Contracts\TestInterface', 'App\Services\TestService');
$this->app->bind('App\Contracts\Test1Interface', 'App\Services\Test1Service');
TestService.php:
namespace App\Services;
use App\Contracts\TestInterface;
use App\Repositories\TestRepository;
class TestService implements TestInterface
{
public function __construct(
private TestRepository $testRepo,
) {}
public function index()
{
return $this->testRepo->index();
}
}
Test1Service.php
namespace App\Services;
use App\Contracts\Test1Interface;
use App\Repositories\Test1Repository;
class Test1Service implements Test1Interface
{
public function __construct(
private Test1Repository $test1Repo,
) {}
public function index()
{
return $this->test1Repo->index();
}
}
When I call TestController::index on my route, I get:
Cannot call abstract method App\Contracts\TestInterface::index()
How can I fix it or do any better suggestions? Thanks.
I just solved the problem by modifying the following line in ApiController.php:
private $serviceClass;
public function __construct(
private Container $app,
)
{
$this->serviceClass = $app->make($this->service());
}
I'm new to Lumen, and have a fresh install (v8.2.4) and have followed the docs, trying to write my own service, but I keep getting error
"Target class [App\Prodivers\BatmanServiceProvider] does not exist."
Like I said, its a fresh install according to the Lumen docs.
in /bootstrap/app.php
$app->register(App\Providers\BatmanServiceProvider::class);
in /app/Providers/BatmanServiceProvider.php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
class BatmanServiceProvider extends ServiceProvider
{
public function register()
{
return "batman!";
}
}
My controller: app/Http/Controllers/MainController.php
<?php
namespace App\Http\Controllers;
use App\Prodivers\BatmanServiceProvider;
class MainController extends Controller{
public function __construct(BatmanServiceProvider $BatmanServiceProvider){
}
public function main(){
print "hello space!";
}
}
What am I missing/doing wrong?
in /bootstrap/app.php
$app->register(App\Providers\BatmanServiceProvider::class);
in /app/Providers/BatmanServiceProvider.php
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use App\Services\BatmanService;
class BatmanServiceProvider extends ServiceProvider
{
/**
* Register any application services.
*
* #return void
*/
public function register()
{
$this->app->bind(BatmanService::class, function(){
return new BatmanService;
});
}
}
create Services folder in your_lumen_project/app, and create php file BatmanService.php
in /app/Services/BatmanService.php
<?php
namespace App\Services;
class BatmanService
{
public function sayHello(){
return 'hi, space!';
}
}
Now, you can use anywhere!
<?php
namespace App\Http\Controllers;
use App\Services\BatmanService;
class MainController extends Controller{
protected $batmanService;
public function __construct(BatmanService $batmanService){
$this->batmanService = $batmanService;
}
public function main(){
return $this->batmanService->sayHello(); // "hi, space!"
}
}
Error:
BindingResolutionException in Container.php line 887:
Target [App\Helpers\Contracts\AccessTokenInterface] is not instantiable.
Route:
Route::get('/', 'LoginController#handleProviderCallback');
Controller:
namespace App\Http\Controllers;
use App\Helpers\Contracts\AccessTokenInterface;
class LoginController extends Controller
{
public function handleProviderCallback(AccessTokenInterface $accessTokenInstance)
{
return $accessTokenInstance->getSomething();
}
}
Provider:
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use App\Helpers\Contracts\AccessTokenInterface;
use AccessToken;
class TokenServiceProvider extends ServiceProvider
{
protected $defer = true;
public function boot()
{
//
}
public function register()
{
$this->app->bind('AccessTokenInterface::class', function(){
return new AccessToken();
});
}
}
Helper:
namespace App\Helpers;
use App\Helpers\Contracts\AccessTokenInterface;
class AccessToken implements AccessTokenInterface
{
protected $something;
public function setSomething()
{
$something = 100;
}
public function __construct()
{
$this->setSomething();
}
public function getSomething(){
return $something;
}
Interface:
namespace App\Helpers\Contracts;
Interface AccessTokenInterface
{
public function getSomething();
public function setSomething();
}
I have registered Provider in providers and AccessToken in aliases for Helper.
I have read some stackoverflow answers but can't find solution. I am new to this.
Where I am going wrong?
Remove the quotes from the bind method in your provider:
$this->app->bind(AccessTokenInterface::class, function(){
return new AccessToken();
});
<?php
abstract class BaseController extends Controller {
public function setContainer(ContainerInterface $container) {
parent::setContainer($container);
$this->containerInitialized();
}
protected function containerInitialized() {
if($this->getUser()->getNickName()===null){
// I need to directly returns a Response
return new Response('...');
}
}
}
class UserHomeController extends BaseController{
public function indexAction(){
}
}
I need to directly returns a Response on 'containerInitialized' function, not need to call Action's function!
My current practices is throw 'SetResponseException', and listen 'onKernelException' event, when Exception is instance of 'SetResponseException', just replace Response content! But I think a little farfetched!
What you really want is use an event listener.
<?php
namespace AppBundle\EventListener;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\HttpKernel\Event\FilterControllerEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
use Symfony\Component\HttpFoundation\Response;
use AppBundle\Controller\BaseController;
class BaseControllerListener implements EventSubscriberInterface
{
private $tokenStorage;
public function __construct(TokenStorageInterface $token_storage)
{
$this->tokenStorage = $tokenStorage;
}
public function onKernelController(FilterControllerEvent $event)
{
if (!$this->isBaseController($event->getController())) {
return;
}
if ($this->tokenStorage->getToken()->getUser()->getNickName() === null) {
$event->setResponse(new Response('...'));
}
}
protected function isBaseController($controller)
{
if (!is_array($controller)) {
return;
}
return $controller[0] instanceof BaseController;
}
public static function getSubscribedEvents()
{
return array(
KernelEvents::CONTROLLER => 'onKernelController',
);
}
}
then add this to you configuration
services:
app.base_controller_subscriber:
class: AppBundle\EventListener\BaseControllerListener
arguments:
- "#security.token_storage"
tags:
- { name: kernel.event_subscriber }
now you can just do this:
namespace AppBundle\Controller;
// ...
abstract class BaseController extends Controller
{
// other stuff
}
namespace AppBundle\Controller;
// ...
class UserHomeController extends BaseController
{
public function indexAction()
{
}
}
for each controller that will extends BaseController, the BaseControllerListener::onKernelController method will be executed.