When sending update request controller receives null array in Laravel 5.6 - laravel-5

I'm getting existing data from the database and putting it into a form.
While sending a request for an update, it goes to the controller but receiving null in an array.
Here is the view:
Here is the user controller:
Here is the form that I want to update:

$user argument will be passed from router as a string not \App\User model, you need to change your controller method definition to:
public function update(Request $request, string $user) {}
And don't forget to change your argument definition from \App\User to string like
#param string $user

Related

Laravel middleware with a where function

I want a middleware on my website for: People can edit their own posts but others posts. I tried this:
I get all posts that have the same post->user_id and user_id
$matches = Post::where('user_id', auth()->user()->id);
This gives back an array of posts that match the condition
Now what I want is to check if you are on a post that matches this condition, if the post->user_id and user_id do not match abort.
This is what I have, but you still can get on posts where the condition is NOT met.
if (!$matches){
abort(403);
}
return $next($request);
Abort when the criteria is not met and return the request when it is met
Instead of using middleware why not use the Policy, and since you will edit a post you can also use the Form Request. I suggest you to use Form Request
then edit the authorize() and add the condition there.
Okay lets say you are using Route Model Binding
//route
Route::put('/post/{post}', ['PostController','update']);
//controller
public function update(Post $post, UpdatePostRequest $request) {...}
You can directly check if the user is the owner inside the authorize(). Assuming that you define the relationship between the post and user
// app\Models\User.php
public function posts() : HasMany {...}
// app\Models\Post.php
public function user() : BelongsTo {...}
//request
class UpdatePostRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* #return bool
*/
public function authorize()
{
//true if the Auth::user() own the post. otherwise false.
return $this->post->user()->is(Auth::user());
}
/**
* Get the validation rules that apply to the request.
*
* #return array<string, mixed>
*/
public function rules()
{
return [
// Your validation rules
];
}
It works if you will update the post but if just want to prevent the user from accessing the post they do not own. put this in your middleware.
if(! $request->post->user()->is(Auth::user())) {
abort(403);
}
return $next($request);
If you're inside a post, I guess you will get the Post ID inside your request as well. Something like http://127.0.0.1:5500/posts/1
Then you can get both Post and User ID. Use both values to determine whether the user has authorized the post or not.
Example:
Assume you have added the post ID URL Param as post_id
$match = Post::where('user_id', auth()->user()->id)->where('id', $request->route('post_id'));
if (!$match){
abort(403);
}
return $next($request);

How do I iterate into an object that I send with ajax to my controller in laravel?

I have this object:
[{cantidad:1,precio_unitario:3}{cantidad:5,precio_unitario:6}]
I need to send it to my laravel controller using post with axios.
axios.post("compras_listas/a",this.items).then(respuesta=>{
//reponse code here
})
I know the data is stored in a variable called $request, but I do not know how to access the data that axios is sending.
You can post from axios with data as an object whose key can be used to retrieve data in the controller from the $request object
//this.items = [{cantidad:1,precio_unitario:3}{cantidad:5,precio_unitario:6}]
axios.post("compras_listas/a",{payload: this.items}).then(respuesta=>{
//reponse code here
})
Then in the controller method you can access the data as
public function example(Request $request)
{
$payload = $request->input('payload');
//rest of the processing in the controller method
}

How to validate related objects request data from a parent controller in Laravel?

I'm using Laravel 8.x and have a one-to-one and one-to-many relationship with models as follows.
class ServiceProvider extends Model
{
use HasFactory;
protected $guarded = [];
public function contact() {
return $this->hasOne('App\Models\Contact');
}
public function services() {
return $this->hasMany('App\Models\Service');
}
}
I'm using a single form to get all the data. The problem is both Contact and Service has their own validation to be done. I can duplicate the validation in the ServiceProviderController. But it seems ugly and violate DRY. Is there a way to call the ContactController and ServiceController to do the validation and return the validation result to be accessed by the ServiceProviderController?
As I guess you are doing something like:
/**
* Store a new service provider.
*
* #param Request $request
* #return Response
*/
public function store(Request $request)
{
$validator = Validator::make($request->all(), [
'title' => 'required|unique:posts|max:255',
'body' => 'required',
]);
if ($validator->fails()) {
return redirect('services/create')
->withErrors($validator)
->withInput();
}
// Store The Service Provider...
}
If Yes, I would recommend using a form request validator to validate the request. So if the request is get passed your controller will be called. Also, you can use the same Request Validation rule for both controllers. you can read how to create and use one more here.
You can set up enumerator classes that will return validation rules for you, or even declare static properties on your model which will hold an array of validation rules, and which can be called like: ServiceProvider::$rules or something similar.
This way you will keep all your rules at one place. You can't explicitly call controllers whenever, they respond to routes.
When you get the validation rules, just use $request->validate() method and send the rules you gathered to it.

How to pass multiple string variables to a Laravel Gate

I have a “security” service which I want to gradually move over to a Laravel Gate, so I can benefit from the helper methods that Laravel provides within the rest of the APP.
I defined the gate as follows now:
Gate::define('denja', function($user, $module, $permission) {
// validation of access to $module and $permission goes here
});
This works fine when I do
$user->can('denja', ['accounting', 'invoice.create']);```
for instance, but I don’t see how in my routes, I can define the middleware to properly function...
Route::post( '/accounting/invoices', 'InvoiceController#create')
->middleware("can:denja,accounting,invoice.create");```
Passing these parameters seems to be impossible from the middleware - the page now always returns a 403...
Any thoughts on how I can pass these parameters correctly to the gate from the Middleware? I think it's in fact a problem with the parameters; even with a dd() in the defined gate, I'm getting the 403.
I know I’m a bit “abusing” the system, but since we have an existing service that basically expects a user, module and permission under that module, I just want to delegate to that service for now...
When you are using can middleware :
The first is the name of the action we wish to authorise and the later is the route parameter we wish to pass to the policy method or a Model class path. documentation
For example :
Route::put('/post/{postId}', function (Post $post) {
// The current user may update the post...
})->middleware('can:update,postId');
OR
Route::post('/post', function () {
// The current user may create posts...
})->middleware('can:create,App\Post');
In your case :
Route::post( '/accounting/invoices', 'InvoiceController#create')
->middleware("can:denja,accounting,invoice.create");
which is missing the basic parameter signatures as there is no route param with name accounting or invoice.create nor a class.
Solution :
Remove middleware from route declaration :
Route::post( '/accounting/invoices', 'InvoiceController#create');
You can use can() method in your controller :
public function create(Request $request){
// Initialize $model and $permissions
// as per your business logic
if(!$request->user()->can('denja', $module, $permission){
abort(403);
}
// continue your logic for authorised user
}
Even if above solution works, if you have more authorisation rules, its better to make a policy class.
I to had this same problem so I did some digging into the 'can' middleware (Which maps to Illuminate\Auth\Middleware\Authorize)
Once in the class we see the following code
/**
* Get the model to authorize.
*
* #param \Illuminate\Http\Request $request
* #param string $model
* #return \Illuminate\Database\Eloquent\Model|string
*/
protected function getModel($request, $model)
{
if ($this->isClassName($model)) {
return trim($model);
} else {
return $request->route($model, null) ?:
((preg_match("/^['\"](.*)['\"]$/", trim($model), $matches)) ? $matches[1] : null);
}
}
What this means is...
If our string passed in is a class name then return that class name
If it is not a class name then...
1) Try to get it from the route, then return the route param
2) Try to get the model from the string via the regex "/^['\"](.*)['\"]$/"
So now lets say we have the middleware call of
$this->middleware(sprintf("can:create,%s,%s", User::class, Role::SUPPORT));
This will not work because the Role::SUPPORT does not match the regex
To match it we simply need to place the Role::SUPPORT into quotes.
TAKE NOTE OF THE "'" around the second %s
$this->middleware(sprintf("can:create,%s,'%s'", User::class, Role::SUPPORT));
To answer your question specifically, quote your string
Route::post('/accounting/invoices', 'InvoiceController#create')
->middleware("can:'denja','accounting','invoice.create'");

Laravel 5 Pass Data from Middleware to Controller

My middleware is similar to Auth. It checks for a URL pattern (eg: /rest/*), and then looks for token in the request, retrieves its corresponding user from database. After that, I want to save that user in a variable so that I can get back to it later in any of the following controller. What's the best way?
Middleware:
public function handle($request, Closure $next)
{
$token = Input::get("token");
// get user data from database
$user = User::get_user_from_token($token);
// ?? -> How to pass $user to controller, so that ..
return $next($request);
}
In Controller:
public function profile_save() {
// I get the user back here without querying again
$user = ???
}
I would flash the data to the session. When you flash data it only stays there until the next request.
In your middleware add
Session::flash('user', $user);
Don't forget to add this at the top of your middle ware
use Session;
Then whenever you need to access your user use
Session::get('user');
Here is a link to the docs for reference
http://laravel.com/docs/5.0/session#flash-data
I'm using Laravel 5.1.
To pass parameters from the middleware to the controller you can add it to the Request object.
In the middleware:
public function handle($request, Closure $next)
{
$user = 'DB Call To Get User';
$age = 20;
$request->route()->setParameter('user', $user);
$request->route()->setParameter('age', $age);
return $next($request);
}
Then you can get the user in the controller from either the arguments:
public function TestAction(Request $request, User $user, $age)
{}
Or explicitly from the request object:
public function TestAction(Request $request)
{
$user = $request->route()->getParameter('user');
$age = $request->route()->getParameter('age');
}
Of course you can flash the data temporarily to the session or save it to the session itself and set an expiry time, but if you only need it to last for the lifetime of the request then i think this is a good way.
Hope this helps!

Resources