I'm quite new in Laravel 5, what I am trying to do is a simple repository with dependency injection. But I'm stuck with this error:
Argument 1 passed to
App\Http\Controllers\Api\UserController::__construct() must implement
interface App\Repositories\UserInterface, instance of
App\Repositories\UserRepository given
Here is my code:
UserController:
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Response;
use App;
use Auth;
use Crypt;
use Lang;
use Image;
use Storage;
use Config;
use Validator;
use App\User;
use App\Repositories\UserInterface;
class UserController extends Controller
{
protected $config;
protected $users;
public function __construct(UserInterface $users)
{
$this->middleware('api');
$this->middleware('auth', ['except' => 'getInfo']);
$this->users = $users;
$this->config = Config::get('images.avatar');
}
UserInterface:
namespace App\Repositories;
use App\Repositories\BaseInterface;
interface UserInterface extends BaseInterface
{
};
BaseInterface:
namespace App\Repositories;
interface BaseInterface
{
public function all();
public function paginate($count);
public function find($id);
}
BaseRepository
namespace App\Repositories;
use App\Repositories\BaseInterface;
class BaseRepository implements BaseInterface
{
protected $model;
public function __call($name, $args)
{
// $this->getNewInstance()->{$name($args)};
return call_user_func_array([
$this->getNewInstance(),
$method], $args);
}
public function all($relations = [])
{
$instance = $this->getNewInstance();
return $instance->with($relations)->all();
}
public function find($id, $relations = [])
{
$instance = $this->getNewInstance();
return $instance->with($relations)->find($id);
}
public function findOrFail($id, $relations = [])
{
$instance = $this->getNewInstance();
return $instance->with($relations)->findOrFail($id);
}
public function paginate($count)
{
}
protected function getNewInstance()
{
return new $this->model;
}
}
UserRepository
namespace App\Repositories;
use App\Repositories\BaseRepository;
Class UserRepository extends BaseRepository
{
protected $model = 'App\User';
}
RepositoryServiceProvider
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use App;
class RepositoryServiceProvider extends ServiceProvider
{
/**
* Register any error handlers.
*
* #return void
*/
public function boot()
{
}
/**
* Register the service provider.
*
* #return void
*/
public function register()
{
//
App::bind('App\Repositories\UserInterface', 'App\Repositories\UserRepository');
}
}
Of course RepositoryServiceProvider is added under service providers in my config/app.php
Please help, I'm almost sure that I've tried everything whatever I found in Google.
Your UserRepository has to implement UserInterface:
namespace App\Repositories;
use App\Repositories\BaseRepository;
class UserRepository extends BaseRepository implements UserInterface
// ^^^^^^^^^^^^^^^^^^^^^^^^
{
protected $model = 'App\User';
}
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());
}
Laravel CQRS
I am applying CQRS in Laravel just to learn how to use it.
I created a simple user registration and a controller that creates a command to dispatch the handle and use the right use case.
When Trying to use the interface in the controller, it looks like that I need to bind the interface and the implementation because it doesn't know which one to use but in this case I don't really understand how to bind the interface.
CreateUserController.php
<?php
declare(strict_types=1);
namespace App\Http\Controllers\User;
use App\Http\Controllers\Controller;
use App\Http\Requests\Users\CreateUserRequest;
use Illuminate\Http\RedirectResponse;
class CreateUserController extends Controller
{
public function __construct(private \Src\User\Infrastructure\CreateUserController $userController)
{
}
public function __invoke(CreateUserRequest $request): RedirectResponse
{
$this->userController->__invoke($request);
return redirect()->route('verify');
}
}
Src\User\Infrastructure\CreateUserController
<?php
declare(strict_types=1);
namespace Src\User\Infrastructure;
use App\Http\Requests\Users\CreateUserRequest;
use Src\Shared\Domain\Bus\Command\CommandBus;
use Src\User\Application\Create\CreateUserCommand;
final class CreateUserController
{
public function __construct(private CommandBus $commandBus)
{
}
public function __invoke(CreateUserRequest $request)
{
$name = $request->name;
$email = $request->email;
$password = $request->password;
$command = new CreateUserCommand($name, $email, $password);
$this->commandBus->dispatch($command);
}
}
CommandBus
<?php
declare(strict_types=1);
namespace Src\Shared\Domain\Bus\Command;
interface CommandBus
{
public function dispatch(Command $command): void;
}
Command
<?php
declare(strict_types=1);
namespace Src\Shared\Domain\Bus\Command;
interface Command
{
}
CreateUserCommandHandler
<?php
declare(strict_types=1);
namespace Src\User\Application\Create;
use Src\User\Domain\ValueObjects\UserEmail;
use Src\User\Domain\ValueObjects\UserName;
use Src\User\Domain\ValueObjects\UserPassword;
final class CreateUserCommandHandler
{
public function __construct(
private UserCreator $creator
)
{
}
public function __invoke(CreateUserCommand $command)
{
$name = new UserName($command->name());
$email = new UserEmail($command->email());
$password = new UserPassword($command->password());
$this->creator->__invoke($name, $email, $password);
}
}
The Error
I tried this:
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use Src\Shared\Domain\Bus\Command\Command;
use Src\User\Application\Create\CreateUserCommand;
class AppServiceProvider extends ServiceProvider
{
/**
* Register any application services.
*
* #return void
*/
public function register()
{
$this->app->bind(
Command::class,
CreateUserCommand::class
);
}
/**
* Bootstrap any application services.
*
* #return void
*/
public function boot()
{
//
}
}
Here is how you can bind with the interface.
Create a class in app/Providers folder. You can give any name to this class. Eg. InterfaceServiceProvider. extends it with Illuminate\Support\ServiceProvider
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
class InterfaceServiceProvider extends ServiceProvider
{
/**
* Register services.
*
* #return void
*/
public function register()
{
$this->app->bind(YourInterFace::class, YourController::class);
}
/**
* Bootstrap services.
*
* #return void
*/
public function boot()
{
//
}
}
Add this InterfaceServiceProvider in config/app.php in providers array
Eg.
'providers' => [
App\Providers\InterfaceServiceProvider::class,
]
I want to make some operations before controller load and I have problem with include interfaces or classes into function.
My question is how should I do it to start working?
There is a code:
~/src/Controller/ControllerListener.php
<?php
namespace App\EventListener;
use App\Controller\DailyWinController;
use Psr\Log\LoggerInterface;
use Symfony\Component\HttpKernel\Event\FilterControllerEvent;
class ControllerListener implements DailyWinController
{
public function onKernelController(FilterControllerEvent $event, LoggerInterface $logger) {
$logger->alert('Working');
}
}
~/src/Controller/DailyWinController.php
<?php
namespace App\Controller;
interface DailyWinController {
// maybe there something?
}
~/src/Controller/UserController.php
<?php
namespace App\Controller;
use App\Entity\User;
use App\Entity\DailyWin;
use Psr\Log\LoggerInterface;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
class UserController extends Controller implements DailyWinController
{
/**
* #Route("/user", name="user")
* #param AuthorizationCheckerInterface $authChecker
* #param UserInterface $user
* #return \Symfony\Component\HttpFoundation\RedirectResponse|\Symfony\Component\HttpFoundation\Response
*/
public function user(AuthorizationCheckerInterface $authChecker, UserInterface $user = null, LoggerInterface $logger) {
if ($authChecker->isGranted('ROLE_USER') === false) {
return $this->redirectToRoute('logowanie');
}
$logger->warning('Logger is working');
$em = $this->getDoctrine()->getManager();
$DWrep = $em->getRepository(DailyWin::class);
$userId = $user->getId();
$dailyWin = $DWrep->findOneBy(['userId' => $userId]);
return $this->render('andprize/user/index.html.twig', array(
'dailyWin' => $dailyWin,
'userId' => $userId
));
}
}
I have the following problem:
FatalThrowableError Type error: Argument 2 passed to
App\EventListener\ControllerListener::onKernelController() must
implement interface Psr\Log\LoggerInterface, string given
You have to inject the logger to the listener.
<?php
namespace App\EventListener;
use App\Controller\DailyWinController;
use Psr\Log\LoggerInterface;
use Symfony\Component\HttpKernel\Event\FilterControllerEvent;
class ControllerListener implements DailyWinController
{
protected $logger;
public function __construct(LoggerInterface $logger)
{
$this->logger=$logger;
}
public function onKernelController(FilterControllerEvent $event) {
$this->logger->alert('Working');
}
}
I'm trying to find out why I'm receiving this error. I'm following along. However the only difference is that at the time of the recording it was done with Laravel 4.25 and I am now using Laravel 5.0.
Repositories and Inheritance
BindingResolutionException in Container.php line 785:
Target [App\Repositories\User\UserRepository] is not instantiable.
<?php
namespace App\Http\Controllers;
use App\Http\Requests;
use App\Http\Controllers\Controller;
use App\Repositories\User\UserRepository;
use Illuminate\Http\Request;
class UsersController extends Controller {
private $userRepository;
public function __construct(UserRepository $userRepository) {
$this->userRepository = $userRepository;
}
/**
* Display a listing of the resource.
*
* #return Response
*/
public function index() {
$users = $this->userRepository->getAll();
return $users;
}
}
<?php
namespace App\Repositories\User;
use App\Repositories\EloquentRepository;
class EloquentUserRepository extends EloquentRepository implements UserRepository
{
private $model;
function __construct(User $model) {
$this->model = $model;
}
}
<?php
namespace App\Repositories\User;
interface UserRepository {
public function getAll();
}
<?php
namespace App\Repositories;
abstract class EloquentRepository {
public function getAll() {
return $this->model->all();
}
public function getById() {
return $this->model->findOrFail($id);
}
}
You are type hinting an interface, and not the class itself. This error is occurring because Laravel cannot bind an interface because the binding must be instantiable. Abstract classes or interfaces are not valid unless Laravel knows the concrete (instantiable) class to substitute in for the abstract class / interface.
You will need to bind the EloquentUserRepository to the interface:
App::bind('UserRepository', 'EloquentUserRepository');