What does this mean, and how do I fix it??
FatalErrorException in User.php line 8:
Class App\User contains 6 abstract methods and must therefore be declared abstract or implement the remaining methods (Illuminate\Contracts\Auth\Authenticatable::getAuthIdentifierName, Illuminate\Contracts\Auth\Authenticatable::getAuthIdentifier, Illuminate\Contracts\Auth\Authenticatable::getAuthPassword, ...)
It happened when I was trying to log into my dashboard for my laravel app.
This is about the interface implements. If you want to implement the interface, you need to mention all the methods which interface declared.
Illuminate\Contracts\Auth\Authenticatable
The interface definition:
interface Authenticatable {
public function getAuthIdentifierName();
public function getAuthIdentifier();
public function getAuthPassword();
public function getRememberToken();
public function setRememberToken($value);
public function getRememberTokenName();
}
So your User class must have the methods above.
class User implements Illuminate\Contracts\Auth\Authenticatable
{
public function getAuthIdentifierName() {}
public function getAuthIdentifier(){}
public function getAuthPassword(){}
public function getRememberToken(){}
public function setRememberToken($value){}
public function getRememberTokenName(){}
}
Even you do not want write code in those method, however, you still need to write empty method in your user class.
Solution:
The interface mainly used for Auth mechanism. If you do not want use for Auth, you just remove your Authenticatable interface from your User class.
If you need it use for Auth, you need to implement all the interface methods and get it right. More information please read the following websites:
Laravel doc: Custom User Provider and Authenticatable Class
How do I create a custom auth in laravel 5
Replacing the laravel authentication with a custom authentication
Related
We have a Laravel 8 application.
We're using the standard Laravel Auth facade to retrieve the authenticated user.
Our User model has a few custom functions, the most important of which is a shorthand function, hasPermissionTo(). (The reason why is because we have a very custom RBAC setup.)
So in a lot of our controllers, we have something like this...
use Illuminate\Routing\Controller as BaseController;
class ExampleController extends BaseController
{
public function index()
{
if (\Auth::user()->hasPermissionTo('Management:View Users')) {
// do something.
}
// etc.
}
}
That's all well and good until we start running static analysis. We're using Larastan, which is giving me these errors:
------ -------------------------------------------------------------------------------------------
Line Http/Controllers/ExampleController.php
------ -------------------------------------------------------------------------------------------
48 Call to an undefined method Illuminate\Contracts\Auth\Authenticatable::hasPermissionTo().
This also makes sense because the Auth facade proxies Illuminate\Auth\AuthManager and Auth::user(), via __call() magic, normally resolves to Illuminate\Auth\SessionGuard::user() and that typehints this...
/**
* Get the currently authenticated user.
*
* #return \Illuminate\Contracts\Auth\Authenticatable|null
*/
public function user()
{
...
So finally, my question:
Where is the failure here? Do I need to a) configure my static analysis tool better, b) configure Laravel better to more accurately return a specific type, or c) do I need to add explicit if (Auth::user() instanceof User) { ... } clauses all throughout my code?
Is there a correct way to override one of the Laravel stock classes with a more specific one of my own to address more specific functionality? Is there way to type-hint the actual authenticated User into the function declaration so I can declare function index(User $authenticatedUser) and have Laravel autopopulate this in with a more specific type hint?
I understand that I could just add an exclusion for this particular issue in Larastan and move on with my life, but the error is designed to protect against a specific class of error--i.e. if I added Auth0 and replaced App\Model\User with Auth0\Login\User, then I would have an Authenticatable class that fails to run hasPermissionTo(), and I'd have to now fix a bunch of code.
Eventually, this is how we worked around the problem. We added a type-hint for Larastan, so it can infer that $user has this HasRolesContract trait which provides hasPermissionTo().
public function index()
{
/** #var \App\Traits\HasRolesContract */
$user = \Auth::user();
if ($user->hasPermissionTo('Management:View Users')) {
Hopefully this helps someone else!
(Thanks for the nudge, #djjavo)
User model
class User extends Authenticatable{
public function enrollments() {
return $this->hasMany('App\enrollments','user_email');
}
}
Batch model
class batch extends Model{
protected $table = 'batch';
public function enrollments() {
return $this->hasMany('App\enrollments');
}
}
Enrollments model
class enrollments extends Model{
public function batch() {
return $this->belongsTo('App\batch');
}
public function user() {
return $this->belongsTo('App\User','email');
}
}
if I use $enrollment->batch->title, it works..
but if I use $enrollment->user->name, it gives an error
Trying to get property of non-object
Please help, I am stuck
Thanks in advance
EDIT
The problem arose after I changed the foreign key from between user and enrollment from id to email and renamed my column to user_email from user_id. Before that code was working fine.
Solved
Got the problem, It was with some data in enrollment which didn't have registered email with user.
This code will note work simply because User is not a child of Model. To fix it you must extend from Model. Authenticatable is an interface and there is an equivalent trait; there is no such class.
You must implement the interface if you want your user class to be Authenticatable. But to answer your question, extend the base model, Model.
class User extends Model {
public function enrollments() {
return $this->hasMany('App\enrollments','user_email');
}}
In addition:
If you need to log an existing user instance into your application,
you may call the login method with the user instance. The given object
must be an implementation of the
Illuminate\Contracts\Auth\Authenticatable contract. Of course, the
App\User model included with Laravel already implements this
interface:
https://laravel.com/docs/5.3/authentication
I encountered this issue using the repository pattern. Currently I use an interface, and a custom class to achieve it, then type-hint it into the controller's construct and because of Laravel, it will solve the repositories' dependencies automatically and recursively.
I also do this in a service provider:
$this->app->bind(path/to/repoInterface,path/to/implementationClass)
However, because of the way I coded these repositories, in order to avoid code duplication, I created an abstract class that has a common method to all these repositories. This class is as follows:
abstract class CommonRepo{
public function __construct(SomeModelClass model){}
public function commonMethod(){//Code here}
And my repositories have the following structure:
public class ExampleRepository extends CommonRepo implements ExampleRepositoryI{
public function __construct(){
parent::__construct();
}
}
Laravel doesn't like this, so its giving this error:
Argument 1 passed to path/to/repo/CommonRepo::__construct() must be an instance of path/to/model/SomeModelClass, none given, called in...
So, obviously is not resolving the dependency of the class CommonRepo, but it does resolve the dependencies on the normal repositories.
I'd like, if it's possible, to use type-hinting (the Laravel way) without having to do anything related to the new operator
How can I, then, resolve that class's dependencies ?
PD: Using Laravel 5.2
Parent constructor is called like normal function without touching dependency resolver so you should do one of two possibilities:
public class ExampleRepository extends CommonRepo implements ExampleRepositoryI
{
public function __construct(SomeModelClass $model){
parent::__construct($model);
}
}
or
public class ExampleRepository extends CommonRepo implements ExampleRepositoryI
{
public function __construct(){
parent::__construct(App::make(SomeModelClass::class));
}
}
nice question. I did some tinkering, though I don't know if this is what you're looking for. But you can dynamically create an instance of Eloquent model required by your repository class.
Let's say you have your User model class stored in app\Models\User.php:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class User extends Model
{
//
}
You then create a base abstract class for all of your repository classes: app\Repositories\BaseRepository.php. This is where you place all common functionalities for your repository classes. But rather than injecting the Eloquent instance through the constructor, you may add a method named getModel() to dynamically create an instance of Eloquent model for your repository.
<?php
namespace App\Repositories;
use ReflectionClass;
use RuntimeException;
use Illuminate\Support\Str;
abstract class BaseRepository
{
protected $modelNamespace = 'App\\Models\\';
public function getById($id)
{
return $this->getModel()->find($id);
}
public function getModel()
{
$repositoryClassName = (new ReflectionClass($this))->getShortName();
$modelRepositoryClassName = $this->modelNamespace . Str::replaceLast('Repository', '', $repositoryClassName);
if (! class_exists($modelRepositoryClassName)) {
throw new RuntimeException("Class {$modelRepositoryClassName} does not exists.");
}
return new $modelRepositoryClassName;
}
}
Now let's say you want to create a repository for your User model, and this user's repository must implement the following interface: app\Repositories\UserRepositoryInterface.php
<?php
namespace App\Repositories;
interface UserRepositoryInterface
{
public function getByEmail($email);
}
You create app\Repositories\UserRepository.php class and simply extend it from the BaseRepository class. Also don't forget to implement all specific implementations defined on UserRepositoryInterface.
<?php
namespace App\Repositories;
use App\Repositories\BaseRepository;
use App\Repositories\UserRepositoryInterface;
class UserRepository extends BaseRepository implements UserRepositoryInterface
{
public function getByEmail($email)
{
return $this->getModel()->where('email', $email)->firstOrFail();
}
}
This way you can bind the UserRepositoryInterface to it's implementation like so:
$this->app->bind(\App\Repositories\UserRepositoryInterface::class, \App\Repositories\UserRepository::class);
Finally you can freely inject the UserRepositoryInterface to a controller's constructor or methods. You can also resolve it via service container like this:
$userRepository = App::make(App\Repositories\UserRepositoryInterface::class);
$userRepository->getByEmail('john#example.com');
Of course there's a catch to this approach. The repository class should be started with the associated model, so the InvoiceRepository.php is dedicated for Invoice.php model class.
Hope this help!
This might help. You can listen in for when an object resolves and set attributes.
$this->app->resolving(CommonRepo::class, function ($object, $app) {
// Called when container resolves object of any type...
$object->commonObject = app(CommonObject::class);
});
Docs: https://laravel.com/docs/5.4/container#container-events
I am understanding Laravel(5.1 version although 5.2 now recently comes) framework...and studying it deeply...What I am trying to ask let me elaborate through some example: I have created the model named Blog:
namespace App;
use Illuminate\Database\Eloquent\Model;
class Blog extends Model {
protected $fillable = ['title','body'];
}
Now in my controller I am accessing the function create() of this class in my controller store() method like: public function store(BlogRequest $request)
{
$input = Request::all();
Blog::create($input);
return redirect('blogs');
} As you can see that in above controller method we are accessing the static function/method create() i.e Blog::create($input) ..so the question is as there are so many other methods exists like create() method of a model(Blog) class which extends the Model class...is there any way/strategy/function to find out/know all the functions of this Model Class...
Yes! You can refer to the API documentation.
For example, I searched for model and found Illuminate\Database\Eloquent\Model, which is the class your models extend and there it is the create static method.
You can change the Laravel version on the top left and filter for classes, namespaces, interfaces and traits on the top right. Pretty neat!
Edit:
You can use the getMethods method on the ReflectionClass to list all available methods for a given class.
For example:
$methods = (new ReflectionClass('\App\Blog'))->getMethods();
dd($methods);
I'm new to Laravel, just toying with it and getting my head back into MVC.
I'm trying to make my own User auth provider (custom password hashing) as a service that implements the UserProviderInterface within Laravel.
Inside app/controllers/Account.php:
public function postCreate() {
Auth::attempt(Input::all());
}
I have my app routing Auth::attempt through my custom provider class, and passing me the Input::all from the form into a retrieveByCredentials method.
Inside app/services/PasswordHash/PasswordHashUserProvider.php:
public function retrieveByCredentials(array $credentials) {
// Why can't I do this?
//Error: PasswordHash/User not found
User::find($credentials['username']);
dd($credentials);
}
I am lost at this point on how to access my User eloquent models from within this service class. I tried namespaces but had no luck.
The boot method on service providers use the service container to inject dependencies. To that end, you should be able to do the following (not using Facades, but I don't use facades that often).
class PasswordHashUserProvider extends ServiceProvider
{
protected $user;
public function boot(User $user)
{
$this->user = $user;
}
}
You can then access user via $this->user
Source: https://laravel.com/docs/master/providers#the-boot-method