Undefined property while trying to connect to a laravel powered database - php

I tried to create middleware to control the access of users, why I created a table roles may I have this error
Undefined property: Illuminate\Database\Eloquent\Builder::$role_name
User model
<?php
namespace App;
use Illuminate\Foundation\Auth\User as Authenticatable;
class User extends Authenticatable
{
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = [
'name', 'email', 'password',
];
/**
* The attributes that should be hidden for arrays.
*
* #var array
*/
protected $hidden = [
'password', 'remember_token',
];
public function roles(){
return $this->belongsTo('App\Role','role_id','id');
}
public function hasRole($title){
$user_role=$this->with('roles');
if(!is_null($user_role)){
$user_role=$user_role->role_name;
}
return ($user_role==$title)?true:false;
}
}
the middleware create
<?php
namespace App\Http\Middleware;
use Closure;
class create
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next,$Admin,$SuperAdmin)
{
$User=$request->user();
return ($User->hasRole($SuperAdmin)||$User->hasRole($Admin))?$next($request):response(view('errors.401'),401);
}
}

What you what to do is to receive the relation object. You can do it in this way:
public function hasRole($title){
$user_role = '';
if(!is_null($this->roles)){
$user_role=$this->roles->role_name;
}
return ($user_role==$title)?true:false;
}
The with(...) statment is useful for receiving relation when you're working on collection of elements (eager load constraint).

Related

Call to undefined method App\User::admin() error in Session in Laravel

I'm trying to put some sessions in my project and it's working fine when I'm logged out. But when I'm logged in as an Admin I'm getting the following error:
Call to undefined method App\User::admin()
this is my routes
Route::resource('/create','PagesController#showCreate')->middleware(IsAdmin::class);
Route::get('/users','UserController#index')->middleware(IsAdmin::class);
Route::get('/verify','UserController#userVerify')->middleware(IsAdmin::class);
this is my User model
<?php
namespace App;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
class User extends Authenticatable
{
use Notifiable;
/**
* The attributes that are mass assignable.
* protected $table = 'users';
*public $primaryKey ='id';
* #var array
*/
protected $fillable = [
'name', 'email', 'password','userType',
];
/**
* The attributes that should be hidden for arrays.
*
* #var array
*/
protected $hidden = [
'password', 'remember_token',
];
/**
* The attributes that should be cast to native types.
*
* #var array
*/
protected $casts = [
'email_verified_at' => 'datetime',
'admin' => 'boolean',
];
public function posts(){
return $this->hasMany('App\Post');
}
public function isAdmin()
{
return $this->admin;
}
}
and this is my IsAdmin class
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Support\Facades\Auth;
class IsAdmin
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
{
if ( Auth::check() && Auth::user()->admin() )
{
return $next($request);
}
return redirect('home');
}
}
}
And every time I try to redirect to other routes I get the same error except for the dashboard
Change if statement in your IsAdmin class:
if ( Auth::check() && Auth::user()->isAdmin() )

Laravel Unit test fails with custom attributes

I'm trying to write a unit test on my user model that tests if the soft deleted record is still present in the database.
/**
* check if users are soft deleted only
*
* #return void
*/
public function testUserIsSoftDeleted()
{
$user = factory(User::class)->create();
$user->delete();
$this->assertSoftDeleted('users', $user->toArray());
}
This test runs fine until I add a custom attribute to the model.
<?php
namespace App;
use Laravel\Passport\HasApiTokens;
use Spatie\Permission\Traits\HasRoles;
use Illuminate\Notifications\Notifiable;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Foundation\Auth\User as Authenticatable;
use OwenIt\Auditing\Contracts\Auditable;
class User extends Authenticatable implements MustVerifyEmail, Auditable
{
use HasApiTokens, Notifiable, SoftDeletes, HasRoles, \OwenIt\Auditing\Auditable;
protected $guard_name = 'web';
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = [
'email', 'password', 'active', 'activation_token', 'email_verified_at'
];
/**
* The attributes that should be hidden for arrays.
*
* #var array
*/
protected $hidden = [
'password', 'remember_token', 'activation_token'
];
/**
* The attributes that should be cast to native types.
*
* #var array
*/
protected $casts = [
'email_verified_at' => 'datetime',
];
/**
* The attributes that should be added to the JSON response
*
* #var array
*/
protected $appends = ['md5_email'];
/**
* Convert email address into md5 string
*
* #var string
*/
public function getMd5EmailAttribute()
{
return md5(strtolower(trim($this->email)));
}
}
When I run the test I get the following error.
How do I include custom attributes in the Found array?
To skip md5_email from the query, assign the toArray result to an array and unset the md5_email
Something like
public function testUserIsSoftDeleted()
{
$user = factory(User::class)->create();
$user->delete();
$userInfoArray = $user->toArray()
// This should skip md5_email getting added to the query
unset($userInfoArray["md5_email"])
$this->assertSoftDeleted('users', $userInfoArray);
}
As stated by Cerlin the md5_email attribute in not present in the database, that's why you get the error. You have many options to make the test pass. You might simply unset the md5_email from the user array or, for the sake of clarity, rewrite your test as follow:
/**
* check if users are soft deleted only
*
* #return void
*/
public function testUserIsSoftDeleted()
{
$user = factory(User::class)->create();
$user->delete();
$this->assertSoftDeleted('users', $user->only('id', 'name', 'email'));
}

Laravel Method notify does not exist

I am trying to notify user if a new form is inserted to database, but I get this error:
BadMethodCallException in Macroable.php line 74: Method notify does not exist.
This is the notification class
<?php
namespace App\Notifications\Admin;
use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Notification;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage;
use App\Models\Admin\Forms\Prescriptions;
class PrescriptionNotification extends Notification
{
use Queueable;
public $Prescription;
/**
* Create a new notification instance.
*
* #return void
*/
public function __construct(Prescriptions $Prescription)
{
$this->Prescriptions = $Prescription;
}
/**
* Get the notification's delivery channels.
*
* #param mixed $notifiable
* #return array
*/
public function via($notifiable)
{
return ['database'];
}
/**
* Get the mail representation of the notification.
*
* #param mixed $notifiable
* #return \Illuminate\Notifications\Messages\MailMessage
*/
public function toMail($notifiable)
{
$url = url('/admin/prescriptions/edit/'.$this->Prescriptions->id);
return (new MailMessage)
->line('New form')
->action('View', $url)
->line('');
}
/**
* Get the array representation of the notification.
*
* #param mixed $notifiable
* #return array
*/
public function toArray($notifiable)
{
return [
'test' => 'test'
];
}
}
And in my controller I am doing this:
$users = App\User::all()->where('role', 3);
//trigger email notification
$Prescription = Prescriptions::first();
$users->notify(new PrescriptionNotification($Prescription));
Been following This tutorial, but still to no avail. I have Notifiable in the user model. What else can be done? I am losing my mind what causes this error.
As requested my User class:
<?php
namespace App;
use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;
class User extends Authenticatable
{
use Notifiable;
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = [
'name', 'email', 'password',
];
/**
* The attributes that should be hidden for arrays.
*
* #var array
*/
protected $hidden = [
'password', 'remember_token',
];
//is admin
public function isAdmin()
{
return $this->role; // this looks for an admin column in your users table
}
//relationship with prescription forms
public function confirmations()
{
return $this->hasMany('App\Models\Admin\Forms\Prescription_confirmations', 'physician_id');
}
//relationship with prescriptions forms
public function prescriptions()
{
return $this->hasMany('App\Models\Admin\Forms\Prescriptions', 'physician_id');
}
}
$users is a collection, so you are calling notify method on a collection which will lead to error. And the method notify only exist on user object instance.
You can do this
<?php
foreach ($users as $user) {
$user->notify(new PrescriptionNotification($Prescription));
}
Think it's easier to use Notification Facade.
Notification::send($users, new PrescriptionNotification($Prescription));
And you need to call Notification facade with use like this,
use Illuminate\Support\Facades\Notification;
Also, you can use higher-order messages:
$users->each->notify(new PrescriptionNotification($Prescription));
In my case I forgot to implement the Notifiable trait.
So you have a users class for example:
use Illuminate\Notifications\Notifiable;
class Users {
use Notifiable;
...
}

Dispatching an event in Laravel 5 on model created

I wan to create a Laravel signup system where I would send an email to verify the email once a user has signed up. I tried adding an event dispatched to the created method but I got an error
Fatal error: Non-static method Illuminate\Contracts\Events\Dispatcher::fire() cannot be called statically
Here is what I came up with.
<?php
namespace App;
use Laravel\Cashier\Billable;
use Laravel\Spark\Teams\CanJoinTeams;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Foundation\Auth\User as BaseUser;
use Laravel\Spark\Auth\TwoFactor\Authenticatable as TwoFactorAuthenticatable;
use Illuminate\Contracts\Events\Dispatcher as EventDispatcher;
use Laravel\Spark\Contracts\Auth\TwoFactor\Authenticatable as TwoFactorAuthenticatableContract;
class User extends BaseUser implements TwoFactorAuthenticatableContract
{
use Billable, TwoFactorAuthenticatable,CanJoinTeams;
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = [
'email',
'name',
'password',
];
/**
* The accessors to append to the model's array form.
*
* #var array
*/
protected $appends = [
];
/**
* The attributes excluded from the model's JSON form.
*
* #var array
*/
protected $hidden = [
'card_brand',
'card_last_four',
'extra_billing_info',
'password',
'remember_token',
'stripe_id',
'stripe_subscription'
];
/**
* Boot the model.
*
* #return void
*/
public static function boot()
{
parent::boot();
static::creating(function ($user) {
$user->token = str_random(30);
});
static::created(function ( $user) {
EventDispatcher::fire('UserCreated');
});
}
/**
* Confirm the user.
*
* #return void
*/
public function confirmEmail()
{
$this->verified = true;
$this->token = null;
$this->save();
}
}
I also tried changing the code to
use Billable, TwoFactorAuthenticatable,CanJoinTeams, EventDispatcher;
and replacing the boot part with
static::created(function ( $user, EventDispatcher $event) {
$event->fire('UserCreated');
});
But it gave me another error
App\User cannot use Illuminate\Contracts\Events\Dispatcher - it is not a trait
How do I fire the event once the model has been created ?
In Laravel >5.4 and higher, you can associate eloquent event in your Model class to fire a custom event - e.g. 'created' => ProjectCreated::class. So basically, on Eloquent model created fire ProjectCreated Event.
class Project extends Model
{
/**
* #var array
*/
protected $fillable = ['title', 'description', 'client_id'];
/**
*
* Eloquent model events
*
* #var array
*/
protected $dispatchesEvents = [
'created' => ProjectCreated::class,
];
}
Model's lifecycle events are fired by Eloquent already so no need to fire them yourself. Event name is created with the following code:
$event = "eloquent.{$event}: ".get_class($model);
Therefore, if you want to listen on the created event, you need to listen on "eloquent.created: App\User". The event handler will get the related User model as one of handle() parameters.
If you hovewer want to dispatch an event of your own, you can do that using Event facade:
Event::fire('UserCreated', $user);
You can read more about events in Laravel here: https://laravel.com/docs/5.1/events

User model error after Laravel update (Class User contains 3 abstract method)

After I update my laravel using composer update, I got this
"type":"Symfony\\Component\\Debug\\Exception\\FatalErrorException",
"message":"Class User contains 3 abstract methods and must therefore be declared abstract or implement the remaining methods (Illuminate\\Auth\\UserInterface::setRememberToken, Illuminate\\Auth\\UserInterface::getRememberTokenName, Illuminate\\Auth\\Reminders\\RemindableInterface::getReminderEmail)",
"file":"D:\app\\models\\User.php",
"line":54
error when authenticating.
This error happened because of the latest commit.
You can check the upgrade documentation here, to fix this issue.
As stated, add the following to your User.php model class:
public function getRememberToken()
{
return $this->remember_token;
}
public function setRememberToken($value)
{
$this->remember_token = $value;
}
public function getRememberTokenName()
{
return 'remember_token';
}
This is what worked for me by adding the below to app/User
public function getJWTIdentifier()
{
return $this->getKey();
}
/**
* Return a key value array, containing any custom claims to be added to the JWT.
*
* #return array
*/
public function getJWTCustomClaims()
{
return [];
}
Example app/User
<?php
namespace App;
use Tymon\JWTAuth\Contracts\JWTSubject;
use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;
class User extends Authenticatable implements JWTSubject
{
use Notifiable;
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = [
'name', 'email', 'password',
];
/**
* The attributes that should be hidden for arrays.
*
* #var array
*/
protected $hidden = [
'password', 'remember_token',
];
/**
* Get the identifier that will be stored in the subject claim of the JWT.
*
* #return mixed
*/
public function getJWTIdentifier()
{
return $this->getKey();
}
/**
* Return a key value array, containing any custom claims to be added to the JWT.
*
* #return array
*/
public function getJWTCustomClaims()
{
return [];
}
}

Categories