Laravel Unit test fails with custom attributes - php

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'));
}

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() )

Subscription won't update in database after subscription is updated in Stripe using Laravel Cashier and Jenssegers MongoDB

I am having trouble getting my new subscription to be updated in MongoDB Database. Im using Laravel Cashier, Stripe, and Jenssegers MongoDB.
In the stripe dashboard, users have been successfully added as customers and subscribers.
Here is the ERROR:
[23:24:17] LOG.error: Call to a member function prepare() on null
{"userId":"4ec1b45d36623t2269477d0...
Here is where the ERROR lives:
return true;
}
$statement = $this->getPdo()->prepare($query);
$this->bindValues($statement, $this->prepareBindings($bindings));
Here is my controller:
namespace App\Http\Controllers;
use App\Plan;
use App\User;
use Exception;
use Illuminate\Http\Request;
class CheckoutController extends Controller
{
/**
* The collection name
*
* #var array
*/
public function checkout($plan_id)
{
$plan = Plan::findOrFail($plan_id);
$intent = auth()->user()->createSetupIntent();
return view('billing.checkout', compact('plan', 'intent'));
}
public function process(Request $request)
{
$plan = Plan::findOrFail($request->input('billing_plan_id'));
try {
auth()->user()->newSubscription($plan->name, $plan->stripe_plan_id)-
>create($request->input('payment-method'));
return redirect()->route('billing')->withMessage('Subscribed Successfully');
} catch (Exception $e) {
return redirect()->back()->withError($e->getMessage());
}
}
Here is My User Model:
namespace App;
use Illuminate\Notifications\Notifiable;
use Illuminate\Database\Eloquent\Model;
use Jenssegers\Mongodb\Auth\User as Authenticatable;
use Laravel\Cashier\Billable;
use Illuminate\Foundation\Auth;
class User extends Authenticatable
{
use Billable, Notifiable;
protected $connection = 'mongodb';
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = [
'name', 'email', 'username', 'password', 'phone', 'last_login_at',
'last_login_ip',
];
/**
* The collection name
*
* #var array
*/
protected $table = 'users';
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $dates = ['deleted_at'];
/**
* 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',
];
}
Here is My Plan Model:
namespace App;
use Jenssegers\Mongodb\Eloquent\Model;
/**
* #method static findOrFail($plan_id)
*/
class Plan extends Model
{
protected $fillable = [
'name',
'price',
'stripe_plan_id'
];
}
Here is my Subscription Migration:
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Migrations\Migration;
use Jenssegers\Mongodb\Schema\Blueprint;
class CreateSubscriptionsTable extends Migration
{
/**
* The name of the database connection to use.
*
* #var string
*/
protected $connection = 'mongodb';
public function up()
{
Schema::create('subscriptions', function (Blueprint $collection) {
$collection->bigIncrements('id');
$collection->unsignedBigInteger('userid');
$collection->string('name');
$collection->string('stripe_id');
$collection->string('stripe_status');
$collection->string('stripe_plan')->nullable()->change();
$collection->integer('quantity')->nullable()->change();
$collection->timestamp('trial_ends_at')->nullable();
$collection->timestamp('ends_at')->nullable();
$collection->timestamps();
$collection->index(['user_id', 'stripe_status']);
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::dropIfExists('subscriptions');
}
}
Please help me figure out the source of this issue and how to solve it.
Make sure your model (i'm guessing it's a model but you didn't mention / show it) that is calling $this->getPdo() is extending Jenssegers eloquent model class and not Laravels.
For example:
Replace
class MyModel extends Model
With
class MyModel extends \Jenssegers\Mongodb\Eloquent\Model
Partial Solution:
Although I am getting the same error below
"Call to a member function prepare() on null {"userId":"4ec1b45d36623t2269477d0...".
In order to get the Subscription to update in the database I went into the Subscription.php file in Cashier and I replaced
use Illuminate\Database\Eloquent\Model;
with
use Jenssegers\Mongodb\Eloquent\Model;
This will fix database update issue, but something wierd is still going on in the Connection.php file causing the error.
$statement = $this->getPdo()->prepare($query);

How to have a different Email column name and in hasOne relation table for password reset Laravel 5.8

I tried to change default email field for reset password (the email field is in other table that my User model has hasOne relation to this table, and field name is Email not email), I override method getEmailForPasswordReset in User model with field Email from hasOne relation from another table. And now its just refresh the page and nothing happens, its even didn't write reset request with token to password_resets table.
If I go with the flow route->controller->method, I'm getting to Illuminate\Foundation\Auth\SendsPasswordResetEmails to method sendResetLinkEmail and here I think this check $this->validateEmail($request) doesn't work. If I doing dd to $request before this check I get my request.
Below I've added my image of overriding the getEmailForPasswordReset method
This is my User model:
<?php
namespace App;
use Illuminate\Notifications\Notifiable;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Foundation\Auth\User as Authenticatable;
/**
* Class User
* #package App
*/
class User extends Authenticatable
{
use Notifiable;
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = [
'Allowed_Users', 'Email', 'password',
];
/**
* The attributes that should be hidden for arrays.
*
* #var array
*/
protected $hidden = [
'password', 'remember_token',
];
protected $table = 'sometable';
protected $primaryKey = 'recordId';
public $timestamps = false;
/**
* The attributes that should be cast to native types.
*
* #var array
*/
protected $casts = [
'email_verified_at' => 'datetime',
'Allowed_Users' => 'integer',
];
public function property()
{
return $this->hasOne('App\Property', 'id', 'Allowed_Users');
}
public function getEmailForPasswordReset()
{
$user_property = $this->property()->get();
return $user_property[0]->Email;
}
}
Thx for help

Undefined property while trying to connect to a laravel powered database

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).

Laravel 5 Auth change table columns

I changed some fields in users database table.
table name: users
primaryKey: user_id
username: user_username
password: user_password
e-mail: user_mail
in Illuminate\Foundation\AuthAuthenticatesUsers I added protected $username = 'user_username';
When I try login to my account, I see a blank page after I give my username and password. Debug is on but not working. What happened?
Auth::attempt(array(
'user_username' => 'pionas',
'user_password' => '12345',
));
In User model I added getAuthPassword and changed the column name to user_password. Log is clear.
Auth::loginUsingId(1); - not working
Probably all methods in Auth are not working.
My User model is:
<?php
namespace App\User;
use Illuminate\Auth\Authenticatable;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Auth\Passwords\CanResetPassword;
use Illuminate\Foundation\Auth\Access\Authorizable;
use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
use Illuminate\Contracts\Auth\Access\Authorizable as AuthorizableContract;
use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract;
class User extends Model implements AuthenticatableContract,
AuthorizableContract,
CanResetPasswordContract
{
use Authenticatable, Authorizable, CanResetPassword;
/**
* The database table used by the model.
*
* #var string
*/
protected $table = 'users';
protected $primaryKey = 'user_id';
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = ['user_username', 'user_mail', 'user_password', 'user_group_id', 'user_code', 'user_rang'];
/**
* The attributes excluded from the model's JSON form.
*
* #var array
*/
protected $hidden = array('user_password', 'remember_token');
/**
* Get the password for the user.
*
* #return string
*/
public function getAuthPassword()
{
return $this->user_password;
}
public function comment()
{
return $this->hasOne('UserField', 'user_id');
}
/**
You seem to have stripped some of the required traits that Laravel 5.1 uses. Here is an updated User model with those traits restored:
<?php
namespace App;
use Illuminate\Auth\Authenticatable;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Auth\Passwords\CanResetPassword;
use Illuminate\Foundation\Auth\Access\Authorizable;
use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
use Illuminate\Contracts\Auth\Access\Authorizable as AuthorizableContract;
use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract;
class User extends Model implements AuthenticatableContract,
AuthorizableContract,
CanResetPasswordContract
{
use Authenticatable, Authorizable, CanResetPassword;
/**
* The database table used by the model.
*
* #var string
*/
protected $table = 'users';
protected $primaryKey = 'user_id';
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = ['user_username', 'user_mail', 'user_password', 'user_group_id', 'user_code', 'user_rang'];
/**
* The attributes excluded from the model's JSON form.
*
* #var array
*/
protected $hidden = array('user_password', 'remember_token');
/**
* Get the unique identifier for the user.
*
* #return mixed
*/
public function getAuthIdentifier()
{
return $this->getKey();
}
/**
* Get the token value for the "remember me" session.
*
* #return string
*/
public function getRememberToken()
{
return $this->remember_token;
}
/**
* Set the token value for the "remember me" session.
*
* #param string $value
* #return void
*/
public function setRememberToken($value)
{
$this->remember_token = $value;
}
/**
* Get the column name for the "remember me" token.
*
* #return string
*/
public function getRememberTokenName()
{
return 'remember_token';
}
/**
* Get the e-mail address where password reminders are sent.
*
* #return string
*/
public function getReminderEmail()
{
return $this->user_mail;
}
/**
* Get the password for the user.
*
* #return string
*/
public function getAuthPassword()
{
return $this->user_password;
}
public function comment()
{
return $this->hasOne('UserField', 'user_id');
}
/**
* Scope a query to only include users of a given type.
*
* #return \Illuminate\Database\Eloquent\Builder
*/
public function scopeOfStatus($query, $type)
{
return $query->where('user_status', $type);
}
}
You will need to do two things.
On your model, add the method getAuthPassword() (you already do that)
public function getAuthPassword()
{
return $this->user_password;
}
On your AuthController, when passing the $credentials to the $this->auth->validate() method (or the Auth::attemp() or anything else), you must set the array with a key to check for the password, and this key SHOULD be named as "password". All others keys can have any name, and you will use the name of your username column
$credentials['user_username'] = $request->input('user_username');
$credentials['password'] = $request->input('user_password');
Auth::attempt($credentials);

Categories