I am working on a library application, and I want to create a function, where the user can check out a book to a customer. So I have 2 tables, books
and readers
and I have created a pivot table, called book_reader
as well to create the checkout method. However, I have some problems displaying the data from this table. I have read several articles about this, but they don't take in consideration that there is some data in the pivot table that contains new information and isn't just the joining of the 2 tables. I would be very appreciative if someone could help me with how I can display this data.
Models:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Book extends Model
{
protected $fillable = ['title', 'year', 'language_id', 'isbn', 'pages', 'user_id'];
public function readers()
{
return $this
->belongsToMany(Reader::class, 'book_reader')
->using(Checkout::class)
->withPivot(['returndate', 'maxreturndate']);
}
}
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Reader extends Model
{
protected $fillable = ['name', 'email', 'employee_number'];
public function books()
{
return $this
->belongsToMany(Book::class, 'book_reader')
->using(Checkout::class)
->withPivot(['returndate', 'maxreturndate']);
}
}
<?php
namespace App;
use Illuminate\Database\Eloquent\Relations\Pivot;
class Checkout extends Pivot
{
$table = "book_reader";
$dates = [
"maxreturndate",
"returndate",
];
}
Migrations:
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateCheckedOutsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('book_reader', function (Blueprint $table) {
$table->bigIncrements('id');
$table->bigInteger('book_id')->unsigned();
$table->foreign('book_id')->references('id')->on('books')->onDelete('cascade');
$table->bigInteger('reader_id')->unsigned();
$table->foreign('reader_id')->references('id')->on('readers')->onDelete('cascade');
$table->date('maxreturndate');
$table->date('returndate')->nullable();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('book_reader');
}
}
CheckedOutController:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Book;
use App\Reader;
use Illuminate\Support\Carbon;
class CheckedOutController extends Controller
{
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
*/
public function index()
{
$books = Book::doesntHave("readers")->get();
$readers = Reader::all();
return view('checkedouts/index', compact('books','readers'));
}
index.blade.php:
@foreach($readers->books as $book)
<tr>
<td>{{$book->pivot->id}}</td>
<td>{{$book->pivot->title}}</td>
<td>{{$book->pivot->name}}</td>
<td>{{$book->pivot->created_at}}</td>
<td >{{$book->pivot->maxreturndate}}</td>
<td>{{$book->pivot->returndate}}</td>
<td></td>
Your pivot table contains only returndate
and maxreturndate
as well as the default timestamps; why are you trying to get title
and name
from the pivot property? You don't say what your "problems" are, but I expect that would be one of them.
See here for an example of this setup working: https://implode.io/1OCqbL
On a more general note, since you've set up the relationship as many-to-many, you get the advantages of the pivot table. In reality, your book will not be checked out by more than one person so it might make sense to have an accessor set up as a sort of pseudo-relationship:
public function getReaderAttribute()
{
return $this->readers->first();
}
Now you can refer to $book->reader->pivot
where it's appropriate.
You may want to do the same with return date:
public function getReturndateAttribute()
{
return $this->reader ? $this->reader->pivot->returndate : null;
}
So you can easily get the return date of a book that's checked out.