Laravel form model binding - php

I've been reading about this feature: http://laravel.com/docs/html#form-model-binding
And it looks really neat, but there are couple of things that I'm not certain about.
Do I need to put any code in the controller action to process this form? What does that look like?
The model (User) I want to bind in my form has a separate table for addresses. So I want to be able to fill out the User model's fields, but also the fields for the related Address model. Can I do that with form-model-binding, or do I have to handle the form manually?
Or, failing that, can I use form model binding for the user fields, but manually handle the address fields?

You don't need any different code in your controller to process this form. All your (named) form variables will be in Input::all().
The model ($user) you pass in
Form::model($user, array('route' => array('user.update', $user->id)))
Is just any record you need to, if you have more than one table involved, you'll have to do something like
$user = User::where('id',$userID)
->leftJoin('users_addresses', 'users_addresses.user_id', '=', 'users.id')
->first();
And pass this composed model to your Form::model().
How you name your inputs is entirely up to you, because you'll have to write the logic to process your form. But, in my opinion users_address[street] for the address inputs is good, because you'll end up with an array of addresses columns that you can pass right away to your UserAddress model.
<html>
<head>
<title></title>
</head>
<body>
{{ Form::model($user, array('route' => array('user.update', $user->id))) }}
{{ Form::label('first_name', 'First Name:', array('class' => 'address')) }}
{{ Form::text('first_name') }}
{{ Form::label('last_name', 'Last Name:', array('class' => 'address')) }}
{{ Form::text('last_name') }}
{{ Form::label('email', 'E-Mail Address', array('class' => 'address')) }}
{{ Form::text('email') }}
{{ Form::label('address[street1]', 'Address (Street 1)', array('class' => 'address')) }}
{{ Form::text('address[street1]') }}
{{ Form::label('address[street2]', 'Address (Street 2)', array('class' => 'address')) }}
{{ Form::text('address[street2]') }}
{{ Form::label('ddress[city]', 'City', array('class' => 'address')) }}
{{ Form::text('address[city]') }}
{{ Form::label('address[state]', 'State', array('class' => 'address')) }}
{{ Form::text('address[state]') }}
{{ Form::label('address[zip]', 'Zip Code', array('class' => 'address')) }}
{{ Form::text('address[zip]') }}
{{ Form::submit('Send this form!') }}
{{ Form::close() }}
</body>
</html>
And if you do dd( Input::all() ) in your controller, you'll get something like this:
This result is provided by Kint's dd(): https://github.com/raveren/kint. Really helpful.
If your form just have fields from a single Model, your update method can be very simple and look something like:
public function update($id)
{
$user = User::find($id);
if (!$user->update(Input::all())) {
return Redirect::back()
->with('message', 'Something wrong happened while saving your model')
->withInput();
}
return Redirect::route('user.saved')
->with('message', 'User updated.');
}
On forms a little bit more complex, coders will have to add more logic to their controllers, in you case with a little bit more of research I think you can make this happen:
public function update($id)
{
$user = User::find($id);
$inputs = Input::all();
if (!$user->update($inputs)) {
$address = new UserAddress($inputs['address']);
$user->address()->save($address);
...
}
...
}

In Laravel 5.1 for relation model binding you just need to eager load relation table(s):
$user = User::with(['address'])->find($id);
And in view set fields names as array:
{!! Form::model($user, ['route' => ['user.update', $user->id]]) !!}
{!! Form::text('address[street]') !!}
{!! Form::text('address[number]') !!}
{!! Form::close() !!}

Related

Toggle database value from View on button click Laravel

I am using Laravel framework as a backend API and a few blade PHP files for the front end, specifically for the authentication and the admin panel from the /admin route.
In /admin, I display a list of all registered users and buttons next to them. (This page is only visible for users that have their value in Admin column set as true). I want to toggle the Admin status of a user, either promoting or demoting them by clicking the button next to the user name.
For this, I tried to use a form submit with get method.
I have a method defined inside UserController like this:
public function setAdmin($id) {
$user = User::find($id);
$user->admin = !$user->admin;
if($user->save()) {
echo "Changed";
}
else {
echo "Could not be changed";
}
}
I want to call this method from the view on the click of a button.
I tried using a Form to send a request by specifying the action, but it gave an error saying the values passed are less than the expected number of parameters.
{!! Form::open(['action' => ['UserController#setAdmin', $user->id], 'method' => 'POST']) !!}
{{ Form::submit('Submit', ['class' => 'btn btn-primary']) }}
{!! Form::close() !!}
I have a route set up explicitly to call this action
Route::post('/admin/users/setAdmin', 'UserController#setAdmin')
Although I am not sure if I have to set an explicit route for this action or if it's possible to call a controller function directly from a view without defining the route.
I have iterated through User Model to display all users:
#if(count($users) > 0)
#foreach($users as $user)
<div class="card">
{{ $user }}
</div>
{!! Form::open(['action' => ['UserController#setAdmin', $user->id], 'method' => 'POST']) !!}
{{ Form::submit('Submit', ['class' => 'btn btn-primary']) }}
{!! Form::close() !!}
#endforeach
#else
<h2>No users found!</h2>
#endif
EDIT: Added the foreach section of the blade file. Also I modified the 'action' part of the Form::open() parameters, it was a mistype, the parameters error is still there.
Can someone explain how this can be done?
You are trying to pass a parameter to your route but there is any within its declaration. You need to add it in your route path:
Route::post('/admin/users/setAdmin/{id}', 'UserController#setAdmin')
If you don't want to have an URL like this, you should add a hidden input to your form containing your ID:
{!! Form::open(['action' => ['UserController#setAdmin'], 'method' => 'POST']) !!}
{{ Form::hidden('id', $user->id) }}
{{ Form::submit('Submit', ['class' => 'btn btn-primary']) }}
{!! Form::close() !!}
And in your controller's method:
use Request;
/* ... */
public function setAdmin(Request $request) {
$user = User::find($request->id);
/* ... */
}

Update Database with Laravel

I am trying to update information in my database with Laravel. Not sure what I am doing wrong but I can't seem to find where the problem is. Here is the code for my edit page (This is the page where I would edit information taken from my DB).
{{ Form::open(['url'=>'portfolio/update']) }}
<div>
{{ Form::label('portfolio_title', 'Portfolio Title:') }}
{{ Form::text('portfolio_title',$work->portfolio_title) }}
{{ $errors->first('portfolio_title','<span class="error">:message</span>') }}
</div>
<div>
{{ Form::label('portfolio_description', 'Portfolio Description') }}<br>
{{ Form::textarea('portfolio_description', $work->portfolio_description, ['size' => '50x5']) }}
{{ $errors->first('portfolio_description','<span class="error">:message</span>') }}
</div>
<div>
{{ Form::label('portfolio_content', 'Portfolio Content') }}<br>
{{ Form::textarea('portfolio_content', $work->portfolio_content, ['size' => '50x5']) }}
{{ $errors->first('portfolio_content','<span class="error">:message</span>') }}
</div>
{{ Form::hidden('id',$work->id) }}
<div>
{{ Form::submit('Update Work') }}
</div>
{{ Form::close() }}
I have a controller called PortfolioController that will save info to database and what not.
public function edit($work_title){
$work = Portfolio::wherePortfolio_title($work_title)->first();
return View::make('portfolio/edit', ['work' => $work]);
}
public function update(){
$id = Input::get('id');
$input = Input::except('id');
if( !$this->portfolio->fill($input)->isValid()){
return Redirect::back()->withInput()->withErrors($this->portfolio->errors);
}
$work = Portfolio::find($id);
$work->portfolio_title = Input::get('id');
$work->save();
}
Here is my route that I am working with:
Route::resource('portfolio','PortfolioController');
Route::post('portfolio/update','PortfolioController#update');
I am able to get the form populated with the correct information but when i change something like the title and click update, the page reloads but does not save in the DB. Sometimes I will get an MethodNotAllowedHttpException error. This has been pretty frustrating for me so any help will be greatly appreciated.
Why don't you just actually use your resource route?
First, remove the portfolio/update route. You don't need it.
Then change your Form::open to this:
{{ Form::open(['route' => ['portfolio.update', $work->portfolio_title], 'method' => 'put']) }}
This way you target the update method in your RESTful controller.
Finally change that to use the portfolio_title as identifier and you should be able to remove the hidden id field from your form.
public function update($work_title){}
Please take a look at:
RESTful controllers
Opening a form

Laravel 4 login doesnt work

If i try to login i just get this url:
http://xx.xx.xx.xx/game/public/?_token=4kXP1sYlLIizUUMyMWluK6jSEOacDikXafUSVrIF&username=dieter&password=azerty
Im probably doing something stupid.. Here is my code:
controller:
public function postSignin() {
if (Auth::attempt(array('username'=>Input::get('username'), 'password'=>Input::get('password')))) {
return Redirect::to('users/dashboard')
->with('message', 'You are logged in');
} else {
return Redirect::to('index')
->with('message', 'Your username/password combination was incorrent.')
->withInput();
}
}
Login form:
{{Form::open(array('url'=>'users/signin')) }}
{{ Form::text('username', null, array('class' => 'input-block-level', 'placeholder' => 'Username')) }}
{{ Form::password('password', null, array('class' => 'input-block-level', 'placeholder' => 'Password')) }}
{{ Form::submit('Login', array('class' => 'btn btn-default')) }}
{{ Form::close() }}
Routes:
<?php
Route::controller('users', 'UsersController');
Route::controller('/', 'HomeController');
It's like it is ignoring the 'url' in the login form. If i change it to something else it just responds the same way.
I've bene googling all day for this, so please help. ^^
Thanks
You've got a form without action attribute, and your submit button sends you to the same page. Try to change the Form declaration as this:
{{ Form::open(array('route' => 'users/signin') ) }}
I hope this works fine.

Inside create form, how do I route to a nested resource? 'route' => 'user.lesson.store' doesn't work

I've created a nested resource in my routes.php
Route::resource('user', 'UserController');
Route::resource('user.lesson', 'LessonController');
Route::resource('user.lesson.hotspot', 'HotspotController');
And I've tied all user resource actions to the User controller. I've moved on to Lesson, and I'm trying to create a form to create a new lesson.
{{ Form::open(array('route' => 'user.lesson.store')); }}
{{ Form::label('title', 'Title of lesson'); }}
{{ Form::text('title'); }}
{{ Form::label('description', 'Description of lesson'); }}
{{ Form::textarea('description'); }}
{{ Form::submit('Create New Lesson'); }}
{{ Form::close(); }}
However, this produces an action of .../user/%7Buser%7D/lesson. Pointing route at lesson.store produces an error.
What else do I need to do to get this to work?
You need to provide the route with the user key, as the route name that laravel generates will be like user/{user}/lesson/{lesson}
{{ Form::open(array('route' => array('user.lesson.store', $user->getKey()))); }}

Laravel - Routing to update error

I encounter a error:
Some mandatory parameters are missing ("users") to generate a URL for route "users.update".
I have this set on my view:
{{ Form::open( array('action' => array('UsersController#update')) ) }}
<div> {{ Form::label('username', 'Username:') }}
{{ Form::text('username', $user->username , array('class' => 'form-control')) }}</div>
<div> {{ Form::label('email', 'Email Address:') }}
{{ Form::text('email', $user->email , array('class' => 'form-control')) }}</div>
<div> {{ Form::label('new_password', 'New Password:') }}
{{ Form::text('new_password', '', array('class' => 'form-control')) }} </div>
<div> {{ Form::label('old_password', 'Old Password:') }}
{{ Form::text('password', '', array('class' => 'form-control')) }} </div>
{{ Form::submit() }}
{{ Form::close() }}
I also have a function in my controller linked to update:
public function update() {
return 'This is an update';
}
And finally, when I check all the routes available in Artisan command, I found that the update has a route to: users/{users}
What's wrong with my codes? I'm trying to update a user and it throws this error.
Your route is defined in a way to expect a variable $users to be passed. because of the: {users}
Instead, you should define it like:
Route::post('users/update', 'UsersController#update');
and then in your function update() get the post variable by:
$users_data = Input::get();
OR
if you want to keep the parameter, redefine the form by passing additional parameter:
{{ Form::open( array('action' => array('UsersController#update', $id)) ) }}
The way you are opening the FORM, it is needs a route paramenter. If you dont want to pass parameters, just use the following:
{{ Form::open(array('action' => 'UsersController#update')) }}
Instead of:
{{ Form::open( array('action' => array('UsersController#update')) ) }}
Even when you're setting a action, you may still need a route for it. I STRONGLY recommend you to always use CLEARED DEFINED routes to your controllers. See if the Resource Controllers helps you, in case you don't wanna to define every god damm route (I DON'T).
And, finally answering your question: I think a
{{ Form::open(array('action' => 'UsersController#update')) }}
...may solve your problem. Hope it helps. Sorry for my bad english! :D

Categories