[QUESTION] Custom repository for Auth\DoctrineUserProvider
thsvkr opened this issue · comments
Package version, Laravel version
- laravel-doctrine/orm 1.7.1
- laravel/framework 8.13
Expected behaviour
class DoctrineUserProvider implements UserProvider
{
/**
* Returns repository for the entity.
* @return EntityRepository
*/
protected function getRepository()
{
return new config('auth.custom_repository') //for example
}
}
Actual behaviour
"Argument 2 passed to App\\Users\\Repositories\\DoctrineUserRepository::__construct() must be an instance of Doctrine\\ORM\\EntityRepository, instance of Doctrine\\ORM\\Mapping\\ClassMetadata given, called in /home/vagrant/code/boox/vendor/doctrine/orm/lib/Doctrine/ORM/Repository/DefaultRepositoryFactory.php on line 68",
class UserProvider implements UserProvider
{
/**
* Returns repository for the entity.
* @return EntityRepository
*/
protected function getRepository()
{
return $this->em->getRepository($this->entity);
}
}
Steps to reproduce the behaviour
Use composite repository
class DoctrineUserRepository implements UserRepository
{
/**
* @var EntityManagerInterface
*/
private EntityManagerInterface $em;
/**
* @var EntityRepository
*/
private EntityRepository $er;
/**
* UserRepository constructor.
* @param EntityManagerInterface $em
* @param EntityRepository $er
*/
public function __construct(EntityManagerInterface $em, EntityRepository $er)
{
$this->em = $em;
$this->er = $er;
}
}
User entity
/**
* Class User
* @package App\Users\Entities
* @ORM\Entity(repositoryClass="App\Users\Repositories\UserRepository")
* @ORM\Table(name="users")
* @ORM\HasLifecycleCallbacks
*/
class User implements AuthenticatableContract, JWTSubject
{
use AuthenticatableTrait;`
//
}
in config/auth.php
'providers' => [
'users' => [
'driver' => 'doctrine',
'model' => \App\Users\Entities\User::class,
]
],
Not sure what you question is, the stacktrace points to errors at your end?
As you see from the stacktrace, the DefaultRepositoryFactory
creates repositories by passing $metadata as the second argument. Looks like you have created a repository which does not accept metadata as second argument?
EDIT: Pressed the wrong button, sorry.
If you would like to create repositories in a different way, then use the configuration option doctrine.managers.default.repository_factory
which should point to a classname which implements Doctrine\ORM\Repository\RepositoryFactory.
Looks like you have created a repository which does not accept metadata as second argument?
Yes, my composite repository does not accept metadata as second argument, but accept Doctrine\Orm\EntityRepository
which in turn already accepts metadata
Composite repository binded to interface in App\Providers\AppServiceProvider
namespace App\Providers;
use App\Users\Entities\User;
use App\Users\Interfaces\UserRepository;
use App\Users\Repositories\DoctrineUserRepository;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\EntityRepository;
use Doctrine\ORM\Mapping\ClassMetadata;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
/**
* Register any application services.
* @return void
*/
public function register()
{
$this->app->when(DoctrineUserRepository::class)
->needs(EntityRepository::class)
->give(
fn() => new EntityRepository(
$this->app->make(
EntityManagerInterface::class
),
new ClassMetadata(User::class)
)
);
$this->app->bind(
UserRepository::class,
DoctrineUserRepository::class
);
//
}
//
}
The authentication controller uses Auth::attempt($credentials)
, but Auth
keeps using Doctrine\Orm\EntityRepository
instead of binded to App\Users\Interfaces\UserRepository
I think that replacing the doctrine.managers.default.repository_factory
will not work for me, because I cannot instantiate the Doctrine\ORM\EntityRepository
for App\Users\Repositories\DoctrineUserRepository
repository
I used this as a reference, but it uses its own authentication
Full stacktrace
{
"message": "Argument 2 passed to App\\Users\\Repositories\\DoctrineUserRepository::__construct() must be an instance of Doctrine\\ORM\\EntityRepository, instance of Doctrine\\ORM\\Mapping\\ClassMetadata given, called in /home/vagrant/code/boox/vendor/doctrine/orm/lib/Doctrine/ORM/Repository/DefaultRepositoryFactory.php on line 68",
"exception": "TypeError",
"file": "/home/vagrant/code/boox/app/Users/Repositories/DoctrineUserRepository.php",
"line": 32,
"trace": [
{
"file": "/home/vagrant/code/boox/vendor/doctrine/orm/lib/Doctrine/ORM/Repository/DefaultRepositoryFactory.php",
"line": 68,
"function": "__construct",
"class": "App\\Users\\Repositories\\DoctrineUserRepository",
"type": "->"
},
{
"file": "/home/vagrant/code/boox/vendor/doctrine/orm/lib/Doctrine/ORM/Repository/DefaultRepositoryFactory.php",
"line": 51,
"function": "createRepository",
"class": "Doctrine\\ORM\\Repository\\DefaultRepositoryFactory",
"type": "->"
},
{
"file": "/home/vagrant/code/boox/vendor/doctrine/orm/lib/Doctrine/ORM/EntityManager.php",
"line": 739,
"function": "getRepository",
"class": "Doctrine\\ORM\\Repository\\DefaultRepositoryFactory",
"type": "->"
},
{
"file": "/home/vagrant/code/boox/vendor/laravel-doctrine/orm/src/Auth/DoctrineUserProvider.php",
"line": 130,
"function": "getRepository",
"class": "Doctrine\\ORM\\EntityManager",
"type": "->"
},
{
"file": "/home/vagrant/code/boox/vendor/laravel-doctrine/orm/src/Auth/DoctrineUserProvider.php",
"line": 106,
"function": "getRepository",
"class": "LaravelDoctrine\\ORM\\Auth\\DoctrineUserProvider",
"type": "->"
},
{
"file": "/home/vagrant/code/boox/vendor/tymon/jwt-auth/src/JWTGuard.php",
"line": 124,
"function": "retrieveByCredentials",
"class": "LaravelDoctrine\\ORM\\Auth\\DoctrineUserProvider",
"type": "->"
},
{
"file": "/home/vagrant/code/boox/vendor/laravel/framework/src/Illuminate/Auth/AuthManager.php",
"line": 307,
"function": "attempt",
"class": "Tymon\\JWTAuth\\JWTGuard",
"type": "->"
},
{
"file": "/home/vagrant/code/boox/vendor/laravel/framework/src/Illuminate/Support/Facades/Facade.php",
"line": 261,
"function": "__call",
"class": "Illuminate\\Auth\\AuthManager",
"type": "->"
},
{
"file": "/home/vagrant/code/boox/app/Auth/Http/Controllers/AuthController.php",
"line": 22,
"function": "__callStatic",
"class": "Illuminate\\Support\\Facades\\Facade",
"type": "::"
},
{
"file": "/home/vagrant/code/boox/vendor/laravel/framework/src/Illuminate/Routing/Controller.php",
"line": 54,
"function": "login",
"class": "App\\Auth\\Http\\Controllers\\AuthController",
"type": "->"
},
{
"file": "/home/vagrant/code/boox/vendor/laravel/framework/src/Illuminate/Routing/ControllerDispatcher.php",
"line": 45,
"function": "callAction",
"class": "Illuminate\\Routing\\Controller",
"type": "->"
},
{
"file": "/home/vagrant/code/boox/vendor/laravel/framework/src/Illuminate/Routing/Route.php",
"line": 255,
"function": "dispatch",
"class": "Illuminate\\Routing\\ControllerDispatcher",
"type": "->"
},
{
"file": "/home/vagrant/code/boox/vendor/laravel/framework/src/Illuminate/Routing/Route.php",
"line": 197,
"function": "runController",
"class": "Illuminate\\Routing\\Route",
"type": "->"
},
{
"file": "/home/vagrant/code/boox/vendor/laravel/framework/src/Illuminate/Routing/Router.php",
"line": 691,
"function": "run",
"class": "Illuminate\\Routing\\Route",
"type": "->"
},
{
"file": "/home/vagrant/code/boox/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php",
"line": 128,
"function": "Illuminate\\Routing\\{closure}",
"class": "Illuminate\\Routing\\Router",
"type": "->"
},
{
"file": "/home/vagrant/code/boox/vendor/laravel/framework/src/Illuminate/Routing/Middleware/SubstituteBindings.php",
"line": 41,
"function": "Illuminate\\Pipeline\\{closure}",
"class": "Illuminate\\Pipeline\\Pipeline",
"type": "->"
},
{
"file": "/home/vagrant/code/boox/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php",
"line": 167,
"function": "handle",
"class": "Illuminate\\Routing\\Middleware\\SubstituteBindings",
"type": "->"
},
{
"file": "/home/vagrant/code/boox/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php",
"line": 103,
"function": "Illuminate\\Pipeline\\{closure}",
"class": "Illuminate\\Pipeline\\Pipeline",
"type": "->"
},
{
"file": "/home/vagrant/code/boox/vendor/laravel/framework/src/Illuminate/Routing/Router.php",
"line": 693,
"function": "then",
"class": "Illuminate\\Pipeline\\Pipeline",
"type": "->"
},
{
"file": "/home/vagrant/code/boox/vendor/laravel/framework/src/Illuminate/Routing/Router.php",
"line": 668,
"function": "runRouteWithinStack",
"class": "Illuminate\\Routing\\Router",
"type": "->"
},
{
"file": "/home/vagrant/code/boox/vendor/laravel/framework/src/Illuminate/Routing/Router.php",
"line": 634,
"function": "runRoute",
"class": "Illuminate\\Routing\\Router",
"type": "->"
},
{
"file": "/home/vagrant/code/boox/vendor/laravel/framework/src/Illuminate/Routing/Router.php",
"line": 623,
"function": "dispatchToRoute",
"class": "Illuminate\\Routing\\Router",
"type": "->"
},
{
"file": "/home/vagrant/code/boox/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php",
"line": 166,
"function": "dispatch",
"class": "Illuminate\\Routing\\Router",
"type": "->"
},
{
"file": "/home/vagrant/code/boox/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php",
"line": 128,
"function": "Illuminate\\Foundation\\Http\\{closure}",
"class": "Illuminate\\Foundation\\Http\\Kernel",
"type": "->"
},
{
"file": "/home/vagrant/code/boox/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/TransformsRequest.php",
"line": 21,
"function": "Illuminate\\Pipeline\\{closure}",
"class": "Illuminate\\Pipeline\\Pipeline",
"type": "->"
},
{
"file": "/home/vagrant/code/boox/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php",
"line": 167,
"function": "handle",
"class": "Illuminate\\Foundation\\Http\\Middleware\\TransformsRequest",
"type": "->"
},
{
"file": "/home/vagrant/code/boox/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/TransformsRequest.php",
"line": 21,
"function": "Illuminate\\Pipeline\\{closure}",
"class": "Illuminate\\Pipeline\\Pipeline",
"type": "->"
},
{
"file": "/home/vagrant/code/boox/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php",
"line": 167,
"function": "handle",
"class": "Illuminate\\Foundation\\Http\\Middleware\\TransformsRequest",
"type": "->"
},
{
"file": "/home/vagrant/code/boox/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/ValidatePostSize.php",
"line": 27,
"function": "Illuminate\\Pipeline\\{closure}",
"class": "Illuminate\\Pipeline\\Pipeline",
"type": "->"
},
{
"file": "/home/vagrant/code/boox/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php",
"line": 167,
"function": "handle",
"class": "Illuminate\\Foundation\\Http\\Middleware\\ValidatePostSize",
"type": "->"
},
{
"file": "/home/vagrant/code/boox/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/PreventRequestsDuringMaintenance.php",
"line": 87,
"function": "Illuminate\\Pipeline\\{closure}",
"class": "Illuminate\\Pipeline\\Pipeline",
"type": "->"
},
{
"file": "/home/vagrant/code/boox/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php",
"line": 167,
"function": "handle",
"class": "Illuminate\\Foundation\\Http\\Middleware\\PreventRequestsDuringMaintenance",
"type": "->"
},
{
"file": "/home/vagrant/code/boox/vendor/fruitcake/laravel-cors/src/HandleCors.php",
"line": 57,
"function": "Illuminate\\Pipeline\\{closure}",
"class": "Illuminate\\Pipeline\\Pipeline",
"type": "->"
},
{
"file": "/home/vagrant/code/boox/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php",
"line": 167,
"function": "handle",
"class": "Fruitcake\\Cors\\HandleCors",
"type": "->"
},
{
"file": "/home/vagrant/code/boox/vendor/fideloper/proxy/src/TrustProxies.php",
"line": 57,
"function": "Illuminate\\Pipeline\\{closure}",
"class": "Illuminate\\Pipeline\\Pipeline",
"type": "->"
},
{
"file": "/home/vagrant/code/boox/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php",
"line": 167,
"function": "handle",
"class": "Fideloper\\Proxy\\TrustProxies",
"type": "->"
},
{
"file": "/home/vagrant/code/boox/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php",
"line": 103,
"function": "Illuminate\\Pipeline\\{closure}",
"class": "Illuminate\\Pipeline\\Pipeline",
"type": "->"
},
{
"file": "/home/vagrant/code/boox/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php",
"line": 141,
"function": "then",
"class": "Illuminate\\Pipeline\\Pipeline",
"type": "->"
},
{
"file": "/home/vagrant/code/boox/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php",
"line": 110,
"function": "sendRequestThroughRouter",
"class": "Illuminate\\Foundation\\Http\\Kernel",
"type": "->"
},
{
"file": "/home/vagrant/code/boox/public/index.php",
"line": 52,
"function": "handle",
"class": "Illuminate\\Foundation\\Http\\Kernel",
"type": "->"
}
]
}
I see a solution in creating a separate custom repository factory next to the default one and using it in LaravelDoctrine\ORM\Auth\DoctrineUserProvider` optionally based on the configuration, but I'm not sure how good this design is
class DoctrineUserRepository implements UserRepository
{
/**
* @var EntityManagerInterface
*/
private EntityManagerInterface $em;
/**
* @var EntityRepository
*/
private EntityRepository $er;
public function __construct(EntityManagerInterface $em, \Doctrine\ORM\Mapping\ClassMetadata $class)
{
$this->em = $em;
$this->er = new EntityRepository($em, $class->name);
}
}
Have you tried something like this?
Oh it works thanks
Not new EntityRepository($em, $class->name)
, but new EntityRepository($em, $class)
in __construct
because
Argument 2 passed to Doctrine\\ORM\\EntityRepository::__construct() must be an instance of Doctrine\\ORM\\Mapping\\ClassMetadata, string given