Trying to get property of non-object. Error in laravel - laravel

I'm kinda new at laravel and need your help.
I have this IR model :
class IR extends Model
{
//
protected $fillable=['irnum','date','subject','cause','facts','as','at','rec','user_id'];
protected $casts=['user_id'=>'int'];
public function user()
{
return $this->belongsTo(user::class);
}
public static $rules =array (
'date'=>'required',
'status'=>'required|min:10',
'cause' => 'required|min:10',
'facts' => 'required|min:10',
'ir-as' => 'required|min:10',
'rec' => 'required|min:10',
'ir-at' => 'required|min:10',
);
}
and route:
Route::group(['middleware' => ['web']], function () {
Route::get('/', function () {
return view('welcome');
})->middleware('guest');
Route::resource('tasks','TaskController');
Route::get('ir',function ()
{
return View::make('tasks/ir');
});
Route::resource('irs','IRController');
Route::auth();
});
and this is my controller :
class IRController extends Controller
{
/**
* The task repository instance.
*
* #var TaskRepository
*/
protected $irs;
/**
* Create a new controller instance.
*
* #param TaskRepository $tasks
* #return void
*/
public function __construct(IRRepository $irs)
{
$this->middleware('auth');
$this->irs = $irs;
}
/**
* Display a list of all of the user's task.
*
* #param Request $request
* #return Response
*/
public function index(Request $request)
{
return view('tasks.ir',[
'irs' => $this->irs->forUser($request->user()),
]);
}
/**
* Create a new task.
*
* #param Request $request
* #return Response
*/
public function create()
{
return View::make('irs.create');
}
public function store(Request $request)
{
$request->user_id=Auth::user()->id;
$input =$request->all();
$validation=Validator::make($input, IR::$rules);
if($validation->passes())
{
IR::create($input);
return Redirect::route('tasks.ir');
}
return Redirect::route('tasks.ir')
->withInput()
->withErrors($validation)
->with('message','There were validation errors.');
}
/**
* Destroy the given task.
*
* #param Request $request
* #param Task $task
* #return Response
*/
public function destroy(Request $request, IR $irs)
{
}
}
I really dont know what causes to throw this error.
Error throws when i add Incident report.
Pls help.
New at laravel

You're saying you get an error when you're trying to add an incident report or IR, so I assume problem is in a store() action.
I can see only one potential candidate for this error in a store() action:
Auth::user()->id;
Add dd(Auth::user()); before this clause and if it will output null, use check() method, which checks if any user is authenticated:
if (Auth::check()) {
Auth::user->id;
}

Related

Laravel separate functions to service class

I am refactoring my application according to this article:
https://laravel-news.com/controller-refactor
I had all logic in my controllers so it seems like a good idea to do this. But now I have some struggles with the update function.
class CategoryController extends Controller
{
/**
* Display a listing of the resource.
*
* #param Request $request
* #return JsonResponse
*/
public function index(Request $request): JsonResponse
{
$categories = Category::where('created_by', $request->company->id)->orderBy('order')->get();
return response()->json($categories);
}
/**
* Store a newly created category
*
* #param StoreCategoryRequest $request
* #param CategoryService $categoryService
* #return JsonResponse
*/
public function create(StoreCategoryRequest $request, CategoryService $categoryService): JsonResponse
{
$category = $categoryService->createCategory($request);
if ($category) {
return response()->json(['success' => true, 'message' => 'api.category.save.success']);
}
return response()->json(['success' => false, 'message' => 'api.category.save.failed']);
}
/**
* Update the specified resource in storage.
*
* #param StoreCategoryRequest $request
* #param Category $category
* #param CategoryService $categoryService
* #return JsonResponse
*/
public function update(StoreCategoryRequest $request, Category $category, CategoryService $categoryService): JsonResponse
{
try {
$result = $categoryService->updateCategory($request, $category);
if ($result) {
return response()->json(['success' => true, 'message' => 'api.category.update.success']);
}
return response()->json(['success' => false, 'message' => 'api.category.update.failed']);
} catch (\Exception $e) {
return response()->json(['success' => false, 'message' => 'api.category.update.failed']);
}
}
}
And the route:
Route::put('category/{category}', [CategoryController::class, 'update']);
Laravel is getting the category based on the id, but I don't know how to handle this correctly in my controller. I autoload the CategoryService there, so that I can use the update function. After that I give the actual category as a property to that service, I also don't know if handling the exceptions like this is the 'best way'.
class CategoryService
{
public function createCategory(Request $request): bool {
$category = new Category();
$category->fill($request->all());
$category->created_by = $request->company->id;
return $category->save();
}
/**
* #throws \Exception
*/
public function updateCategory(Request $request, Category $category): bool {
if($this->isOwnerOfCategory($category, $request->company)) {
$category->fill($request->all());
$category->created_by = $request->company->id;
return $category->save();
}
throw new \Exception('Not the owner of the category');
}
private function isOwnerOfCategory(Category $category, Company $company): bool
{
return $category->created_by === $company->id;
}
}
The create function/ flow feels good. But the update function feels like properties are coming from everywhere and the code is a lot less readable. Are there any suggestions to improve this?

Listeners and Events get error: Too few arguments to function App\Events\User\Created::__construct(),

I need have two Listeners in same event, and when an user has been created in the system, Lavarel send my an email with the credentials and another to assign roles of users. It's possible have two listeners in same event? Why does the system show me this message?
When I create an user the system show me:
Too few arguments to function App\Events\User\Created::__construct(), 1 passed in C:\xampp\htdocs\bwm\vendor\laravel\framework\src\Illuminate\Database\Eloquent\Concerns\HasEvents.php on line 205 and exactly 2 expected
This is my Event:
class UserCreated
{
use Dispatchable, InteractsWithSockets, SerializesModels;
public $user;
public $password;
/**
* Create a new event instance.
*
* #return void
*/
public function __construct($user,$password)
{
$this->user = $user;
$this->password = $password;
}
/**
* Get the channels the event should broadcast on.
*
* #return \Illuminate\Broadcasting\Channel|array
*/
public function broadcastOn()
{
return new PrivateChannel('channel-name');
}
}
This is my Listener Assign Roles:
class AssignRoles
{
private $request;
/**
* Create the event listener.
*
* #return void
*/
public function __construct(Request $request)
{
$this->request = $request;
}
/**
* Handle the event.
*
* #param Created $event
* #return void
*/
public function handle(UserCreated $event)
{
$event->user;
switch($role = $this->request->role)
{
case $role == 'Asesor':
$event->user->assignRole('Asesor');
$asesoria = Asesoria::orderby('created_at', 'desc')->first();
$asesoria->user_id = $event->user->id;
$asesoria->published = true;
$asesoria->update();
break;
case $role == 'Comprador':
$event->user->assignRole('Comprador');
break;
default:
$event->user->assignRole('Writer');
}
}
}
This is my Listener Send Login Credentials:
class SendLoginCredentials
{
/**
* Create the event listener.
*
* #return void
*/
public function __construct()
{
//
}
/**
* Handle the event.
*
* #param Created $event
* #return void
*/
public function handle(UserCreated $event)
{
Mail::to($event->user)->queue(
new LoginCredentials($event->user, $event->password)
);
}
}
In my function store of my UsersController I call to dispach:
UserCreated::dispatch($user, $password);
In my EventServiceProvider I have this:
protected $listen = [
Registered::class => [
SendEmailVerificationNotification::class,
],
'App\Events\User\UserCreated' => [
'App\Listeners\User\AssignRoles',
'App\Listeners\SendLoginCredentials',
],
];
You have two parameters in your constructor of UserCreated class and you are passing only one because you are dispatching it wrong way.
you can do it several ways:
Event::dispatch(new UserCreated($user, $password))
event(new UserCreated($user, $password))
Try these. Hope it works
I had a protected $dispachesEvents in User Model:
protected $dispatchesEvents = ['created' => 'App\Events\User\Created'];
That's why I got the error:
Too few arguments to function App\Events\User\Created::__construct(), 1 passed in C:\xampp\htdocs\bwm\vendor\laravel\framework\src\Illuminate\Database\Eloquent\Concerns\HasEvents.php on line 205 and exactly 2 expected
I deleted it, and put the call to the dispacher in my RegisterController.
protected function create(array $data)
{
$user = User::create([
'name' => $data['name'],
'email' => $data['email'],
//'password' => Hash::make($data['password']), //mutador en User model
'password' => $data['password'],
'surname1' => $data['surname1'],
'surname2' => $data['surname2'],
'comunidad_id' => $data['cbx_comunidad'],
'provincia_id' => $data['cbx_provincia'],
'municipio_id' => $data['cbx_municipio'],
]);
//dd($data['password']);
event(new Created($user,$data['password']));
return $user;
}
As I had a protected $dispatchesEvents in User Model,this it executes before that my call in the RegisterController.

Declaration of App\Http\Requests\UserUpdateRequest::user() should be compatible with Illuminate\Http\Request::user($guard = NULL)

I am trying to back and implement FormRequest objects for validation. I have successfully setup the form requests for all of my models except for the User model. I am getting the following error Declaration of App\Http\Requests\UserUpdateRequest::user() should be compatible with Illuminate\Http\Request::user($guard = NULL). Researching this error it seems like it may be an issue with the way that I'm handling the authorization through Policies. Note that the UserStoreRequest works but the UserUpdateRequest returns the error.
UserStoreRequest
<?php
namespace App\Http\Requests;
use App\User;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Support\Facades\Gate;
class UserStoreRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* #return bool
*/
public function authorize()
{
// Authorize action - create-user
return Gate::allows('create', User::class);
}
/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public function rules()
{
return [
'name' => 'required|string',
'email' => 'required|email|unique:users',
'password' => 'required|string|min:8|confirmed',
'markets' => 'required|array',
'roles' => 'required|array',
];
}
/**
* Save the user.
*
* #return \App\User
*/
public function save()
{
// Create the user
$user = new User($this->validated());
// Set the password
$user->password = Hash::make($this->validated()['password']);
$user->setRememberToken(Str::random(60));
// Save the user
$user->save();
// Set users markets
$user->markets()->sync($this->validated()['markets']);
// Update the users role if included in the request
if ($this->validated()['roles']) {
foreach ($this->validated()['roles'] as $role) {
$user->roles()->sync($role);
if ($user->hasRole('admin')) {
$user->markets()->sync(Market::all());
}
}
}
return $user;
}
/**
* Get the error messages for the defined validation rules.
*
* #return array
*/
public function messages()
{
return [
'name.required' => 'The name is required.',
'email.required' => 'The email is required.',
'email.unique' => 'The email must be unique.',
'password.required' => 'The password is required.',
'password.confirmed' => 'The passwords do not match.',
'password.min' => 'The password must be at least 8 characters.',
'markets.required' => 'A market is required.',
'roles.required' => 'A role is required.',
];
}
}
UserUpdateRequest
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Support\Facades\Gate;
class UserUpdateRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* #return bool
*/
public function authorize()
{
// Authorize action - update-user
return Gate::allows('update', $this->user);
}
/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public function rules()
{
return [
'name' => 'required|string',
];
}
/**
* Get the user from the route.
*
* #return \App\User
*/
public function user()
{
return $this->route('user');
}
/**
* Save the email role.
*
* #return \App\Role
*/
public function save()
{
// Update the user
$this->user->update($this->validated());
// // Check to see if password is being updated
// if ($this->validated()['password']) {
// $this->user->password = Hash::make($this->validated()['password']);
// $this->user->setRememberToken(Str::random(60));
// }
// // Set users markets
// $this->user->markets()->sync($this->validated()['markets']);
// // Set users roles
// // // Update the users role if included in the request
// if ($this->validated()['roles']) {
// foreach ($this->validated()['roles'] as $role) {
// $this->user->roles()->sync($role);
// if ($this->user->hasRole('admin')) {
// $this->user->markets()->sync(Market::all());
// }
// }
// }
// // Save the user
// $this->user->save();
return $this->user;
}
/**
* Get the error messages for the defined validation rules.
*
* #return array
*/
public function messages()
{
return [
'name.required' => 'The name is required.',
'email.required' => 'The email is required.',
'email.unique' => 'The email must be unique.',
'markets.required' => 'A market is required.',
'roles.required' => 'A role is required.',
];
}
}
As you can see I have commented out most of the code for the UpdateRequest for troubleshooting. It seems that the issue is with the authorize() method. Below is the code from the UserPolicy
UserPolicy
/**
* Determine whether the user can create models.
*
* #param \App\User $user
*
* #return mixed
*/
public function create(User $user)
{
return $user->hasPermission('create-user');
}
/**
* Determine whether the user can update the model.
*
* #param \App\User $user
* #param \App\User $model
*
* #return mixed
*/
public function update(User $user, User $model)
{
return $user->hasPermission('update-user');
}
UserController
/**
* Store a newly created resource in storage.
*
* #param \Illuminate\Http\UserStoreRequest $request
*
* #return \Illuminate\Http\Response
*/
public function store(UserStoreRequest $request)
{
return redirect($request->save()->path());
}
/**
* Update the specified resource in storage.
*
* #param \Illuminate\Http\UserUpdateRequest $request
* #param \App\User $user
*
* #return \Illuminate\Http\Response
*/
public function update(UserUpdateRequest $request, User $user)
{
return redirect($request->save()->path());
}
I'm using a permission based authorization for this system. The user has the hasPermission() method on it to verify if the user has the required permission to perform the action. I fear that I've confused myself on this setup and that I am not validating correctly. Everything has worked up until trying to implement this on the User model.
hasPermission()
/**
* Check to see if the model has a permission assigned.
*
* #param string $permission
*
* #return bool
*/
public function hasPermission($permission)
{
if (is_string($permission)) {
if (is_null(Permission::whereName($permission)->first())) {
return false;
} else {
return $this->hasRole(Permission::where('name', $permission)->first()->roles);
}
}
return $this->hasRole($permission->roles);
}
hasRole()
/**
* Check to see if model has a role assigned.
*
* #param string $role
*
* #return bool
*/
public function hasRole($role)
{
if (is_string($role)) {
return $this->roles->contains('name', $role);
}
return (bool) $role->intersect($this->roles)->count();
}
Update
I have tried renaming the user() method in UserUpdateRequest to frank() to resolve any issues overriding the Request user. This clears up the error listed above, but then the response is returned unauthorized. The logged in user has permissions set to allow updating users. This is called in the authorize() method using Gate::allows. I'm just not sure if it's checking the logged in user or the model user.
I investigated further and found that there is a new error after changing the method to frank(). I am getting Call to a member function update() on null. I should be returning the user pulled from the route from the frank method but it seems to be returning null.
Updated UserUpdateRequest
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Support\Facades\Gate;
class UserUpdateRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* #return bool
*/
public function authorize()
{
// Authorize action - update-user
return Gate::allows('update', $this->frank);
}
/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public function rules()
{
return [
'name' => 'required|string',
];
}
/**
* Get the user from the route.
*
* #return \App\User
*/
public function frank()
{
return $this->route('user');
}
/**
* Save the email role.
*
* #return \App\Role
*/
public function save()
{
// Update the user
$this->frank->update($this->validated());
// // Check to see if password is being updated
// if ($this->validated()['password']) {
// $this->user->password = Hash::make($this->validated()['password']);
// $this->user->setRememberToken(Str::random(60));
// }
// // Set users markets
// $this->user->markets()->sync($this->validated()['markets']);
// // Set users roles
// // // Update the users role if included in the request
// if ($this->validated()['roles']) {
// foreach ($this->validated()['roles'] as $role) {
// $this->user->roles()->sync($role);
// if ($this->user->hasRole('admin')) {
// $this->user->markets()->sync(Market::all());
// }
// }
// }
// // Save the user
// $this->user->save();
return $this->frank;
}
/**
* Get the error messages for the defined validation rules.
*
* #return array
*/
public function messages()
{
return [
'name.required' => 'The name is required.',
'email.required' => 'The email is required.',
'email.unique' => 'The email must be unique.',
'markets.required' => 'A market is required.',
'roles.required' => 'A role is required.',
];
}
}
The issue is the user() method you defined on your UserUpdateRequest class.
UserUpdateRequest extends Illuminate\Foundation\Http\FormRequest, which in turn extends Illuminate\Http\Request. Illuminate\Http\Request already has a user() method defined, so the user() method in your UserUpdateRequest class is attempting to override this definition.
Since your UserUpdateRequest::user() method doesn't match the Illuminate\Http\Request::user($guard = null) signature, you're getting that error.
You can either:
Remove the user() method from your UserUpdateRequest class, or
Rename your user() method on your UserUpdateRequest class, or
Add the $guard = null parameter to your user() method on your UserUpdateRequest class, so that it matches the signature of the base user() method.

Custom PUT route with FormRequest in Laravel

I want to make a custom PUT route to manage AJAX request
Route::post('some/{id}/another/new', 'SomeController#store');
Route::put('some/{cid}/another/{id}/edit', 'SomeController#update');
and I want to use FormRequest as a request parameter
/**
* Store a newly created resource in storage.
*
* #param \Illuminate\Http\Request $request
* #return \Illuminate\Http\Response
*/
public function store(DirectionRequest $request)
{
$data = $request->validated();
$direction = Direction::create($data);
return response()->json($direction, 201);
}
/**
* Update the specified resource in storage.
*
* #param \Illuminate\Http\Request $request
* #param \App\Direction $direction
* #return \Illuminate\Http\Response
*/
public function update(DirectionRequest $request, $clientId, $directionId )
{
$data = $request->validated();
$direction = Direction::find($directionId);
$direction->update($data);
return response()->json($direction, 201);
}
DirectionRequest.php
<?php
namespace App\Http\Requests;
use Illuminate\Contracts\Validation\Validator;
use Illuminate\Http\Exceptions\HttpResponseException;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
class DirectionRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* #return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public function rules()
{
return [
'country' => 'required|string|max:255'
];
}
/**
*
* #return type
*/
public function all($keys = null) {
$data = parent::all();
$data['created_by'] = Auth::User()->id;
return $data;
}
/**
*
* #param Validator $validator
* #throws HttpResponseException
*/
protected function failedValidation(Validator $validator) {
throw new HttpResponseException(response()->json($validator->errors(), 422));
}
}
and AJAX call
const editData = new FormData();
editData.append("country", document.getElementById('country').value);
return fetch(`/some/` + sidId + `/another/` + id + `/edit`, {
method: "PUT",
body: editData,
headers: new Headers({
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
})
})
.then(response => {
if (!response.ok) {
throw new Error(response.statusText)
}
return response.json()
})
.catch(error => {
console.log(error)
});
And I get 422 Unprocessible Entity error which return all my model fields with errrors, but they are filled and sended by the AJAX request.
How to use FormRequest in custom route to use validation rules from it? I dont want to copy code with rules because I use that FormRequest in another method (store) and there it works
Simple Request shows put data, but FormRequest doesn't
After follow #RossWilson link
laracast.com I've change my request type to POST and then I could validate inputs with FormRequest rules and other stuff from it

Unable to overwrite authorized method in policy

I want to respond with a custom message when authorization fails.
I've overwritten the method in the Policy class but it does not return the custom message.
Policy:
class PostPolicy
{
use HandlesAuthorization;
/**
* Determine if user can view post
* #param User $user
* #param Post $post
* #return bool
*/
public function view(User $user, Post $post)
{
return $user
->posts()
->where('post_id', $post->id)
->exists();
}
/**
* [deny description]
* #return [type] [description]
*/
protected function deny()
{
return response()->json([
'message' => 'My custom unauthorized message'
], 401);
}
}
Implementing in PostController:
...
public function show(Post $post)
{
$this->authorize('view', $post);
...
}
The response still returns whats defined in the HandlesAuthorization trait, i.e.:
protected function deny($message = 'This action is unauthorized.')
{
throw new AuthorizationException($message);
}
You can simply add this code inside the AuthorizationException.php
/**
* Render the exception into an HTTP response.
* #param \Illuminate\Http\Request $request
* #return \Illuminate\Http\Response
*/
public function render(Request $request)
{
if ($request->is('api/*')) {
$response = [
'message' => $this->message,
'status' => 403,
];
return response()->json($response, 403);
}
}

Resources