cult3

The Foundations of CRUD in Laravel 4

Jun 23, 2014

Table of contents:

  1. Writing the routes
  2. The Controller
  3. Injecting the repository
  4. The index method
  5. The show method
  6. The create method
  7. The store method
  8. The edit method
  9. The update method
  10. The delete method
  11. The destroy method
  12. Conclusion

CRUD (Create, Read, Update and Delete) are the four basic functions that you will see in a lot of web applications. These four simple functions allow us to accomplish a great deal when it comes to working with data that needs to be stored in persistent storage such as a database.

Laravel 4 provides a fantastic foundation for building CRUD web applications. CRUD is so prevalent that you’ll probably find yourself copying boilerplate code from one project to another.

However, if you have never written the CRUD boilerplate code before it can be a bit difficult to get your head around what you need to write.

In this tutorial I’m going to walk you through my basic CRUD setup. This basic template can be reused over and over again so I think it will be very applicable to whatever you are building. I’ll be writing this template for a Cribbbs resource, but it will apply in exactly the same way for blog posts, users, projects or whatever is applicable to your application.

Writing the routes

Whenever I set up this basic CRUD boilerplate, the first thing I like to do is to list out all of the routes that I’m going to need:

Route::get("cribbbs", [
    "uses" => "CribbbController@index",
    "as" => "cribbbs.index",
]);

Route::get("cribbbs/create", [
    "uses" => "CribbbController@create",
    "as" => "cribbbs.create",
]);

Route::post("cribbbs", [
    "uses" => "CribbbController@store",
    "as" => "cribbbs.store",
]);

Route::get("cribbbs/{id}", [
    "uses" => "CribbbController@show",
    "as" => "cribbbs.show",
]);

Route::get("cribbbs/{id}/edit", [
    "uses" => "CribbbController@edit",
    "as" => "cribbbs.edit",
]);

Route::put("cribbbs/{id}", [
    "uses" => "CribbbController@update",
    "as" => "cribbbs.update",
]);

Route::get("cribbbs/{id}/delete", [
    "uses" => "CribbbController@delete",
    "as" => "cribbbs.delete",
]);

Route::delete("cribbbs/{id}", [
    "uses" => "CribbbController@destroy",
    "as" => "cribbbs.destroy",
]);

Don’t worry if this looks a little bit intimidating right now, I’ll be working through each route one step at a time.

The Controller

Each of the routes that we’ve outlined above maps to a method on a CribbbController:

class CribbbController extends BaseController
{
}

Injecting the repository

The first thing I will do to this controller will be to inject a repository so that we create, read, update and delete from the persistent storage (i.e the database):

use Cribbb\Repositories\Cribbb\CribbbRepository;

class CribbbController extends BaseController
{
    /**
     * The Cribbb Repository
     *
     * @var Cribbb\Repositories\Cribbb\CribbbRepository
     */
    protected $cribbbRepository;

    /**
     * Inject the CribbbRepository
     *
     * @param Cribbb\Repositories\Cribbb\CribbbRepository $cribbbRepository
     * @return void
     */
    public function __construct(CribbbRepository $cribbbRepository)
    {
        $this->cribbbRepository = $cribbbRepository;
    }
}

If you are unfamiliar with the idea behind repositories, take a look at this tutorial.

The index method

The first method I will implement on the controller is the index() method. The index() method is used to return a listing of all the entities of the resource:

/**
 * Return a listing of all Cribbbs
 *
 * @return View
 */
public function index()
{
    $cribbbs = $this->cribbbRepository->all();

    return View::make('cribbbs.index', compact('cribbbs'));
}

In the index() method we can simply grab all entities from the database and return them to the View. In real life you would probably want to paginate the results if you are likely going to have a lot of records in the database. If you are unfamiliar with pagination, take a look at Working with Pagination in Laravel 4.

A simple view for displaying all the entities could be:

@if (Session::has('message'))
<div>{{ Session::get('message') }}</div>
@endif

<div>
<a href="{{ URL::route('cribbb.create') }}">Create</a>
</div>

<table>
    <thead>
        <tr>
            <th>Name</th>
            <th></th>
        </tr>
    </thead>
    <tbody>
    @foreach ($cribbbs as $cribbb)
        <tr>
            <td>{{ $cribbb->name }}</td>
            <td><a href="{{ URL::route('cribbb.show', ['id' => $cribbb->id]) }}">View</a></td>
        </tr>
    @endforeach
    </tbody>
</table>

This will display a table of all of the entities that are returned from the method. I’ve also included a link to create a new entity and a link to click through to view any individual entity.

You will also notice that I’ve included a flash message at the very top. Don’t worry about this for now as we’ll come back to it later.

The show method

The show() method will return a single entity based upon it’s id:

/**
 * Display a single Cribbb by id
 *
 * @param int $id
 * @return View
 */
public function show($id)
{
    $cribbb = $this->cribbbRepository->find($id);

    if ($cribbb) {
        return View::make('cribbb.show', compact('cribbb'));
    }

    App::abort(404);
}

In this method we search for the particular Cribbb using the repository.

If the id is valid we can return the View and the $cribbb.

If the id is not valid we can throw a 404 Not Found error.

Here is a simple view for displaying a single entity:

@if (Session::has('message'))
<div>{{ Session::get('message') }}</div>
@endif

<table>
    <tr>
        <th>Name</th>
        <td>{{ $cribbb->name }}</td>
    </tr>
</table>

In this view I’m simply echoing each attribute of the entity (in this case only the name!).

You will also notice that I’ve included another flash message at the top of the view. Again, don’t worry about this for now as I’ll mention it again soon.

The create method

The create() method has the sole purpose of displaying a form for creating a new entity:

/**
 * Display the form to create a new Cribbb
 *
 * @return View
 */
public function create()
{
    return View::make('cribbb.create');
}

All I’m doing here is returning a view.

Here is a basic create view:

@if ($errors->any())
<div>
<ul>
{{ implode(",", $errors->all('<li>:message</li>'))}}
</ul>
</div>
@endif

{{ Form::open(['route' => ['cribbb.store']]) }}
<div>
{{ Form::label('name', 'Name') }}
{{ Form::text('name', null) }}
</div>
<div>
{{ Form::submit('Create') }}
</div>
{{ Form::close() }}

In this view I’ve got a form that points to the cribbb.store method.

I’ve also included an unordered list that will display any errors with the input from the form when the form is submitted.

The store method

The store() method will accept the POST request from the form and attempt to create a new entity:

/**
 * Store a new Cribbb
 *
 * @return Redirect
 */
public function store()
{
    $cribbb = $this->cribbbRepository->create(Input::all());

    if ($cribbb) {
        return Redirect::route('cribbb.show', $cribbb->id)
            ->with('message', 'The cribbb has been created!');
    }

    return Redirect::route('cribbb.create')->withInput()
        ->withErrors($this->cribbbRepository->errors());
}

This method passes the Input::all() to the repository. If a new entity is successfully created it will be returned from the create() method.

If a new entity was created we can redirect to the show() method to display the new entity. You will notice I’m also passing a message. This message will be displayed in the flash message from earlier.

If no entity was created we can redirect back to the form with an array of errors that are retrieved from the repository.

Note: I’m assuming here that you have implemented the repository and validation that I’ve covered in previous tutorials.

The edit method

The edit() method will display a form to allow the user to edit an existing entity:

/**
 * Display the form to edit an existing Cribbb
 *
 * @param int $id
 * @return View
 */
public function edit($id)
{
    $cribbb = $this-> cribbb Repository->find($id);

    if ($cribbb) {
        return View::make('cribbb.edit', compact('cribbb'));
    }

    App::abort(404);
}

First we check to see if the id that was passed actually exists in the database. If the entity does exist we can return the view and embed the $cribbb.

If the id does not exist we can throw a 404.

An example of an edit view could be:

@if ($errors->any())
<div>
<ul>
{{ implode(",", $errors->all('<li>:message</li>'))}}
</ul>
</div>
@endif

{{ Form::model($cribbb, ['route' => ['cribbb.update', $cribbb->id],'method' => 'put']) }}
<div>
{{ Form::label('name', 'Name') }}
{{ Form::text('name', null) }}
</div>
<div>
{{ Form::submit('Update') }}
</div>
{{ Form::close() }}

This form will bind the current $cribbb to auto populate the form fields. You will notice that I’ve also specified that this form should use the PUT HTTP method.

Once again I will also include an unordered list to display any errors when the user submits the form.

The update method

The update() method will accept the PUT request and attempt to update the existing entity:

/**
 * Update an existing Cribbb
 *
 * @param int $id
 * @return Redirect
 */
public function update($id)
{
    $cribbb = $this->cribbbRepository->find($id);

    if ($cribbb) {
        $cribbb = $this->cribbbRepository->update(array_merge(['id' => $id], Input::all()));

        if ($cribbb) {
            return Redirect::route('cribbb.show', $id)
                ->with('message', 'The cribbb has been updated!');
        }

        return Redirect::route('cribbb.edit', $id)
            ->withInput()
            ->withErrors($this->cribbbRepository->errors());
    }

    App::abort(404);
}

First we check to see if the id is a valid entity id in the database. If the id is not valid we can just throw a 404 Not Found error.

Next we attempt to update the entity using the repository.

If the entity was successfully updated, the updated entity will be returned from the repository. We can then redirect to the show() method with a flash message.

If the entity failed to update we can redirect back to the edit() method with the errors. This will auto populate the form with the incorrect data so the user can correct her errors.

The delete method

The delete() method will display a form to allow the user to delete an entity from the database:

/**
 * Display the form to delete a Cribbb
 *
 * @return View
 */
public function delete($id)
{
    $cribbb = $this->cribbbRepository->find($id);

    if ($cribbb) {
        return View::make('cribbb.delete', compact('cribbb'));
    }

    App::abort(404);
}

First we check to see if the id actually exists. Again, if the id does not exist we can just throw a 404 Not Found error.

If the id does exist we can return the view and embed the $cribbb.

An example of a delete view could be:

<p>Are you sure you want to delete {{ $cribbb->name }}?</p>

{{ Form::open(['route' => ['cribbb.destroy', $cribbb->id], 'method' => 'delete']) }}
<button type="submit">Delete</button>
{{ Form::close() }}

This view has a form that can send the correct DELETE HTTP request to the destroy() method.

The destroy method

The destroy method will delete the entity through the repository:

/**
 * Destroy a Cribbb
 *
 * @return Redirect
 */
public function destroy($id)
{
    $cribbb = $this->cribbbRepository->find($id);

    if ($cribbb) {
        $this->cribbbRepository->delete($id);

        return Redirect::route('cribbb.index')
            ->with('message', "The $cribbb->name has been deleted!");
    }

    App::abort(404);
}

Once again we first check to ensure the id is valid. If the id is not valid we can throw a 404 Not Found response.

Next we can delete the entity by passing the id to the delete() method on the repository.

Finally we can redirect back to the index() method and pass a flash message as confirmation.

Conclusion

This basic CRUD template allows you to get up and running with your application in very little time. CRUD based applications are nearly always the same basic structure. By having boilerplate code that you can copy from one project to another you will end up saving yourself a lot of time getting the basics down first.

I think having boilerplate code like this really allows you to iterate on your ideas very quickly. By actually having something you can play with in your browser you can start working through your idea or showing it to a client or project owner.

This is a series of posts on building an entire Open Source application called Cribbb. All of the tutorials will be free to web, and all of the code is available on GitHub.

Philip Brown

@philipbrown

© Yellow Flag Ltd 2024.