Книга: Laravel 4 Cookbook
Назад: Deployment
Дальше: Packages

API

I seldom think of MVC in terms of applications which don’t really have views. Turns out Laravel 4 is stocked with features which make REST API’s a breeze to create and maintain.

The code for this chapter can be found at: https://github.com/formativ/tutorial-laravel-4-api

Dependencies

One of the goals, of this tutorial, is to speed up our prototyping. To that end; we’ll be installing Jeffrey Way’s Laravel 4 Generators. This can be done by amending the composer.json file to including the following dependency:

1 "way/generators" : "dev-master" 

This was extracted from composer.json.

We’ll also need to add the GeneratorsServiceProvider to our app config:

1 "Way\Generators\GeneratorsServiceProvider" 

This was extracted from app/config/app.php.

You should now see the generate methods when you run artisan.

Creating Resources With Artisan

Artisan has a few tasks which are helpful in setting up resourceful API endpoints. New controllers can be created with the command:

1 php artisan controller:make EventController 

New migrations can also be created with the command:

1 php artisan migrate:make CreateEventTable 

These are neat shortcuts but they’re a little limited considering our workflow. What would make us even more efficient is if we had a way to also generate models and seeders. Enter Jeffrey Way’s Laravel 4 Generators…

You can learn more about Laravel 4’s built-in commands by running php artisan in your console, or at: http://laravel.com/docs.

Creating Resources With Generators

With the generate methods installed; we can now generate controllers, migrations, seeders and models.

Generating Migrations

Let’s begin with the migrations:

1 php artisan generate:migration create_event_table 

This simple command will generate the following migration code:

 1 <?php  2   3 use Illuminate\Database\Migrations\Migration;  4 use Illuminate\Database\Schema\Blueprint;  5   6 class CreateEventTable extends Migration {  7   8     /**  9     * Run the migrations. 10     * 11     * @return void 12     */ 13     public function up() 14     { 15         Schema::create('event', function(Blueprint $table) { 16             $table->increments('id'); 17   18             $table->timestamps(); 19         }); 20     } 21  22     /** 23     * Reverse the migrations. 24     * 25     * @return void 26     */ 27     public function down() 28     { 29         Schema::drop('event'); 30     } 31 } 

This file should be saved as app/database/migrations/00000000_000000_create_event_table.php.

We’ve seen these kinds of migrations before, so there’s not much to say about this one. The generators allow us to take it a step further by providing field names and types:

1 php artisan generate:migration --fields="name:string, description:text, started_a\ 2 t:timestamp, ended_at:timestamp" create_event_table 

This command alters the up() method previously generated:

 1 public function up()  2 {  3     Schema::create('event', function(Blueprint $table) {  4         $table->increments('id');  5         $table->string('name');  6         $table->text('description');  7         $table->timestamp('started_at');  8         $table->timestamp('ended_at');  9         $table->timestamps(); 10     }); 11 } 

This was extracted from app/database/migrations/0000000000_0000000_create_event_table.php.

Similarly, we can create tables for sponsors and event categories:

1 php artisan generate:migration --fields="name:string, description:text" create_ca\ 2 tegory_table 3  4 php artisan generate:migration --fields="name:string, url:string, description:tex\ 5 t" create_sponsor_table 6 These commands generate the following migrations: 
 1 <?php  2   3 use Illuminate\Database\Migrations\Migration;  4 use Illuminate\Database\Schema\Blueprint;  5   6 class CreateCategoryTable extends Migration {  7   8     /**  9     * Run the migrations. 10     * 11     * @return void 12     */ 13     public function up() 14     { 15         Schema::create('category', function(Blueprint $table) { 16             $table->increments('id'); 17             $table->string('name'); 18             $table->text('description'); 19             $table->timestamps(); 20         }); 21     } 22  23     /** 24     * Reverse the migrations. 25     * 26     * @return void 27     */ 28     public function down() 29     { 30         Schema::drop('category'); 31     } 32 } 

This file should be saved as app/database/migrations/00000000_000000_create_category_table.php.

 1 <?php  2   3 use Illuminate\Database\Migrations\Migration;  4 use Illuminate\Database\Schema\Blueprint;  5   6 class CreateSponsorTable extends Migration {  7   8     /**  9     * Run the migrations. 10     * 11     * @return void 12     */ 13     public function up() 14     { 15         Schema::create('sponsor', function(Blueprint $table) { 16             $table->increments('id'); 17             $table->string('name'); 18             $table->string('url'); 19             $table->text('description'); 20             $table->timestamps(); 21         }); 22     } 23  24     /** 25     * Reverse the migrations. 26     * 27     * @return void 28     */ 29     public function down() 30     { 31         Schema::drop('sponsor'); 32     } 33 } 

This file should be saved as app/database/migrations/00000000_000000_create_sponsor_table.php.

The last couple of migrations we need to create are for pivot tables to connect sponsors and categories to events. Pivot tables are common in HABTM (Has And Belongs To Many) relationships, between database entities.

The command for these is just as easy:

1 php artisan generate:pivot event category 2  3 php artisan generate:pivot event sponsor 4 These commands generate the following migrations: 
 1 <?php  2   3 use Illuminate\Database\Migrations\Migration;  4 use Illuminate\Database\Schema\Blueprint;  5   6 class PivotCategoryEventTable extends Migration {  7   8     /**  9     * Run the migrations. 10     * 11     * @return void 12     */ 13     public function up() 14     { 15         Schema::create('category_event', function(Blueprint $table) { 16             $table->increments('id'); 17             $table->integer('category_id')->unsigned()->index(); 18             $table->integer('event_id')->unsigned()->index(); 19             $table->foreign('category_id')->references('id')->on('category')->onD\ 20 elete('cascade'); 21             $table->foreign('event_id')->references('id')->on('event')->onDelete(\ 22 'cascade'); 23         }); 24     } 25  26     /** 27     * Reverse the migrations. 28     * 29     * @return void 30     */ 31     public function down() 32     { 33         Schema::drop('category_event'); 34     } 35 } 

This file should be saved as app/database/migrations/00000000_000000_pivot_category_event_table.php.

 1 <?php  2   3 use Illuminate\Database\Migrations\Migration;  4 use Illuminate\Database\Schema\Blueprint;  5   6 class PivotEventSponsorTable extends Migration {  7   8     /**  9     * Run the migrations. 10     * 11     * @return void 12     */ 13     public function up() 14     { 15         Schema::create('event_sponsor', function(Blueprint $table) { 16             $table->increments('id'); 17             $table->integer('event_id')->unsigned()->index(); 18             $table->integer('sponsor_id')->unsigned()->index(); 19             $table->foreign('event_id')->references('id')->on('event')->onDelete(\ 20 'cascade'); 21             $table->foreign('sponsor_id')->references('id')->on('sponsor')->onDel\ 22 ete('cascade'); 23         }); 24     } 25  26     /** 27     * Reverse the migrations. 28     * 29     * @return void 30     */ 31     public function down() 32     { 33         Schema::drop('event_sponsor'); 34     } 35 } 

This file should be saved as app/database/migrations/00000000_000000_pivot_event_sponsor_table.php.

Pay special attention to the names of the tables in the calls to the on() method. I have changed them from plural tables names to singular table names. The templates used to construct these constraints don’t seem to take into account the name of the table on which the constrains are being created.

Apart from the integer fields (which we’ve seen before); these pivot tables also have foreign keys, with constraints. These are common features of relational databases, as they help to maintain referential integrity among database entities.

These migrations specify foreign key constraints. This means the database will require valid foreign keys when you insert and update rows in these tables. Your seeder class needs to provide these valid ID values, or you should remove the constraints (references(‘id’)…onDelete(‘cascade’)).

With all these migration files created; we have only to migrate them to the database with:

1 php artisan migrate 

(This assumes you have already configured the database connection details, in the configuration files.)

Generating Seeders

Seeders are next on our list. These will provide us with starting data; so our API responses don’t look so empty.

1 php artisan generate:seed Category 2 php artisan generate:seed Sponsor 

These commands will generate stub seeders, and add them to the DatabaseSeeder class. I have gone ahead and customised them to include some data (and better formatting):

 1 <?php  2   3 class CategoryTableSeeder  4 extends Seeder  5 {  6     public function run()  7     {  8         DB::table("category")->truncate();  9  10         $categories = [ 11             [ 12                 "name"        => "Concert", 13                 "description" => "Music for the masses.", 14                 "created_at"  => date("Y-m-d H:i:s"), 15                 "updated_at"  => date("Y-m-d H:i:s") 16             ], 17             [ 18                 "name"        => "Competition", 19                 "description" => "Prizes galore.", 20                 "created_at"  => date("Y-m-d H:i:s"), 21                 "updated_at"  => date("Y-m-d H:i:s") 22             ], 23             [ 24                 "name"        => "General", 25                 "description" => "Things of interest.", 26                 "created_at"  => date("Y-m-d H:i:s"), 27                 "updated_at"  => date("Y-m-d H:i:s") 28             ] 29         ]; 30  31         DB::table("category")->insert($categories); 32     } 33 } 

This file should be saved as app/database/seeds/CategoryTableSeeder.php.

 1 <?php  2   3 class SponsorTableSeeder  4 extends Seeder  5 {  6     public function run()  7     {  8         DB::table("sponsor")->truncate();  9  10         $sponsors = [ 11             [ 12                 "name"        => "ACME", 13                 "description" => "Makers of quality dynomite.", 14                 "url"         => "http://www.kersplode.com", 15                 "created_at"  => date("Y-m-d H:i:s"), 16                 "updated_at"  => date("Y-m-d H:i:s") 17             ], 18             [ 19                 "name"        => "Cola Company", 20                 "description" => "Making cola like no other.", 21                 "url"         => "http://www.cheerioteeth.com", 22                 "created_at"  => date("Y-m-d H:i:s"), 23                 "updated_at"  => date("Y-m-d H:i:s") 24             ], 25             [ 26                 "name"        => "MacDougles", 27                 "description" => "Super sandwiches.", 28                 "url"         => "http://www.imenjoyingit.com", 29                 "created_at"  => date("Y-m-d H:i:s"), 30                 "updated_at"  => date("Y-m-d H:i:s") 31             ] 32         ]; 33  34         DB::table("sponsor")->insert($sponsors); 35     } 36 } 

This file should be saved as app/database/seeds/SponsorTableSeeder.php.

To get this data into the database, we need to run the seed command:

1 php artisan db:seed 

If you kept the foreign key constraints (in the pivot table migrations); you will need to modify your seeder classes to include valid foreign keys.

At this point; we should have the database tables set up, and some test data should be in the category and sponsor tables.

Generating Models

Before we can output data, we need a way to interface with the database. We’re going to use models for this purpose, so we should generate some:

1 php artisan generate:model Event 2  3 php artisan generate:model Category 4  5 php artisan generate:model Sponsor 

These commands will generate stub models which resemble the following:

1 <?php 2  3 class Event extends Eloquent { 4  5     protected $guarded = array(); 6  7     public static $rules = array(); 8 } 

This file should be saved as app/models/Event.php.

We need to clean these up a bit, and add the relationship data in…

 1 <?php  2   3 class Event  4 extends Eloquent  5 {  6     protected $table = "event";  7    8     protected $guarded = [  9         "id", 10         "created_at", 11         "updated_at" 12     ]; 13  14     public function categories() 15     { 16         return $this->belongsToMany("Category", "category_event", "event_id", "ca\ 17 tegory_id"); 18     } 19  20     public function sponsors() 21     { 22         return $this->belongsToMany("Sponsor", "event_sponsor", "event_id", "spon\ 23 sor_id"); 24     } 25 } 

This file should be saved as app/models/Event.php.

 1 <?php  2   3 class Category  4 extends Eloquent  5 {  6     protected $table = "category";  7    8     protected $guarded = [  9         "id", 10         "created_at", 11         "updated_at" 12     ]; 13  14     public function events() 15     { 16         return $this->belongsToMany("Event", "category_event", "category_id", "ev\ 17 ent_id"); 18     } 19 } 

This file should be saved as app/models/Category.php.

 1 <?php  2   3 class Sponsor  4 extends Eloquent  5 {  6     protected $table = "sponsor";  7    8     protected $guarded = [  9         "id", 10         "created_at", 11         "updated_at" 12     ]; 13  14     public function events() 15     { 16         return $this->belongsToMany("Event", "event_sponsor", "sponsor_id", "even\ 17 t_id"); 18     } 19 } 

This file should be saved as app/models/Sponsor.php.

As I mentioned before; we’ve gone with a belongsToMany() relationship to connect the entities together. The arguments for each of these is (1) the model name, (2) the pivot table name, (3) the local key and (4) the foreign key.

I refer to them as the local and foreign keys but they are actually both foreign keys on the pivot table. Think of local as the key closest to the model in which the relationship is defined and the foreign as the furthest.

Our models’ $table property should match what’s specified in the migrations and seeders.

The last step in creating our API is to create the client-facing controllers.

Generating Controllers

The API controllers are different from those you might typically see, in a Laravel 4 application. They don’t load views; rather they respond to the requested content type. They don’t typically cater for multiple request types within the same action. They are not concerned with interface; but rather translating and formatting model data.

Creating them is a bit more tricky than the other classes we’ve done so far:

1 php artisan generate:controller EventController 

The command isn’t much different, but the generated file is far from ready:

 1 <?php  2 class EventController extends BaseController {  3   4     /**  5     * Display a listing of the resource.  6     *  7     * @return Response  8     */  9     public function index() 10     { 11         return View::make('events.index'); 12     } 13  14     /** 15     * Show the form for creating a new resource. 16     * 17     * @return Response 18     */ 19     public function create() 20     { 21         return View::make('events.create'); 22     } 23  24     /** 25     * Store a newly created resource in storage. 26     * 27     * @return Response 28     */ 29     public function store() 30     { 31         // 32     } 33  34     /** 35     * Display the specified resource. 36     * 37     * @param int $id 38     * @return Response 39     */ 40     public function show($id) 41     { 42         return View::make('events.show'); 43     } 44  45     /** 46     * Show the form for editing the specified resource. 47     * 48     * @param int $id 49     * @return Response 50     */ 51     public function edit($id) 52     { 53         return View::make('events.edit'); 54     } 55  56     /** 57     * Update the specified resource in storage. 58     * 59     * @param int $id 60     * @return Response 61     */ 62     public function update($id) 63     { 64         // 65     } 66  67     /** 68     * Remove the specified resource from storage. 69     * 70     * @param int $id 71     * @return Response 72     */ 73     public function destroy($id) 74     { 75         // 76     } 77 } 

This file should be saved as app/controllers/EventController.php.

We’ve not going to be rendering views, so we can remove those statements/actions. We’re also not going to deal just with integer ID values (we’ll get to the alternative shortly).

For now; what we want to do is list events, create them, update them and delete them. Our controller should look similar to the following:

 1 <?php  2   3 class EventController  4 extends BaseController  5 {     6     public function index()  7     {  8         return Event::all();  9     } 10  11     public function store() 12     { 13         return Event::create([ 14             "name"        => Input::get("name"), 15             "description" => Input::get("description"), 16             "started_at"  => Input::get("started_at"), 17             "ended_at"    => Input::get("ended_at") 18         ]); 19     } 20  21     public function show($event) 22     { 23         return $event; 24     } 25  26     public function update($event) 27     { 28         $event->name        = Input::get("name"); 29         $event->description = Input::get("description"); 30         $event->started_at  = Input::get("started_at"); 31         $event->ended_at    = Input::get("ended_at"); 32         $event->save(); 33         return $event; 34     } 35  36     public function destroy($event) 37     { 38         $event->delete(); 39         return Response::json(true); 40     } 41 } 

This file should be saved as app/controllers/EventController.php.

We’ve deleted a bunch of actions and added some simple logic in others. Our controller will list (index) events, show them individually, create (store) them, update them and delete (destroy) them.

We need to return a JSON response differently, for the destroy() action, as boolean return values do not automatically map to JSON responses in the same way as collections and models do.

You can optionally specify the template to be used in the creation of seeders, models and controllers. you do this by providing the –template option with the path to a Mustache template file. Unfortunately migrations do not have this option. If you find yourself using these generators often enough, and wanting to customise the way in which new class are created; you will probably want to take a look at this option (and the template files in vendor/way/generators/src/Way/Generators/Generators/templates).

You can find out more about Jeffrey Way’s Laravel 4 Generators at: https://github.com/JeffreyWay/Laravel-4-Generators.

Binding Models To Routes

Before we can access these; we need to add routes for them:

 1 Route::model("event", "Event");  2   3 Route::get("event", [  4     "as"   => "event/index",  5     "uses" => "EventController@index"  6 ]);  7   8 Route::post("event", [  9     "as"   => "event/store", 10     "uses" => "EventController@store" 11 ]); 12  13 Route::get("event/{event}", [ 14     "as"   => "event/show", 15     "uses" => "EventController@show" 16 ]); 17  18 Route::put("event/{event}", [ 19     "as"   => "event/update", 20     "uses" => "EventController@update" 21 ]); 22  23 Route::delete("event/{event}", [ 24     "as"   => "event/destroy", 25     "uses" => "EventController@destroy" 26 ]); 

This was extracted from app/routes.php.

There are two important things here:

  1. We’re binding a model parameter to the routes. What that means is that we are telling Laravel to look for a specific parameter (in this case event) and treat the value found as an ID. Laravel will attempt to return a model instance if it finds that parameter in a route.
  2. We’re using different request methods to do perform different actions on our events. GET requests retrieve data, POST requests store data. PUT requests update data and DELETE requests delete data. This is called REST (Representational State Transfer).

Laravel 4 does support the PATCH method, though it’s undocumented. Many API’s support/use the PUT method when what they implement is the closer to the PATCH method. That’s a discussion for elsewhere; but just know you could use both without modification to Laravel 4.

You can find out more about Route Model Binding at: http://laravel.com/docs/routing#route-model-binding.

Troubleshooting Aliases

If you go to the index route; you will probably see an error. It might say something like “Call to undefined method IlluminateEventsDispatcher::all()”. This is because there is already a class (or rather an alias) called Event. Event is the name of our model, but instead of calling the all() method on our model; it’s trying to call it on the event disputer class baked into Laravel 4.

I’ve lead us to this error intentionally, to demonstrate how to overcome it if you ever have collisions in your applications. Most everything in Laravel 4 is in a namespace. However, to avoid lots of extra keystrokes; Laravel 4 also offers a configurable list of aliases (in app/config/app.php).

In the list of aliases; you will see an entry which looks like this:

1 'Event' => 'Illuminate\Support\Facades\Event', 

This was extracted from app/config/app.php.

I changed the key of that entry to Events but you can really call it anything you like.

It’s often just easier to change the name of the classes you create than it is to alter the aliases array. There are many Laravel 4 tutorials that will refer to these classes by their alias, so you’ll need to keep a mental log-book of the aliases you’ve changed and where they might be referred to.

Testing Endpoints

It’s not always easy to test REST API’s simply by using the browser. Often you will need to use an application to perform the different request methods. Thankfully modern *nix systems already have the Curl library, which makes these sorts of tests easier.

You can test the index endpoint with the console command:

1 curl http://dev.tutorial-laravel-4-api/event 

Your host (domain) name will differ based on your own setup.

You should only be seeing a JSON response - if you’re seeing HTML there’s a good chance it’s a Laravel error page. Check your application logs for more details.

Unless you’ve manually populated the event table, or set up a seeder for it; you should see an empty JSON array. This is a good thing, and also telling of some Laravel 4 magic. Our index() action returns a collection, but it’s converted to JSON output when passed in a place where a Response is expected.

Let’s add a new event:

1 curl -X POST -d "name=foo&description=a+day+of+foo&started_at=2013-10-03+09:00&en\ 2 ded_at=2013-10-03+12:00" http://dev.tutorial-laravel-4-api:2080/event 

..now, when we request the index() action, we should see the new event has been added. We can retrieve this event individually with a request similar to this:

1 curl http://dev.tutorial-laravel-4-api:2080/event/1 

There’s a lot going on here. Remember how we bound the model to a specific parameter name (in app/routes.php)? Well Laravel 4 sees that ID value, matches it to the bound model parameter and fetches the record from the database. If the ID does not match any of the records in the database; Laravel will respond with a 404 error message.

If the record is found; Laravel returns the model representation to the action we specified, and we get a model to work with.

Let’s update this event:

1 curl -X PUT -d "name=best+foo&description=a+day+of+the+best+foo&started_at=2013-1\ 2 0-03+10:00&ended_at=2013-10-03+13:00" http://dev.tutorial-laravel-4-api:2080/even\ 3 t/1 

Notice how all that’s changed is the data and the request type — even though we’re doing something completely different behind the scenes.

Lastly, let’s delete the event:

1 curl -X DELETE http://dev.tutorial-laravel-4-api:2080/event/1 

Feel free to set the same routes and actions up for categories and sponsors. I’ve not covered them here, for the sake of time, but they only differ in terms of the fields.

Authenticating Requests

So far we’ve left the API endpoints unauthenticated. That’s ok for internal use but it would be far more secure if we were to add an authentication layer.

We do this by securing the routes in filtered groups, and checking for valid credentials within the filter:

1 Route::group(["before" => "auth"], function() 2 { 3     // ...routes go here 4 }); 

This was extracted from app/routes.php.

1 Route::filter("auth", function() 2 { 3     // ...get database user 4  5     if (Input::server("token") !== $user->token) 6     { 7         App::abort(400, "Invalid token"); 8     } 9 }); 

This was extracted from app/filters.php.

Your choice for authentication mechanisms will greatly affect the logic in your filters. I’ve opted not to go into great detail with regards to how the tokens are generated and users are stored. Ultimately; you can check for token headers, username/password combos or even IP addresses.

What’s important to note here is that we check for this thing (tokens in this case) and if they do not match those stored in user records, we abort the application execution cycle with a 400 error (and message).

You can find out more about filters at: http://laravel.com/docs/routing#route-filters.

Using Accessors And Mutators

There are times when we need to customise how model attributes are stored and retrieved. Laravel 4 lets us do that by providing specially named methods for accessors and mutators:

 1 public function setNameAttribute($value)  2 {  3     $clean = preg_replace("/\W/", "", $value);  4     $this->attributes["name"] = $clean;  5 }  6   7 public function getDescriptionAttribute()  8 {  9     return trim($this->attributes["description"]); 10 } 

This was extracted from app/models/Event.php.

You can catch values, before they hit the database, by creating public set*Attribute() methods. These should transform the $value in some way and commit the change to the internal $attributes array.

You can also catch values, before they are returned, by creating get*Attribute() methods.

In the case of these methods; I am removing all non-word characters from the name value, before it hits the database; and trimming the description before it’s returned by the property accessor. Getters are also called by the toArray() and toJson() methods which transform model instances into either arrays or JSON strings.

You can also add attributes to models by creating accessors and mutators for them, and mentioning them in the $appends property:

 1 protected $appends = ["hasCategories", "hasSponsors"];  2   3 public function getHasCategoriesAttribute()  4 {  5     $hasCategories = $this->categories()->count() > 0;  6     return $this->attributes["hasCategories"] = $hasCategories;  7 }  8   9 public function getHasSponsorsAttribute() 10 { 11     $hasSponsors = $this->sponsors()->count() > 0; 12     return $this->attributes["hasSponsors"] = $hasSponsors; 13 } 

This was extracted from app/models/Event.php.

Here we’ve created two new accessors which check the count for categories and sponsors. We’ve also added those two attributes to the $appends array so they are returned when we list (index) all events or specific (show) events.

You can find out more about attribute accessor and mutators at: http://laravel.com/docs/eloquent#accessors-and-mutators.

Using Cache

Laravel 4 provides a great cache mechanism. It’s configured in the same was as the database:

 1 <?php  2   3 return [  4     "driver"    => "memcached",  5     "memcached" => [  6         [  7             "host"   => "127.0.0.1",  8             "port"   => 11211,  9             "weight" => 100 10         ] 11     ], 12     "prefix" => "laravel" 13 ]; 

This file should be saved as app/config/cache.php.

I’ve configured my cache to use the Memcached provider. This needs to be running on the specified host (at the specified port) in order for it to work.

Installing and running Memcached are outside the scope of this tutorial. It’s complicated.

No matter the provider you choose to use; the cache methods work the same way:

1 public function index() 2 { 3     return Cache::remember("events", 15, function() 4     { 5         return Event::all(); 6     }); 7 } 

This was extracted from app/controllers/EventController.php.

The Cache::remember() method will store the callback return value in cache if it’s not already there. We’ve set it to store the events for 15 minutes.

The primary use for cache is in key/value storage:

 1 public function total()  2 {  3     if (($total = Cache::get("events.total")) == null)  4     {  5         $total = Event::count();  6         Cache::put("events.total", $total, 15);  7     }  8   9     return Response::json((int) $total); 10 } 

This was extracted from app/controllers/EventController.php.

You can also invoke this cache on Query Builder queries or Eloquent queries:

1 public function today() 2 { 3     return Event::where(DB::raw("DAY(started_at)"), date("d")) 4         ->remember(15) 5         ->get(); 6 } 

This was extracted from app/controllers/EventController.php.

…we just need to remember to add the remember() method before we call the get() or first() methods.

You can find out more about cache at: http://laravel.com/docs/cache.

Назад: Deployment
Дальше: Packages