In this section we'll be building a user administration tool. User admins are one of the most common components to be found in web applications. They also use a number of important systems that we want to explore with Laravel including database interactions, forms, and routing.
We'll be storing and retrieving records from a database so now it would be a good time for you to create a database for this application. Keep the database name, user, and password handy.
Let's get started.
Armed with our database name, user, and password, we can now tell Laravel how to connect to our database.
Open the file application/config/database.php
and scan the contents. You'll find example configurations for each database driver. Determine which driver you're going to use from the available options (sqlite
, mysql
, pgsql
, and sqlserv
) and enter the name of the driver as the default database connection.
Then, in the Connections section add your database name, user, and password.
Ok! We're just where we want to be. Let's get started by creating the users table.
You might typically create the users table with a tool like phpMyAdmin or Navicat. But, Laravel provides a fancy migrations system for us and we should use it because it improves our workflow and reduces deployment bugs.
Migrations are version control for your schema modifications. Migrations reduce the amount of headache that we face by requiring us to only define the schema alteration once. Afterwards, we can deploy our changes to any number of systems without the potential for human error.
Note
Migrations are especially useful for projects in which you're collaborating with others. Like using source control, migrations are always a good idea.
Developers who are new to migrations might believe them unnecessary or believe that they add too much additional work at first. But, stick with it and their value will become quickly apparent.
Let's start by creating our migration template with Laravel's command-line tool Artisan.
In order to use Artisan, we will need to add the directory which contains the PHP binary to our PATH
environment variable. This lets us execute the PHP binary from anywhere, as the system will know where to find it. You can test this by running the following command from your command-line terminal:
# php -v
You should see a nice readout telling you which version of PHP you're running.
If you find that your command-line interface doesn't know where the PHP binary is, you'll need to update your system's PATH
. You can modify your PATH
variable on OS X and Linux with the following command line:
# export PATH=/path/to/php/binary:$PATH
Windows users will need to right-click on Computer from the start menu and click on Properties. Click on Advanced system settings, and then click on Environment Variables. Here you can find the system variable PATH
and add the directory that contains your PHP binary.
Now that the PHP binary is in our path, let's navigate to our project
folder. Now we can go ahead and install our migrations database table. Execute the following command:
# php artisan migrate:install
You should see the message, Migration table created successfully. If you get errors, verify that your database connection information is correct.
Next, let's create a new migration template in our application/migrations
folder.
# php artisan migrate:makecreate_users_table
The migration files are formatted with the year, month, day, time, and the text that you added that enable it to be identified by a human, in this case create_users_table
. Mine looks like 2012_08_16_112327_create_users_table.php
. The structure of the filename is important as it helps Laravel to understand the order in which it should run the migrations. By using a convention for naming your migrations, you'll be helping your team to better understand your work (and vice-versa). An example convention might consist of entries like create_users_table
, add_fields_to_users_table
, or rename_blog_posts_table_to_posts
.
The migrations file contains a single class with the human readable name that we entered before. The class has two methods, up()
and down()
.
When migrations are run, Laravel reads in each migration file one by one and runs its up()
method. If you feel that a mistake has been made, you can rollback migrations. When rolling back a change, Laravel runs the down()
method. The up()
method is for making your desired changes to the database. The down()
method is for reverting your changes.
Let's go ahead and look at what our create_users_table migration
should look like:
classCreate_Users_Table { /** * Make changes to the database. * * @return void */ public function up() { Schema::table('users', function($table) { $table->create(); $table->increments('id'); $table->string('email'); $table->string('real_name'); $table->string('password'); $table->timestamps(); }); } /** * Revert the changes to the database. * * @return void */ public function down() { Schema::drop('users'); } }
Let's first discuss our up()
method. Our goal is to create the users
table and to define the fields within it. In order to accomplish this goal, we'll use the Laravel Schema
class. When creating or making modifications to tables, we use the Schema
class' table()
method.
Schema::table()
accepts two arguments. The first is the name of the table that you'll be interacting with, in this case it's users
. The second argument is a closure which contains your table definition. The closure receives the argument $table
and this is the object that we'll be interacting with to define the table.
$table->create();
This line tells Laravel that the table will need to be created. If we omit this line, Schema
will generate the ALTER TABLE
syntax rather than the CREATE TABLE
syntax.
$table->increments('id');
The increments()
method tells Schema
that the specified field should be an auto-incremented primary key. With Laravel, you'll want to use simple field names such as id
, email
, and password
. If you aren't familiar with using Object-Relational Mapping (ORM), you may be in the habit of creating those same field names with the table name as a prefix. For example, user_id
, user_email
, user_password
. The purpose behind defining field names with the table name as a prefix is to simplify query generation when using a query builder. This is no longer necessary and it's best to follow the more simple convention as it manages redundant interactions for you, removing the need for you to continuously write the boilerplate code.
$table->string('email'); $table->string('real_name'); $table->string('password');
Next we have a few string declarations. These will be created as the VARCHAR
fields with the default length of 200
. You can override the length of these fields by passing a second argument that represents the intended length. For example:
$table->string('email', 300);
This line creates a VARCHAR
field named email
with a length of 300
.
Note
It's important to note that we shouldn't reduce the size of the password
field as we'll need that length for the output from Laravel's Hash
class.
$table->timestamps();
Finally, we come to the timestamps()
method. This will create two DATETIME
fields (created_at
and updated_at
). It is not unreasonable to create the timestamp
fields for every table in the database as they can be very useful for troubleshooting down the road. The Eloquent ORM will automatically manage these timestamp
fields for us. So, we can forget about them for now.
The down()
method should revert any changes made to the up()
method. In this case, the up()
method creates a database table called users. So, the down()
method should remove the table.
Schema::drop('users');
This is done with the method Schema::drop()
. drop()
takes a single argument, a string value containing the name of the table that you wish to drop.
That's it! We have our first migration. Once you memorize the commonly used methods such as increments()
, string()
, decimal()
, timestamps()
, and date()
, you'll be able to make migrations just as fast as you were able to modify your database with your preferred database management tool. But, now we gain the added benefit from using them in versioned and collaborative situations.
Now, we're ready to run our migrations. From this point on, running migrations will always be done in the same way. Let's go ahead and give it a shot:
# php artisan migrate
Now, we should see the message, Migrated: 2012_08_16_112327_create_users_table.
It's very important to test our migrations. If we don't test our migrations, it could come back to bite us later in the project when we need to roll back migrations and run into an error. Proper migration testing verifies that the up()
and down()
methods both function as intended.
To test the up()
method, run the migration and open your preferred database management application. Then, verify that everything is as you intended. Then, test the down()
method by rolling back the migration and doing the same. Roll back your migration now by using the following command:
# php artisan migrate:rollback
Optimally, you will be notified that the migration was rolled back successfully. Double-check that your database no longer contains the users
table. That's it! This migration is good to go. Run your migrations for one last time and let's move on to the next step.
# php artisan migrate
Now that we have created our users
table, we should go ahead and create our user model. In the context of MVC, a model is a class that represents various types of data interactions. The data can include information stored in a database such as users, blog posts, and comments or interactions with many other types of data sources such as files, forms, or web services. For the sake of this document, we'll primarily be using models to represent the data that we store in our database.
Models sit in the application/models
folder. So go ahead and create the file application/models/user.php
with the following code:
class User extends Eloquent { }
This is all we need! This tells Laravel that our user model represents data in the users table. Wait! How does Laravel know that? Well, because we're following Laravel's conventions of course! Our database table users
is plural because it signifies that it stores more than one user record. The model class is named User
singular because it represents one single user record in the users
table. The User
class name is capitalized because of the standard for using Pascal case for class names. If your database table was named user_profiles
, your model's class name would be UserProfile
.
We can see how using conventions prevents us from having to make a bunch of configurations. Well, what if we must use a database table that doesn't follow conventions? No problem! We can just define the table name manually. Just add the following line to the User
class:
public static $table = 'my_users_table';
That's all it takes. Now, Laravel knows that when interacting with this model, it should use the table named my_users_table
. Most conventions in Laravel can be overridden with configuration when necessary.
There's one important thing that we should add to our user model. We're storing the user's e-mail address, real name, and password. We want to make sure that the user's password isn't stored in plain text. We need to hash their password before it is stored in the database. For this we'll create a setter.
A setter is a method that intercepts the assignment of an attribute. In this case, we're going to intercept the assignment of the password attribute, hash the value that we received, and then store the hashed value in the database.
Let's look at some code.
class User extends Eloquent { public function set_password($string) { $this->set_attribute('password', Hash::make($string)); } }
As you can see, the convention for declaring setters is to prefix the name of the attribute whose assignments you want to intercept with set_
. The user's password will be passed to the setter as the argument $string
.
We use the set_attribute()
method to store a hashed version of the user's password into the model. Typically the set_attribute()
method is not necessary. But, we don't want our setter to be stuck in an endless loop as we continuously attempt to assign $this->password
. The set_attribute()
method accepts two arguments. The first is the name of the attribute and the second is the value that we want to assign to it. When assigning values with set_attribute()
, setter methods will not be called and the data will be directly modified within the model.
We're using the make()
method from Laravel's Hash
class to create a salted hash of the user's password.
Before we can move on and test our user model, we need to know a few things about routing in Laravel. Routing is the act of linking a URL to a function in your application. In Laravel, it's possible to route in two ways. You can either route to a closure or a controller action. As we'll be going over controllers in more detail later, let's start by looking at how we can route to a closuRoutes in Laravel are declared in application/routes.php
. This file will represent the connection between your site's URLs and the functions that contain application logic for your site. This is very handy as other developers will be able to come into your project and know how requests are routed, simply by reviewing this file.
Here is a simple example of routing to a closure:
Route::get('test', function(){ return "This is the test route."; });
We're using the Route::get()
method to define the route. Route::get()
registers a closure with the router that specifically responds to a GET
request at the specified URI. To register a closure for the POST
, PUT
, and DELETE
requests, you'd use Route::post()
, Route::put()
, and Route::delete()
respectively. These methods correspond to what are commonly referred to as the HTTP verbs.
Typically, developers only interact with the GET
and POST
requests. When a user clicks on a link or enters a URL in their address bar, they're creating a GET
request. When a user submits a form, they're typically creating a POST
request.
The first argument for the Route::get()
method is the URI for the route (the part of the URL after the domain name), and the second argument is the closure which contains the desired application logic.
Let's update the example and test the route.
Note
Notice that instead of using echo to output the string we're returning it. That's because whether you route to a closure or route to a controller action, you should always return your response. This allows Laravel to handle many situations in a robust way.
Now go ahead and navigate to http://myfirst.dev/test
. You will see the message, This is the test route.
Now, let's test the User
model and learn a bit about Eloquent in the process. In this application, we're going to interact with the User
model in a few ways. We'll want to use the Create
, Retrieve
, Update
, and Delete
methods for user records. These common methods are referred to as CRUD methods.
Eloquent simplifies development by removing the need to manually implement CRUD methods for your models. If you've ever designed models without an ORM, you are already aware that this alone can save you many hours on large sites.
Now, let's explore the various ways in which you can create new user records. We'll repurpose our test route from the previous step to help us get to know Eloquent. Update the route declaration with the following code:
Route::get('test', function() { $user = new User; $user->email = "[email protected]"; $user->real_name = "Test Account"; $user->password = "test"; $user->save(); return "The test user has been saved to the database.";});
Let's review:
$user = new User;
First, we create a new instance of our User
model and store it in the $user
variable:
$user->email = "[email protected]"; $user->real_name = "Test Account"; $user->password = "test";
Then, we set some attributes in our User
model. These attributes directly correspond to the fields in our users database table.
$user->save();
Next, we tell Eloquent that we want to save the contents of this model to the database.
return "The test user has been saved to the database.";
Finally, we output this string to the browser so that we know that all is well.
Go ahead and navigate to http://myfirst.dev/test
in your browser. You should see the confirmation message that the user has been saved to the database.
Now, take a look at the contents of your database's users
table. You will see a new record filled with our data. Notice that the timestamps
fields have been automatically pre-populated for you. It's that easy to create new database records with Eloquent!
Now it's time for us to create our first controller. You've already learned how we can route to a closure and you can use this method to make an entire web-application. So, what are controllers and why should we use them?
Controllers are containers for methods that contain application logic related to a common domain. A domain is simply a categorization of purpose. In the context of our web application, we will be working solely with administrating user data. Therefore, our domain is users
. Our users
controller will contain the application logic that controls our application flow and delivers our database data to the view for formatting.
Since controllers allow us to group logic, we can also apply configurations to a controller that will affect all of the methods inside it. We'll explore more of this concept later.
Let's create the file application/controllers/users.php
and fill it with our controller class' skeleton:
<?php class Users_Controller extends Base_Controller { public function action_index() { return "Welcome to the users controller."; } }
Our users
controller is a class whose name is constructed from the domain of the methods contained within and is suffixed with _Controller
. Since this controller's domain is user accounts, our controller is named Users_Controller
. The _Controller
suffix is required because it prevents controller classes from having name collisions with other classes in the system.
You'll notice that our Users_Controller
class extends Laravel's default Base_Controller
class. This is a good practice because if we need some code or configurations to affect all of our controllers, we can just edit the file application/controllers/base.php
and make changes to the Base_Controller
class. Every controller that extends the Base_Controller
class will be affected.
You'll also notice that we have defined a controller action named index
. A controller action is a method within a controller class that we intend to be the destination for a route. You may decide to create methods within a controller class that will only be called from other methods within that class; these would not be actions.
Controller actions are named with the prefix action_
. This is an important distinction because we do not want users to be able to access methods within our controller that aren't actions.
So, now that we have this controller how can we access the index
action from our browser? For now, we can't. We haven't routed any URL to that controller action. So, let's do that. Open up application/routes.php
and add the following line:
Route::controller('users');
As you can see, we can register an entire controller with the router with one command. Now, we can access our users
controller's index
action with http://myfirst.dev/users/index
. The index
action is also considered to be the default action for a controller, so we can also access our index
action at http://myfirst.dev/users
.
It's important to note that while routing to closures is convenient, routing to controllers is generally considered better practice for a few reasons. Controllers are not loaded into memory until their routes are accessed, which helps to reduce the memory footprint of your application. They also make maintenance easier by making it quite clear where the developer can find the code for the route. Controllers are derived from a base class, so it's simple to make a change in one class and through inheritance have that change affect other classes. Finally, since controllers are actions grouped by purpose, it's often quite convenient to assign filters on a per-controller basis. We'll talk more about filters in the section Top 5 features you need to know about.
Now we can go to http://myfirst.dev/users
and access the index
method of our controller. That's pretty cool, but our users
controller's index
page needs to show us a list of the users in the system. To display a list of users, we're going to need to create a view.
A view is a file that contains formatting data (typically HTML). PHP variables, conditionals, and loops are used within the view to display and format dynamic content.
Laravel provides its own templating system called Blade. Blade removes PHP tags and provides shortcuts for common tasks so that your views are cleaner and easier to create and maintain.
Let's get started by creating the folder application/views/users/
. This folder will store all of the views for our users
controller. It is a standard convention to create a folder under application/views
for each controller that needs a view. Then, create the view file at application/views/users/index.blade.php
. The convention is to name the view file after the controller action in which it's used. In this example, we're using Blade. If you do not wish to use Blade simply name the file index.php
.
Let's fill the view with the following HTML:
<h1>Users</h1> <ul> <li>Real Name - Email</li> </ul>
It's not pretty. But, it's easy to understand.
Now, we'll make a modification to the users
controller's index
action:
public function action_index() { return View::make('users.index'); }
Now, where we were previously returning a string, we'll return a View object. Let's take a closer look at what's happening here.
The View
class' make()
method is a factory method that is used to generate View objects. In this case, we're passing the argument users.index
. This is Laravel's internal notation for referring to view files. The notation is made up of the path to the view file relative to the application/views
directory including the filename without its file extension. For example, application/views/users/index.php
would be written as users.index
, and application/views/admin/users/create.php
would be written as admin.users.create
.
Note
It's important to note that we're returning the View object instead of using echo to send the rendered contents of the view to the browser. This is an important aspect of the way that Laravel works. We'll never use echo from within a routed closure or a controller action. Instead, we'll always return the result and allow Laravel to handle things appropriately.
Now, when we go to http://myfirst.dev/users
, we'll see the view that we just created!
The fact that we can go to a URL and see the view file that we created is pretty cool. But, we need to be able to see the list of users from our database. To accomplish this goal, we'll first query the User
model from our controller action, and then pass that data to the view. Finally, we'll update our view to display the user data received from the controller.
Let's start by updating our users
controller's index
action:
public function action_index() { $users = User::all(); return View::make('users.index')->with('users', $users); }
Let's look at this line by line:
$users = User::all();
First, we request all users as objects from Eloquent. If we have no rows in our users
table, $users
will be an empty array. Otherwise, $users
will be an array of objects. These objects are instantiations of our User
class.
return View::make('users.index')->with('users', $users);
Then, we modify the creation of our View
object a bit. We chained a new method named with()
. The with()
method allows us to pass data from the controller into the view. This method accepts two arguments. The first argument is the name of the variable that will be created in the view. The second argument will be the value of that variable.
To recap, we've queried the database for all users and passed them as an array of User
objects to the view. The array of User
objects will be available in the view as the variable $users
due to the fact that users
was the first argument to the with()
method.
Now that our view has access to the user data, let's update the view so that we can actually see those users.
<h1>Users</h1> @if($users) <ul> @foreach($users as $user) <li>{{ $user->real_name }} - {{ $user->email }}</li> @endforeach </ul> @else Looks like we haven't added any users, yet! @endif
Blade is easy to understand and results in much more elegant code. The {{ }}
tags output the results of the expression within them and replace a typical echo command. Other constructions such as if()
, foreach()
, and for()
are the same, but without PHP tags and with a preceding @
.
Note
Blade doesn't incur a significant performance penalty since it renders to a raw PHP cache. Parsing of a Blade template is only done when changes have been made.
It's also important to note that you are still free to use PHP tags in the Blade templates.
As you can see we use an if statement to check if the $users
array contains data. If it does, we loop through the users and display a new list item for each. If the $users
array doesn't contain any data, we output a message saying so.
And that's it! Save the file and hit reload in your browser, and you will see the test account that we created.
We've already mentioned that Laravel's routing system enables you to route GET
, POST
, PUT
, and DELETE
requests to closures. But we haven't talked about how to individually route them to controller actions.
The answer is RESTful controllers! RESTful controllers enable you to route to different controller actions based on the request method. Let's configure our application to use RESTful controllers.
Since all of our controller classes are derived from the Base_Controller
class, we can simply add the $restful
configuration to it and all of our controllers will be affected.
Update your Base_Controller
class to look like this:
classBase_Controller extends Controller{ public $restful = true; /** * Catch-all method for requests that can't be matched. * * @param string $method * @param array $parameters * @return Response */ public function __call($method, $parameters) { return Response::error('404'); } }
Now, every controller that extends Base_Controller
(including our own Users_Controller
) is a RESTful controller!
But, wait. Now, we'll get a 404 error when we go to http://myfirst.dev/users
. This is because we are not declaring our actions the RESTful way.
Edit your Users_Controller
class and change the line:
public function action_index()
To this:
public function get_index()
Your Users_Controller
class should now look like this:
classUsers_Controller extends Base_Controller { public function get_index() { $users = User::all(); return View::make('users.index')->with('users', $users); } }
Now, when we save and reload the page in our browser it works again! The get_ prefix
that we added to our index
method serves much the same purpose as the action_
prefix that we were using previously.
Unless a method is prefixed appropriately, Laravel will not route URLs to them. In this way, we can ensure that only controller actions are routable and that our web-application's users can't access other methods that may exist in our controllers by simply typing the names of the methods in their browsers.
When an action is prefixed with get_
, it will only respond to the GET
requests. An action prefixed with post_
will only respond to the POST
requests. The same is true of put_
and delete_
. This gives us more code separation and allows us to really improve the readability and maintainability of our application.
It's time to give our site's administrators the ability to create users. We're going to need a new form. Let's start off by creating the file application/views/users/create.php
and populating it with the following form HTML:
<h1>Create a User</h1> <form method="POST"> Real Name: <input type="text" name="real_name"/><br /> Email: <input type="text" name="email"/><br /> Password: <input type="password" name="password" /><br /> <input type="submit" value="Create User"/> </form>
Then, let's create a controller action for it. In our Users_Controller
, let's add the following action.
public function get_create() { return View::make('users.create'); }
Now, we can go to http://myfirst.dev/users/create
and see our form. Once again, it's not pretty but sometimes simple is best.
When we submit the form it's going to make a POST
request to our application. We haven't yet created any actions to handle the POST
requests, so if we submit it now we're going to get a 404 error. Let's go ahead and create a new action in Users_Controller
:
public function post_create() { return "The form has been posted here."; }
Notice that this method has the same action name as the get_create()
method that we're using to show the create user form. Only the prefix is different. The get_create()
method responds to the GET
requests where the post_create()
method responds to the POST
requests. In the case of our create user form, the post_create()
method receives the contents of the form's submitted input fields.
Go ahead and submit the create user form and you'll see the message, The form has been posted here.
Now that we are receiving the data from the form, we can go ahead and create the user account.
Let's update our post_create()
function in the Users_Controller
class to add this functionality:
public function post_create() { $user = new User; $user->real_name = Input::get('real_name'); $user->email = Input::get('email'); $user->password = Input::get('password'); $user->save(); return Redirect::to ('users'); }
Here we're creating a new user record in the same way that we did in our test
route. The only difference is that we're using Laravel's Input
class to retrieve the data from the form. Whether the data comes from a GET
request's query string or a POST
request's post data, the Input::get()
method can be used to retrieve the data.
We populate the User
object with input data. Then we save the new user.
return Redirect::to('users');
Here's something new. Instead of returning a string or a View
object, we're using the Redirect
class to return a Response
object. Both routed closures and controller actions are expected to return a response. That response could be a string or a Response
object. When a View
object is returned it will be rendered as a string. The Redirect
class' to()
method specifically tells Laravel to redirect the user to the page specified in its argument. In this example the user will be redirected to http://myfirst.dev/users
.
We're redirecting the user here so that they can see the updated list of users, which will include the user that they just created. Go ahead and give it a try!
We need a link from the users index view to the create user form as it's currently inaccessible from the user interface. Go ahead and add the link to the file application/views/users/ index.blade.php
with the following line of code:
{{ HTML::link('users/create', 'Create a User') }}
Laravel's HTML
class can be used to create a variety of HTML tags. You might be asking yourself why you wouldn't simply write the HTML for the link yourself. One very good reason to use Laravel's HTML helper class is that it provides a unified interface for creating tags that may need to change dynamically. Let's look at an example to clarify this point.
Let's say that we want that link to look like a button and our designer created a sweet CSS class named btn
. We need to update the call to HTML::link()
to include the new class attribute:
{{ HTML::link('users/create', 'Create a User', array('class' => 'btn')) }}
Actually, we could include any number of attributes to that class and they'd all be handled appropriately. Any attribute assigned to the HTML elements can be updated dynamically by passing a variable to that method instead of declaring it inline.
<?php $create_link_attributes = array('class' => 'btn'); ?> {{ HTML::link('users/create', 'Create a User', $create_link_attributes) }}
Now that we can add users, we may want to do a bit of cleanup. Let's add a delete action to our users
controller.
public function get_delete($user_id) { $user = User::find($user_id); if(is_null($user)) { return Redirect::to('users'); } $user->delete(); return Redirect::to('users'); }
Now, let's step through this.
public function get_delete($user_id)
This is the first time that we've declared a parameter in a controller action. In order to delete a user, we need to know which user to delete. Since we have used Route::controller('users')
to have Laravel automatically handle the routing for our controller, it'll know that when we go to the URL http://myfirst.dev/users/delete/1
it should route to the delete action and pass additional URI segments as arguments to the method.
If you wanted to receive a second argument from a URL (for example, http://myfirst.dev/users/delete/happy
), you would add a second parameter to your action as follows:
public function get_delete($user_id, $emotion)
Next, we need to verify that a user with the specified user ID actually exists.
$user = User::find($user_id);
This line tells Eloquent to find a user with an ID that matches the argument. If a user is found, the $user
variable will be populated with an object that is an instance of our User
class. If not, the $user
variable will contain a null value.
if(is_null($user)) { return Redirect::to('users'); }
Here, we're checking if our user variable has the null value indicating that the requested user was not found. If so, we'll redirect back to the users
index.
$user->delete(); return Redirect::to('users');
Next, we delete the user and redirect back to the users
index.
Of course, our work here won't be finished until we update our application/views/users/index.php
file to give us links to delete each user. Replace the list item code with the following:
<li>{{ $user->real_name }} - {{ $user->email }} - {{ HTML::link('users/delete/'.$user->id, 'Delete') }}</li>
Reload the users
index page and you'll now see the delete link. Click on it and be horrified that we've irreparably removed data from the database. I hope it wasn't anything important!
So, we can add and delete users, but what if we have made a typo and want to fix it? Let's update our users
controller with the methods that are necessary for us to display our update form and then to retrieve the data from it in order to update the user record:
public function get_update($user_id) { $user = User::find($user_id); if(is_null($user)) { return Redirect::to('users'); } return View::make('users.update')->with('user', $user); }
Here we have our new get_update()
method. This method accepts a user ID as an argument. Much like we did with the get_delete()
method, we need to load the user record from the database to verify that it exists. Then, we'll pass that user to the update form.
public function post_update($user_id) { $user = User::find($user_id); if(is_null($user)) { return Redirect::to('users'); } $user->real_name = Input::get('real_name'); $user->email = Input::get('email'); if(Input::has('password')) { $user->password = Input::get('password'); } $user->save(); return Redirect::to('users'); }
When a user submits our update form, they'll be routed to post_update()
.
You may have noticed a common theme with methods that receive a user ID as an argument. Whenever we are going to interact with a user model we need to know for sure that the database record exists and that the model is populated. We must always first load it and validate that it is not null.
Afterwards, we assign new values to the real_name
and email
attributes. We don't want to just change the user's password every time we submit a change. So, we'll first verify that the password field wasn't left blank. Laravel's Input
class' has()
method will return false
, if an attribute either wasn't sent in the form post or if it's blank. If it's not blank, we can go ahead and update the attribute in the model.
We then save the changes to the user and redirect back to the users
index page.
Now, we just need to create the update
form and we'll have a full administrative system!
Go ahead and create the view at application/views/users/update.blade.php
and fill it with this lovely form:
<h1>Update a User</h1> {{ Form::open() }} Real Name: {{ Form::text('real_name', $user->real_name) }}<br /> Email: {{ Form::text('email', $user->email) }}<br /> Change Password: {{ Form::password('password') }}<br /> {{ Form::submit('Update User') }} {{ Form::close() }}
This is almost exactly like the create form except that we have mixed things up a little. First of all, you'll notice that we're using Laravel's Form
class helper methods. These helper methods, like the HTML
class' helper methods, are not mandatory. However, they are recommended. They offer many of the same advantages as the HTML
class' helper methods. The Form
class' helper methods offer a unified interface for generating the resulting HTML tags. It's much easier to programmatically update HTML tag attributes by passing an array as an argument than to loop through and generate the HTML yourself.
Real Name: {{ Form::text('real_name', $user->real_name) }}
Text fields can be prepopulated by passing in a second argument. In this example, we're passing the real_name
attribute from the user
object that we passed from the controller. We then prepopulate the email
field in the same way.
Change Password: {{ Form::password('password') }}
Notice that we're not prepopulating the password
field. It doesn't make sense to do so as we're not storing a readable version of the password in the database. Not only that, to prevent a developer from making a mistake the Form::password()
method does not have the functionality to prepopulate this field at all.
And with that we have a fully working update user form!