Laravel tips del 4 – Accessors i Eloquent ORM

Marcus Olsson,

En fantastisk användbar funktion med Eloquent som ofta missas (om man går efter frågorna på Stack Overflow i alla fall) är Accessors.

Accessor kort och gott ett attribut som man kan sätta på en modell, ett attribut som saknar ett motsvarande fält i databasen.

Låt oss säga att du bygger en applikation som ska hantera bokningen av t.ex. lokaler (hade uthyrning av filmer som exempel först, men vem hyr fysiska filmer idag?) – man kan så klart ha ett boolean-fält som visar om lokalen är uthyrd eller ej, man i det här exemplet så använder vi ett start- och stoppdatum för bokningen, och använder en accessor för att se efter lokalen är tillgänglig just nu.

Först, en enkel migration, där vi har koll på vilken kund som hyr en viss lokal, start- och stoppdatum för bokningen:

1class CreateBookingsTable extends Migration {
2 public function up() {
3 Schema::create('bookings', function($table) {
4 $table->increments('id');
5 $table->integer('customer_id');
6 $table->integer('room_id');
7 $table->date('booked_from')->nullable();
8 $table->date('booked_to')->nullable();
9 $table->timestamps();
10 });
11 }
12}
13
14$ php artisan migrate
1class CreateBookingsTable extends Migration {
2 public function up() {
3 Schema::create('bookings', function($table) {
4 $table->increments('id');
5 $table->integer('customer_id');
6 $table->integer('room_id');
7 $table->date('booked_from')->nullable();
8 $table->date('booked_to')->nullable();
9 $table->timestamps();
10 });
11 }
12}
13
14$ php artisan migrate

Nu skapar vi vår accessor, vi använder Carbon för att enklare jämföra datum (notera att vi endast kollar av om bokningsdatumet är före eller efter "idag", i verkligheten skulle andra kontroller behövas också):

1use Carbon\Carbon;
2class Booking extends Eloquent {
3 public function getAvailableAttribute() {
4 $now = Carbon::now();
5 $bookedTo = Carbon::createFromFormat('Y-m-d', $this->booked_to);
6 $diff = $now->diffInDays($bookedTo, false);
7 if($diff >= 0) {
8 return false;
9 }
10 return true;
11 }
12}
1use Carbon\Carbon;
2class Booking extends Eloquent {
3 public function getAvailableAttribute() {
4 $now = Carbon::now();
5 $bookedTo = Carbon::createFromFormat('Y-m-d', $this->booked_to);
6 $diff = $now->diffInDays($bookedTo, false);
7 if($diff >= 0) {
8 return false;
9 }
10 return true;
11 }
12}

Så enkelt var det, nu kan vi enkelt kolla om en lokal i fråga är tillgänglig/bokad just nu.

1$room = Room::find(1);
2$room->available; // true/false beroende på bokningsdatum
1$room = Room::find(1);
2$room->available; // true/false beroende på bokningsdatum

Notera att accessors skapar "snake_case"-attribut:

1public function getIsAvailableAttribute() {
2 // Kod
3}
4
5$room = Room::find(1);
6$room->is_available;
1public function getIsAvailableAttribute() {
2 // Kod
3}
4
5$room = Room::find(1);
6$room->is_available;

Men om man vill hämta en Collection som JSON då, hur får man in accessorn då? Man använder helt enkelt $appends-attributet;

1protected $appends = array('is_available');
1protected $appends = array('is_available');

Notera att den här guiden använder Laravel 4.2, accessors 5.0 fungerar i princip likadant. Se dokumentationen för mer information.