auth()->user()->pUserId makes Attempt to read property "pUserId" on null - laravel

I have a problem where i can't get the pUserId from database when using authentication
Here's the controller(Home Controller):
function index(){
$id = Auth::user()->pUserId; //Here's the main problem
$profiles = profiles::where('pUserId',$id)->first();
return view('home', compact('profiles'));
// return view('home');
}
auth.php(config):
'providers' => [
'users' => [
'driver' => 'eloquent',
'model' => App\Models\User::class,
],
]
User.php(model)(default by laravel):
class User extends Authenticatable
{
use HasApiTokens, HasFactory, Notifiable;
protected $table = 'profiles';
protected $guarded = [''];
I've already tried without using controller and straight to .blade.php and the error is still the same
#auth
<div class="header-control">
{{ auth()->user()->pUserId }} //main problem
</div>
#endauth
The Error Display
Here's the route:
Route::get('/home', 'HomeController#index');
Route::get('/', 'LoginController#index')->middleware('guest');
Route::get('/login', 'LoginController#index')->middleware('guest');
Route::post('/login/authenticate', 'LoginController#authenticate')->middleware('guest');
Login Controller:
function authenticate(Request $request)
{
$login = $request->validate([
'pUserId' => 'required',
'password' => 'required'
]);
if(Auth::attempt($login))
{
$request->session()->regenerate();
return redirect()->intended('/home');
}
else
{
return back()->with('error', 'Wrong Login Details');
}
}
There's a several pUserId in profiles tables, but just said "property "pUserId" on null" when using
auth()->user()->pUserId or
$id = Auth::user()->pUserId;
Auth:attempt($login) is successfully working, i just don't understand it doesn't work in Home Controller
migrations:
public function up()
{
Schema::create('profiles', function (Blueprint $table) {
$table->string('pUserId',5)->primary();
$table->string('pNamaLengkap', 255);
$table->enum('pJobDescription', ['Full Stack Developer','Backend Developer','Frontend Developer']);
$table->enum('pUnitKerja', ['Talent Management','Company Management','Customer Management']);
$table->enum('pDirectorate',['Human Resources','Company Profile','Stabilitas Sistem Keuangan','Sistem Pengelolaan','Pendukung Kebijakan']);
$table->string('password', 255);
$table->timestamps();
});
}
DB profiles

In your user model, specify the primary key if you don't use id as the primary key:
protected $primaryKey = 'pUserId';

Related

PhpUnit - Expected Status 200 But Received 500

I have users table with hasMany educational backgrounds & educational awards. Then that educational backgrounds hasMany educational awards
Here's my Testcase when user uploads image my endpoint receives it
public function testuploadUsersImageEducationalAwards()
{
Storage::fake('public');
$photo = UploadedFile::fake()->create('photo.png')->size(25000);
$data = [
'photo' => $photo,
'award' => $this->faker->word,
'educational_background_id' => EducationalBackground::factory()->create()->id
];
$this->withoutExceptionHandling();
$response = $this->sendPostRequestToEndpoint($data, 200);
$data['file_name'] = $response['file_name'];
unset($data['photo']);
$response->assertJson($data)
->assertJsonStructure([
'id',
'award',
'photo',
'educational_background_id',
'created_at',
'updated_at',
]);
$this->assertDatabaseHas('users.educational_awards', $data);
}
Here's my endpoint with assert status 200
private function sendPostRequestToEndpoint(array $data, $status)
{
return $this->json("POST", '/api/users/educational-award/upload-picture', $data)->assertStatus($status);
}
UPDATE
Here's my EducationalBackgroundFactory
class EducationalBackgroundFactory extends Factory
{
protected $model = EducationalBackground::class;
public function definition()
{
return [
'user_id' => User::factory()->create()->id,
'studies_type' => $this->faker->randomElement([EducationalBackground::BASIC, EducationalBackground::SECONDARY, EducationalBackground::UNDERGRADUATE, EducationalBackground::GRADUATESCHOOL]),
'year' => Carbon::now()->format("Y"),
'course' => $this->faker->word,
];
}
}
Here's my EducationalBackground model
class EducationalBackground extends Model
{
use HasFactory;
const BASIC = "basic";
const SECONDARY = "secondary";
const UNDERGRADUATE = "undergrad";
const GRADUATESCHOOL = "grad";
protected $table = 'users.educational_backgrounds';
protected $fillable = [
'user_id',
'studies_type',
'year',
'course',
];
public function user()
{
return $this->belongsTo('App\Models\User', 'user_id');
}
public function educationalAwards()
{
return $this->hasMany("App\Models\Users\EducationalAward", "educational_background_id");
}
}
Here's my migration
public function up()
{
Schema::create('users.educational_backgrounds', function(Blueprint $table) {
$table->bigIncrements('id');
$table->integer('user_id')->unsigned();
$table->foreign('user_id')->references('id')->on('users');
$table->enum('studies_type', ['basic', 'secondary', 'undergrad', 'grad']);
$table->integer('year');
$table->string('course')->nullable();
$table->timestamps();
});
}
Here's my controller code
public function uploadUsersImageEducationalAwards(UserImageRequest $request, EducationalBackground $educational_background)
{
$uploaded_image = $request->photo->store('users/educational_awards');
$file_type = $request->photo->getClientOriginalExtension();
$file = EducationalAward::create([
'educational_background_id' => $educational_background->id,
'award' => $request->award,
'photo' => $uploaded_image,
]);
return response()->json($file, 200);
}
But this gives me 500 status which i found a way to log error in details. Here's an image for more clarity
remove unset function before sending response.

Laravel Roles and Permissions based on Role specific Ability

I have a project in which I want a Specific page to be viewed by a specific user which have a role of viewing for example I have User 1 that has an Admin Role and the Admin Role has the Ability to View this page in my design I made 3 models Users, Roles, and Abilities
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.
*
* #var array
*/
protected $fillable = [
'name', 'email', 'password','district','area','committee','position',
];
/**
* 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',
];
public function answer()
{
return $this->hasMany('App\Answer');
}
public function roles()
{
return $this->belongsToMany('App\Role');
}
public function hasRole($role)
{
if ($this->roles()->where('name', $role)->first()) {
return true;
}
return false;
}
public function assignRole($role)
{
$this->roles()->save($role);
}
}
Role Model:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Role extends Model
{
protected $fillable = ['name'];
public function abilities()
{
return $this->belongsToMany('App\Ability');
}
public function hasAbility($ability)
{
if ($this->abilities()->where('name', $ability)->first()) {
return true;
}
return false;
}
public function assignAbility($ability)
{
$this->abilities()->save($ability);
}
public function users()
{
return $this->belongsToMany('App\User');
}
}
Ability Model:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Ability extends Model
{
protected $fillable = ['name'];
public function roles()
{
return $this->belongsToMany('App\Role');
}
}
This is my UserPolicy:
<?php
namespace App\Policies;
use App\User;
use App\Role;
use Illuminate\Auth\Access\HandlesAuthorization;
class UserPolicy
{
use HandlesAuthorization;
public function view (Role $role)
{
return $role->hasAbility('view');
}
public function manage (User $user)
{
return true;
}
public function edit (User $user)
{
return true;
}
public function update (User $user)
{
return true;
}
public function add (User $user)
{
return true;
}
}
And the Controller of The Policy
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;
use App\User;
use App\Role;
class MemberController extends Controller
{
public function index(Role $role)
{
$this->authorize('view', $role);
return view ('members.create')->with('users', User::all());
}
public function manage(User $user)
{
$this->authorize('manage', $user);
return view ('members.manage')->with('users', User::all());
}
public function edit(User $user)
{
$this->authorize('edit', $user);
return view ('members.edit')->with('user', User::all())->with('roles', Role::all());
}
public function update(Request $request, User $user)
{
$this->authorize('update', $user);
$user->roles()->sync($request->roles);
return redirect('/members/edit');
}
public function store(User $user)
{
$this->authorize('add', $user);
$this->validate(request(), [
'name' => ['required', 'string', 'max:255'],
'district' => ['required', 'string', 'max:255'],
'area' => ['required', 'string', 'max:255'],
'committee' => ['required', 'string', 'max:255'],
'position' => ['required', 'string', 'max:255'],
'email' => ['required', 'string', 'email', 'max:255', 'unique:users'],
'password' => ['required', 'string', 'min:8', 'confirmed'],
]);
$data = request()->all();
$member = new User();
$member->name = $data['name'];
$member->district = $data['district'];
$member->area = $data['area'];
$member->committee = $data['committee'];
$member->position = $data['position'];
$member->email = $data['email'];
$member->password = Hash::make($data['password']);
$member->save();
return redirect('/members/create');
}
}
The index function should be the one related to the function view in the UserPolicy
and this is the can located in my blade.php file
#can('view', \App\Role::class)
<li class="">
<a class="" href="/members/create">
<span><i class="fa fa-user-plus" aria-hidden="true"></i></span>
<span>Add Member</span>
</a>
</li>
#endcan
in the policy when I link it to the name of the role of the logged in user everything works just fine but if I want to link it to an ability of the role it doesn't work so any idea on how the View Function in the UserPolicy should be implemented ?
The first parameter that is passed to the policy is the authenticated User, not its Role. I don't think it works. Maybe if you reimplement using an EXISTS query.
public function view (User $user)
{
return $user->roles()->whereHas('abilities', function ($ability) {
$ability->where('name', 'view');
})
->exists();
}
->exists() turns the query into an EXISTS query, which will return a boolean value if the query finds anything without having to return any rows.
https://laravel.com/docs/7.x/queries#aggregates
You could put that logic into an User method.
# User model
public function hasAbility($ability): bool
{
return $this->roles()->whereHas('abilities', function ($ability) {
$ability->where('name', 'view');
})
->exists();
}
public function view (User $user)
{
return $user->hasAbility('view');
}

How do I pass the value of a primary to the foreign key and then use it to display information from the database?

I want the contacts to be displayed specifically according to the group. The groups in turn are being displayed according to the logged in user. However, all the contacts for the user are being displayed in every group that the user creates.It works when the value is being hardcoded but I want the value to be assigned dynamically.How do I do that?
This is the group controller
class GroupController extends Controller {
public function index()
{
$groups = Group::where('user_id',Auth::user()->id)->get();
return view('groups.index', compact('groups'));
}
public function store(Request $request)
{
$group = $request->all();
$request->validate([
'group_name'=>'required',
]);
$group = new Group([
'group_name' => $request->get('group_name'),
'user_id' => Auth::user()->id,
]);
$group->save();
return redirect('/groups');
}}
This is the contact controller
class ContactController extends Controller{
public function index(Request $request)
{
$group_id=$request->query('id');
$contacts = Contact::where('user_id',Auth::user()->id)->where('group_id','=','id')->get();
return view('contacts.index', compact('contacts'));
}
public function store(Request $request)
{
$contact = $request->all();
$request->validate([
'contact_name'=>'required',
'contact_number'=> 'required|integer',
'contact_email' => 'required'
]);
$contact = new Contact([
'contact_name' => $request->get('contact_name'),
'contact_number'=> $request->get('contact_number'),
'contact_email'=> $request->get('contact_email'),
'user_id' => Auth::user()->id,
'group_id'=> $request->query('id'),
]);
$contact->save();
return redirect('/contacts');
}}
This is the migration for contacts.
class CreateContactsTable extends Migration{
public function up()
{
Schema::create('contacts', function (Blueprint $table) {
$table->increments('id');
$table->integer('user_id')->unsigned();
$table->integer('group_id')->unsigned();
$table->string('contact_name');
//$table->string('contact_number');
$table->string('contact_email');
$table->string('contact_number')->nullable();
$table->timestamps();
});
Schema::table('contacts', function($table) {
$table->foreign('user_id')->references('id')->on('users');
$table->foreign('group_id')->references('id')->on('groups');
});}

Laravel 5.4 Eloquent not Saving certain fields

I have been working on logging all user activities in Model events... But for some reason, the records are stored in the user_action table but the action_model field. This is my code.
User Action Class
`
class UserAction extends Model
{
use SoftDeletes;
protected $table = 'user_actions';
/**
*
*/
protected $fillable = [
'user_id','action', ' action_model', 'action_id'
];
public function user()
{
return $this->belongsTo(User::class, 'user_id');
}
}
`
UserActionObervable
class UserActionObserver
{
public function saved($model)
{
$type = $model->getTable();
// dd($type); when dump the value exists
if ($model->wasRecentlyCreated == true) {
// Data was just created
$action = 'created';
} else {
// Data was updated
$action = 'updated';
}
if (Sentinel::check()) {
UserAction::create([
'user_id' => Sentinel::getUser()->id,
'action' => $action,
'action_model' => 'model', //I tried to pass in constant
'action_id' => $model->id
]);
}
}
public function deleting($model)
{
if (Sentinel::check()) {
UserAction::create([
'user_id' => Sentinel::getUser()->id,
'action' => 'deleted',
'action_model' => $model->getTable(),
'action_id' => $model->id
]);
}
}
}
This is the schema
Schema::create('user_actions', function (Blueprint $table) {
$table->increments('id');
$table->integer('user_id')->unsigned()->nullable();
$table->string('action'); // created / updated / deleted
$table->string('action_model');
$table->integer('action_id')->nullable();
$table->timestamps();
$table->engine = 'InnoDB';
$table->foreign('user_id')->references('id')
->on('users')->onDelete('cascade');
});
protected $fillable = [
'user_id','action', ' action_model', 'action_id'
];
Try to remove the space before action_model. The field in $fillable doesn't match the key you're passing into the create() method.

Laravel Route Model Binding return id null on product deletion

I'm using laravel 5.1.28. Here I'm just trying to create a simple application that can add, delete, and edit products but I noticed that when using the binding model, the $product instance just return null. I'm going to explain next, but first here are the full codes (without blade):
In my route.php I have the following route for product:
Route::model('products', 'App\Product');
Route::group(array('prefix' => 'admin', 'middleware' => 'SentinelAdmin'), function ()
{
# Product Management admin backend
Route::group(array('prefix' => 'products'), function () {
Route::get('/', array('as' => 'products', 'uses' => 'ProductController#index'));
Route::get('create', 'ProductController#create');
Route::post('create', 'ProductController#store');
Route::get('{productId}/delete', array('as' => 'delete/product', 'uses' => 'ProductController#destroy'));
Route::get('{productId}/confirm-delete', array('as' => 'confirm-delete/product', 'uses' => 'ProductController#getModalDelete'));
Route::get('{productId}/restore', array('as' => 'restore/product', 'uses' => 'ProductController#getRestore'));
Route::get('{productId}', array('as' => 'products.show', 'uses' => 'ProductController#show'));
});
Route::resource('products', 'ProductController');
});
So, this is my simple database migration:
class CreateProductsTable extends Migration
{
public function up()
{
Schema::create('products', function (Blueprint $table) {
$table->increments('id');
$table->string('user_id');
$table->string('name');
$table->string('description')->nullable();
$table->string('category')->nullable();
$table->decimal('price')->nullable();
$table->integer('quantity')->nullable();
$table->tinyInteger('in_stock')->nullable(); //0 - no, 1 - yes
$table->string('photos')->default('default_product_photo.jpg')->nullable(); //add one first
$table->timestamps();
});
}
public function down()
{
Schema::table('products', function (Blueprint $table) {
});
}
}
In my Product.php model, I have this:
**class Product extends Model
{
protected $table = 'products';
protected $guarded = ['id'];
protected $fillable = [
'user_id',
'name',
'description',
'category',
'price',
'quantity',
'in_stock',
'photos',
];
}**
This are the 2 functions that I have in the ProductController.php
For the 1st FUNCTION getModalDelete below, it will find the product id, and display a confirmation box to delete the product. If confirmed button is clicked, the route delete/product/{id} will be called and the destroy method is then called the (2nd function). The 2nd function is matter:
class ProductController extends Controller
{
//1st FUNCTION
public function getModalDelete(Request $request, $id)
{
$product_id = Product::where('id', '=', $id)->firstOrFail();
$model = 'products'; ////testing s
$confirm_route = $error = null;
try {
$confirm_route = route('delete/product', ['id' => $product_id]);
return View('admin/layouts/modal_confirmation', compact('error', 'model', 'confirm_route'));
} catch (ProductNotFoundException $e) {
$error = trans('product/message.error.delete', compact('id'));
return View('admin/layouts/modal_confirmation', compact('error', 'model', 'confirm_route'));
}
}
//2nd FUNCTION
public function destroy(Product $product)
{
Product::destroy($product);
// $product->forceDelete(); //doesn't work either
//dd($product); //Weird that it returns null.
//$success = Lang::get('products/message.success.delete');
//return Redirect::route('admin.products.index')->with('success', $success);
}
}
But if I changed the parameter of the function from
public function destroy(Product $product)
{
}
to
public function destroy($id)
{
}
it works. But I just don't know why the parameter (Product $product) doesn't work here using route model binding. The $product just return null. but the $id returns a value.
Found out it was the issue on front end template:
Actually I tried changing from
Route::model('products', 'App\Product');
to
Route::model('product', 'App\Product');
before attempted to post this question and it did not work due to the issue of the frontend template that I'm using. So, the answers from #Mark Davidson changing the
Route::model('products', 'Product');
to
Route::model('product', 'Product');
and changing the parameter of
{productId}
to
{product}
works perfectly.
The route of deleting the product in the front end has some issue. I can delete the product using the URL browser but clicking on the delete button doesn't popup and I was unable to debug the value. Somehow, the button popup appear if I change the
Route::model('product', 'App\Product');
to
Route::model('products', 'App\Product');
but it returns the $product instance to null. Problem solved.

Resources