Constructor injection does not work with Laravel - php

I got the error below when I tried to use constructor injection in LoginController.php
Illuminate\Contracts\Container\BindingResolutionException
Target class [Domain\User\UserService] does not exist.
Any idea why?
Following are details.
LoginController.php
class LoginController extends Controller
{
use AuthenticatesUsers;
private $userService;
/**
* Where to redirect users after login.
*
* #var string
*/
protected $redirectTo = RouteServiceProvider::HOME;
public function __construct(UserService $userService)
{
$this->userService = $userService;
$this->middleware('guest')->except('logout');
}
UserService.php
namespace Domain\User;
class UserService
{
private $userRepository;
public function __construct(IUserRepository $userRepository)
{
$this->userRepository = $userRepository;
}
}
UserRepository.php
class UserRepository implements IUserRepository
{
private $user;
public function __construct(User $user)
{
$this->user = $user;
}
UserRepositoryServiceProvider.php
public function register()
{
$this->app->bind(
IUserRepository::class,
function ($app) {
return new UserRepository($app->make(User::class));
}
);
}
UserServiceProvider.php
public function register()
{
$this->app->bind(
'UserService',
UserService::class
);
}

Related

Laravel UnitTest not working when pass constructor has Interface

I'm new to UnitTest and trying to integrate it into my Laravel application, but I'm getting the below error:
Call to a member function findOne() on null
at app/Services/User/UserService.php:32
28▕ $this->userWebsiteRepository = $userWebsiteRepository;
29▕ }
30▕
31▕ public function findOne($data = []){
➜ 32▕ return $this->userRepository->findOne($data);
33▕ }
34▕
This is my code.
AuthController.php
class AuthController extends Controller {
private $userService;
public function __construct(UserService $userService)
{
$this->userService = $userService;
}
public function show($id){
return $this->userService->findOne(['id' => $id]);
}
}
UserService.php
class UserService
{
public $userRepository;
public function __construct(UserRepositoryInterface $userRepository)
{
$this->userRepository = $userRepository;
}
}
UserRepositoryInterface.php
interface UserRepositoryInterface
{
public function findOne($data);
}
UserRepository.php
use App\Models\User;
class UserRepository implements UserRepositoryInterface
{
private $model;
public function __construct(User $user)
{
$this->model = $user;
}
public function findOne($data)
{
if (empty($data)) return false;
$query = $this->model->with(['userWebsites', 'userWebsites.website', 'role']);
if(!empty($data['id'])) $query = $query->where('id', $data['id']);
return $query->first();
}
}
RepositoryServiceProvider.php
class RepositoryServiceProvider extends ServiceProvider
{
/**
* Register services.
*
* #return void
*/
public function register()
{
$this->app->bind(UserRepositoryInterface::class, UserRepository::class);
}
}
AuthControllerTest.php
class AuthControllerTest extends TestCase
{
public $authController;
public $userRepositoryInterfaceMockery;
public $userServiceMokery;
public function setUp(): void{
$this->afterApplicationCreated(function (){
$this->userRepositoryInterfaceMockery = Mockery::mock(UserRepositoryInterface::class)->makePartial();
$this->userServiceMokery = Mockery::mock((new UserService(
$this->app->instance(UserRepositoryInterface::class, $this->userRepositoryInterfaceMockery)
))::class)->makePartial();
$this->authController = new AuthController(
$this->app->instance(UserService::class, $this->userServiceMokery)
);
}
}
public function test_abc_function(){
$res = $this->authController->abc(1);
}
}
I was still able to instantiate the AuthController and it ran to the UserService. but it can't get the UserRepositoryInterface argument. I think the problem is that I passed the Interface in the constructor of the UserService. .What happened, please help me, thanks
I don't know where $userService comes from to your controller's constructor, but it seems like it comes from nowhere. You need to pass it as argument, so Laravel can resolve its instance in service container.
class AuthController extends Controller {
private $userService;
public function __construct(
private AuthService $authService,
UserRepositoryInterface $userRepository
) {
$this->userService = new UserService($userRepository);
}
public function show($id)
{
return $this->userService->findOne(['id' => $id]);
}
}
Also there is literally no findOne method in UserService. You need one there.
class UserService
{
public function __construct(private UserRepositoryInterface $userRepository)
{
}
public function findOne(array $data)
{
return $this->userRepository->findOne($data);
}
}
Update
In that case you need this in service provider:
$this->app->bind(UserRepositoryInterface::class, UserRepository::class);
$this->app->bind(UserService::class, function ($app) {
return new UserService($app->make(UserRepositoryInterface::class));
});

Call UserPasswordEncoderInterface encodePassword in DoctrineMigrations

I am trying to encode a password with the encodePassword function from Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface; inside my migration here is my code
I tried with implements UserPasswordEncoderInterface but i did not manage to use this method encodePassword
The error is
Call to a member function encodePassword() on null
<?php
declare(strict_types=1);
namespace DoctrineMigrations;
use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
use Ramsey\Uuid\Uuid;
use App\Entity\User;
/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20201112164728 extends AbstractMigration
{
/**
* #var UserPasswordEncoderInterface
*/
private $encoder;
public function getPassword($password)
{
$user = new User();
return $this->encoder->encodePassword($user,$password);
}
public function getDescription(): string
{
return '';
}
public function up(Schema $schema): void
{
}
public function postUp(Schema $schema): void
{
$this->connection->insert('users', [
'id' => Uuid::uuid4(),
'email' => 'xxx#xxx.com',
'password' => $this->getPassword('foo'),
]);
}
public function down(Schema $schema): void
{
}
}

Injecting problem - missing parent constructor call

I am trying to inject my BaseService within antoher service where I need to call my repository that I wrote in BaseService.
I think it's pretty simple thing but it marks __construct part with :
Missing parent constructor call
I made that logic in BaseService and it works
class BaseService
{
/** #var ContainerInterface */
public $container;
public $em;
public function __construct(ContainerInterface $container, EntityManagerInterface $em)
{
$this->container = $container;
$this->em = $em;
}
/**
* #return \Doctrine\Common\Persistence\ObjectRepository|\Doctrine\ORM\EntityRepository
*/
public function getMyDataRepository()
{
return $this->em->getRepository(MyData::class);
}
}
and my other service:
class DataService extends AbstractAdmin
{
public function __construct(BaseService $baseService)
{
$this->baseService = $baseService;
}
public function getTransactions(Card $card)
{
return $this->getMyDataRepository()
->createQueryBuilder('c')
->getQuery();
}
}
I found an answer.
I did it like this:
public $baseService;
public function __construct($code, $class, $baseControllerName, BaseService $baseService)
{
parent::__construct($code, $class, $baseControllerName);
$this->baseService = $baseService;
}
As Abstract Admin has its constructor.
You forgot to add parent constructor of AbstractAdmin on DataService.
class DataService extends AbstractAdmin
{
public function __construct(BaseService $baseService)
{
parent::__construct(AbstractAdmin dependencies goes here);
$this->baseService = $baseService;
}
public function getTransactions(Card $card)
{
return $this->getMyDataRepository()
->createQueryBuilder('c')
->getQuery();
}
I dont know which dependencies need your AbstractAdmin

Symfony 3.3 The autoloader expected class

I've got a problem with my Symfony project. I'm trying to put a form login authenticator and for that I need to create a repository of my user class. However, i've got that error :
The autoloader expected class "AppBundle\Repository\UserRepository" to be defined in file "C:\wamp64\www\Symfony\vendor\composer/../../src\AppBundle\Repository\UserRepository.php". The file was found but the class was not in it, the class name or namespace probably has a typo.
Here's my UserRepository class :
<?php
namespace AppBundle\Repository;
use Doctrine\Bundle\DoctrineBundle\Repository\EntityRepository;
use AppBundle\Entity\User;
class UserRepository extends EntityRepository
{
public function findAllOrderedByName()
{
return $this->getEntityManager()
->createQuery(
'SELECT u FROM AppBundle:User u ORDER BY u.username ASC'
)
->getResult();
}
}
?>
My User entity :
<?php
namespace AppBundle\Entity;
use Symfony\Component\Security\Core\User\UserInterface;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity(repositoryClass="AppBundle\Repository\UserRepository")
* #ORM\Table(name="user")
*/
class User implements UserInterface
{
/**
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\Column(type="string", unique=true)
*/
private $username;
/**
* #ORM\Column(type="string", unique=true)
*/
private $apiKey;
/**
* #ORM\Column(type="string", length=64)
*/
private $password;
public function getId()
{
return $this->id;
}
public function getUsername()
{
return $this->username;
}
public function getPassword()
{
return $this->password;
}
public function getApiKey()
{
return $this->apiKey;
}
public function getRoles()
{
return array('ROLE_USER');
}
public function getSalt()
{
}
public function eraseCredentials()
{
}
public function setUsername($_username)
{
$this->username = $_username;
}
public function setPassword($_password)
{
$this->password = $_password;
}
public function setId($_id)
{
return $this->id = $_id;
}
public function setApiKey($_apiKey)
{
return $this->apiKey = $_apiKey;
}
}
?>
My security.yml :
security:
encoders:
AppBundle\Entity\User:
algorithm: bcrypt
providers:
our_db_provider:
entity:
class: AppBundle:User
property: username
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
main:
guard:
authenticators:
- AppBundle\Security\LoginFormAuthenticator
And finally my FormLoginAuthenticator :
<?php
namespace AppBundle\Security;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\User\UserProviderInterface;
use Symfony\Component\Security\Guard\Authenticator\AbstractFormLoginAuthenticator;
use AppBundle\Repository\UserRepository;
class LoginFormAuthenticator extends AbstractFormLoginAuthenticator
{
private $userRepository;
public function __construct(UserRepository $userRepository)
{
$this->userRepository = $userRepository;
}
public function supports(Request $request)
{
return $request->attributes->get('_route') === 'app_login'
&& $request->isMethod('POST');
}
public function getCredentials(Request $request)
{
return [
'username' => $request->request->get('username'),
'password' => $request->request->get('password'),
];
}
public function getUser($credentials, UserProviderInterface $userProvider)
{
return $this->userRepository->findOneBy(['username' => $credentials['username']]);
}
public function checkCredentials($credentials, UserInterface $user)
{
die($user);
}
public function onAuthenticationSuccess(Request $request, TokenInterface $token, $providerKey)
{
// todo
}
protected function getLoginUrl()
{
// TODO: Implement getLoginUrl() method.
}
}
?>
Thanks you by advance for helping me. Also, if you have a better solution to build my form authenticator, it will be very nice.

Using Repository pattern in laravel 4

so i am new in Laravel.
I want to use repository pattern, and here my problem:
here is my interface:
namespace Repositories\User;
interface IUserRepository
{
public function getAllUsers();
}
here my class:
namespace Repositories\User;
use models\User;
class UserRepository implements IUserRepository
{
public function getAllUsers()
{
return User::all();
}
}
here my controller:
class UserController extends \BaseController {
protected $user;
public function __contruct(IUserRepository $user)
{
$this->user = $user;
}
/**
* Display a listing of the resource.
*
* #return Response
*/
public function index()
{
$users = $this->user->getAllUsers();
return View::make('index');
}
}
i register it in boostrap\start.php
App::bind('Repositories\User\IUserRepository', 'Repositories\User\UserRepository');
i think it can run smooth but it is a result i get :( :
Call to a member function getAllUsers() on a non-object
$users = $this->user->getAllUsers();
So why? :(( Thanks for helping!
If you infect that repo, then use namespace:
public function __contruct(Repositories\User\IUserRepository $user)
{
$this->user = $user;
}

Categories