Laravel Form Model Binding not submitting - php

I'm having some trouble using form model binding with L4. My form is being populated, and the routes are correct but it's not submitting correctly.
Controller:
public function edit($id)
{
$transaction = Transaction::where('id', '=', $id)->get();
return View::make('transaction')->with('transactions', $transaction);
}
public function update($id)
{
$transaction = Transaction::find($id);
$input = Input::all();
$transaction->status = $input['status'];
$transaction->description = $input['description'];
$transaction->save();
}
View:
#foreach($transactions as $transaction)
{{ Form::model($transaction, array('route' => array('transactions.update', $transaction->id))); }}
{{ Form::text('description'); }}
{{ Form::select('status', array('R' => 'Recieved', 'S' => 'Shipped', 'P' => 'Pending'), 'R'); }}
{{ Form::submit('Submit'); }}
{{ Form::close(); }}
#endforeach

I'm assuming that your transactions.* routes are being generated via Route::resource().
Per the documentation, Laravel generates the following routes for a resource:
Verb Path Action Route Name
GET /resource index resource.index
GET /resource/create create resource.create
POST /resource store resource.store
GET /resource/{resource} show resource.show
GET /resource/{resource}/edit edit resource.edit
PUT/PATCH /resource/{resource} update resource.update
DELETE /resource/{resource} destroy resource.destroy
You'll see that resource.update is expecting a PUT/PATCH request, but Laravel forms default to POST.
To fix this, add 'method' => 'PUT' to the array of form options, like so:
{{ Form::model($transaction, array(
'method' => 'PUT',
'route' => array('transactions.update', $transaction->id)
)); }}
This will add a hidden input, <input type="hidden" name="_method" value="PUT" />, to your form which tells Laravel to spoof the request as a PUT.

Related

Laravel 8 form to update database

I am creating a simple blog site with CRUD functionality in Laravel 8. I have done this before using the deprecated Laravel forms, but am now trying to do it using HTML forms.
However, I am having some problem with the update part of the website. I have a controller called BlogsController with this function to be called to update the blog in the database which should be called when the user submits the form to update.
BlogsController update function
public function update(Request $request, $id)
{
$this->validate($request, [
'title' => 'required',
'body' => 'required',
'category' => 'required',
'description' => 'required',
'read_time' => 'required'
]);
$blog = Blog::find($id);
$blog->title = $request->input('title');
$blog->body = $request->input('body');
$blog->category = $request->input('category');
$blog->description = $request->input('description');
$blog->read_time = $request->input('read_time');
$blog->user_id = auth()->user()->id;
$blog->save();
return redirect('/dashboard')->with('success', 'Blog Updated');
}
What action does the form need to direct to? Top of update form
<form method="POST" action="update">
Route in web.php
Route::resource('blog', 'App\Http\Controllers\BlogsController');
Implementation in Laravel forms
{!! Form::open(['action' => ['App\Http\Controllers\BlogsController#update', $blog->id], 'method' => 'POST']) !!}
You can get a list of all your application routes and names by running
$ php artisan route:list
For your blog update route you should use
<form method="POST" action="{{ route('blog.update', ['blog' => $blog]) }}">
#method('PATCH')
</form>
in your template.
Make sure you have you have your csrf token set correctly at your form by using the #csrf, see Laravel docs.
One thing that's cool with Laravel is Route model binding. So what's that mean? We can do something like this in your update method
// BlogController.php
public function update(Request $request, Blog $blog) {
$request->validate([
'title' => 'required',
'body' => 'required',
'category' => 'required',
'description' => 'required',
'read_time' => 'required'
]);
$blog->title = $request->title;
$blog->body = $request->body;
$blog->category = $request->category;
$blog->description = $request->description;
$blog->read_time = $request->read_time;
if ($blog->save()) {
return redirect('/dashboard')->with('success', 'Blog Updated');
} else {
// handle error.
}
}
In your template, you'll want to make sure you're using a PATCH method:
<form method="POST" action="{{ route('blog.update', ['blog' => $blog]) }}">
#csrf
#method('PATCH')
...
</form>
I assume you are using Resource route for your CRUD functionality. In that case, Update method in resource controller called via PUT method and not POST. So, in your form, just add this to change the Form submission method to PUT:
<input name="_method" type="hidden" value="PUT">
Also, in your form declaration, you have to add the destination route like this:
<form method="POST" action="{{ route('blog.update', $blog->id) }}">
You also have the option of using the action to get a URL to the registered route:
action('App\Http\Controllers\BlogsController#update', ['blog' => $blog])
Check all route list:
$ php artisan route:list
your route should be like:
<form method="POST" action="{{ route('blog.update', ['blog' => $blog]) }}">
{{csrf_field()}}
{{ method_field('PATCH') }}
</form>

How to pass 2 parameters in a route, but make one hidden in Laravel?

I want to make an edit_Item functionality, but I'm having a little bit of trouble with routing when submiting the edited form. I get this error:
InvalidArgumentException in UrlGenerator.php line 314:
Route [userItems] not defined.
First of all, in my Edit page, I have a form which passes 2 arguments from the Items table (item_id and user_id) to the controller and it looks like this:
{!! Form::model($items, ['action' => ['ItemController#update', $items->id, $items->user_id], 'method' => 'PUT']) !!}
//Form inputs
{{ Form::close() }}
My Update controller looks like this:
public function update($id, $user_id){
// validate
// read more on validation at http://laravel.com/docs/validation
$rules = array(
'title' => 'required',
'description' => 'required|description',
);
// store
$items = Item::find($id);
$items->title = Input::get('title');
$items->description = Input::get('description');
$items->save();
// redirect
Session::flash('message', 'Successfully updated item!');
return Redirect::route('userItems');
}
And my Route with the Update method looks like this:
Route::put('/userItems/{id}/{user_id}', 'ItemController#update');
Now, when I submit I'm currently getting routed to:
http://localhost:8000/userItems/26/3
And I need to get routed to:
http://localhost:8000/userItems/3
Any ideas on how to make the item_id(26) disappear from the route?
You could use an hidden input
Define a hidden field (not visible to a user).
Your form
{!! Form::model($items, ['action' => ['ItemController#update', $items->user_id], 'method' => 'PUT']) !!}
<input type="hidden" name="item_id" value="{{$items->id}}">
//Form inputs
{{ Form::close() }}
Your route
Route::put('/userItems/{user_id}', 'ItemController#update');
Your controller
public function update($user_id){
// validate
// read more on validation at http://laravel.com/docs/validation
$rules = array(
'title' => 'required',
'description' => 'required|description',
);
// store
$item_id = Request::input('item_id');
$items = Item::find($item_id);
$items->title = Input::get('title');
$items->description = Input::get('description');
$items->save();
// redirect
Session::flash('message', 'Successfully updated item!');
return Redirect::route('userItems');
}

Laravel update method passing through model name instead of ID

I am having an issue with my resource route when calling the update method.
I get this error:
Creating default object from empty value
The controller:
public function update($id)
{
$input = Input::all();
$validation = Validator::make($input, Vehicle::$rules, Vehicle::$messages);
if ($validation->passes())
{
$this->vehicle->update($id, $input);
return Redirect::route('admin.vehicles.index')->with('success', 'Car Updated');
}
return Redirect::back()
->withInput()
->withErrors($validation);
}
repository:
public function update($id, $input)
{
$vehicle = Vehicle::find($id);
$vehicle->VRM = $input['VRM'];
$vehicle->make = $input['make'];
$vehicle->model = $input['model'];
$vehicle->description = $input['description'];
$vehicle->save();
}
Route:
Route::resource('/admin/vehicles', 'VehiclesController');
If I print the ID then it shows {vehicle}.
My form is this:
{{ Form::open(['route' => 'admin.vehicles.update', 'class' => 'form-horizontal edit-vehicle-form', 'method' => 'PATCH']) }}
// input fields etc
{{ Form::close() }}
I think there is something wrong with the form possibly? Since when the error is thrown the URL is:
http://localhost/admin/vehicles/%7Bvehicles%7D
Never had any issues before with using resource routes with CRUD applications and cant see where this is going wrong?
You need the id in update route...
{{ Form::open(['route' => array('admin.vehicles.update', $vehicle->id), 'class' => 'form-horizontal edit-vehicle-form', 'method' => 'PATCH']) }}

Laravel conflicting routes

My routes.php excerpt:
Route::group(['prefix' => 'admin', 'namespace' => 'Admin'], function() {
Route::resource('posts', 'PostsController', [
'except' => ['show']
]);
Route::delete('posts/trash', [
'as' => 'posts.trash.empty',
'uses' => 'PostsController#emptyTrash'
]);
});
My PostsController.php excerpt:
/**
* DELETE /admin/posts/{id}
*/
public function destroy($id)
{
// code
}
/**
* DELETE /admin/posts/trash
*/
public function emptyTrash()
{
// code
}
The problem is that Laravel confuses the 'trash' string in a DELETE /admin/posts/trash request as an {id} parameter. As a consequence, the destroy() method is called instead of emptyTrash(). Why and What can I do for this?
Firstly, order matters. Laravel will search the routes for a match in the order you register them. As you figured out, Laravel will take trash as an id and therefore the URI matches the resource route. Since that route is registered before your additional one, it will use the resource route.
The simplest fix is to just change that order:
Route::delete('posts/trash', [
'as' => 'posts.trash.empty',
'uses' => 'PostsController#emptyTrash'
]);
Route::resource('posts', 'PostsController', [
'except' => ['show']
]);
If you don't like that you can try to limit the parameter for your resource route to numbers only. Unfortunately you can't just add a ->where() to the resource route like you could with others.
Instead you have to define a global pattern for the route parameter. The route parameter Route::resource chooses is the resource name (in snake_case).
So this should work for you:
Route::pattern('posts', '[0-9]+');
Somewhere in your view, you should have a button or a link for actually deleting the post. The view should look something like this:
#section('content')
<div class="panel panel-default">
<div class="panel-heading clearfix">
<b>{{ $post->post_name . ' (id:' . $post->post_id . ')' }}</b><br />
<b> {{ link_to_route('overview', 'Go Back To Post List') }} </b>
<div class="pull-right">
// FORM FOR DELETING POST
{{ Form::open(array('route' => array('delete_post', $post->post_id))) }}
{{ link_to_route('edit_post', 'Edit Post', array('id' => $post->post_id), array('class' => 'post_img_button_edit')) }}
{{ Form::hidden('_method', 'DELETE') }}
{{ Form::submit('Delete Post', array('class' => 'post_img_button_delete')) }}
{{ Form::close() }}
</div>
<div class="pull-right">
// FORM FOR EMPTYING TRASH
{{ Form::open(array('route' => 'empty_trash')) }}
{{ Form::hidden('_method', 'DELETE') }}
{{ Form::submit('Empty Trash', array('class' => 'post_img_button_delete')) }}
{{ Form::close() }}
</div>
</div>
/* Additional HTML code within view */
Your controller should be similar to this:
public function destroy($id)
{
$this->post->delete($id);
return \Redirect::route('overview');
}
public function emptyTrash()
{
// code for collecting and emptying Trash
}
And your routes should look similar to this:
Route::delete('admin_posts/admin_posts/{id}/destroy', array('as'=>'delete_post', 'uses'=>'PostsController#destroy'));
Route::delete('posts/trash', array('as'=>'empty_trash', 'uses'=>'PostsController#emptyTrash'));
The name of your route for actually deleting posts be 'delete_post'.
The name of your route for emptying your trash will be empty_trash
Basically you're explicitly defining your routes so that you'll avoid less ambiguity and Laravel will know which routes to take. Hopefully this information will help!

Attempt to update users table generates MethodNotAllowedHttpException, Laravel-4

UsersController:
public function update($id)
{
if( ! $this->user->isValid(Input::all()))
{
return Redirect::back()->withInput()->withErrors($this->user->errors);
}
$user = $this->user->find($id);
$user->save();
return Redirect::route('users.index');
}
Route:
Route::resource('users','UsersController');
Model:
protected $table = 'users'
edit.blade.php:
{{ Form::model($user, array('route'=>array('users.update','$user'=>'id'))) }}
I notice that this does NOT generate a "PUT" action. The page source:
<form method="POST" action="https://zocios.com/users/id" accept-charset="UTF-8"><input name="_token" type="hidden" value="...">
Hitting the Update User button gets me:
Exception \ MethodNotAllowedHttpException
Is the problem "$user->save();"? Something else I'm doing wrong? Thanks!
You need to specify the method:
{{ Form::model($user, array('method' => 'put', 'route'=>array('users.update','$user'=>'id'))) }}
There is no other method than GET and POST that is accepted (despite the specs), so the framework does the job of identyfying hidden input in your form _method to make it work.

Categories