Laravel根据关系选择模型



我正在开发一个库应用程序,我想创建一个函数,用户可以在其中向客户出租一本书。然而,我希望现在出租的书在出租另一本书时不要出现在选择框中。我已经查阅了几篇关于这方面的文章,但无法真正找到解决方案,所以我很乐意得到任何帮助。其想法是,当一本书设置了属性"maxreturndate"时,它就不会出现。

CheckedOutController:

<?php
namespace AppHttpControllers;
use IlluminateHttpRequest;
use AppCheckedOut;
use AppBook;
use AppReader;

class CheckedOutController extends Controller
{
/**
* Display a listing of the resource.
*
* @return IlluminateHttpResponse
*/
public function index()
{
$checkedOuts = CheckedOut::with(['book', 'reader'])->get();
return view('checkedouts/index', compact('checkedOuts'));
}
/**
* Show the form for creating a new resource.
*
* @return IlluminateHttpResponse
*/
public function create()
{
$books = Book::all();
$readers = Reader::all();
return view('checkedouts/create', compact('books','readers'));
}
/**
* Store a newly created resource in storage.
*
* @param  IlluminateHttpRequest  $request
* @return IlluminateHttpResponse
*/
public function store(Request $request)
{
$validatedData = $request->validate([
'book_id' => 'required',
'reader_id' => 'required',
'maxreturndate' => 'required|date',
'returndate' => 'nullable',
]);
$checkedOut = CheckedOut::create($validatedData);
return redirect('checkedouts')->with('success', 'Buch wurde erfolgreich verliehen!');
}
/**
* Display the specified resource.
*
* @param  int  $id
* @return IlluminateHttpResponse
*/
public function show($id)
{
//
}
/**
* Show the form for editing the specified resource.
*
* @param  int  $id
* @return IlluminateHttpResponse
*/
public function edit($id)
{
//
}
/**
* Update the specified resource in storage.
*
* @param  IlluminateHttpRequest  $request
* @param  int  $id
* @return IlluminateHttpResponse
*/
public function update(Request $request, $id)
{
//
}
/**
* Remove the specified resource from storage.
*
* @param  int  $id
* @return IlluminateHttpResponse
*/
public function destroy($id)
{
//
}
}

index.blade.php

@extends('layout')

@section('title')
<title>Alle ausgeliehen Bücher</title>
@section('content')
<style>
.uper {
margin-top: 40px;
}
</style>
<div class="uper">
@if(session()->get('success'))
<div class="alert alert-success">
{{ session()->get('success') }}
</div><br />
@endif
<table class="table table-hover">
<thead>
<tr>
<td>ID</td>
<td>Titel</td>
<td>Verliehen an</td>
<td>Verleihdatum</td>
<td>Fällig am</td>
<td>Zurückgebracht am</td>
<td colspan="2">Funktionen</td>
</tr>
</thead>
<tbody>
@foreach($checkedOuts as $checkedOut)
<tr>
<td>{{$checkedOut->id}}</td>
<td>{{$checkedOut->book->title}}</td>
<td>{{$checkedOut->reader->name}}</td>
<td>{{$checkedOut->created_at}}</td>
<td >{{$checkedOut->maxreturndate}}</td>
<td>{{$checkedOut->returndate}}</td>
<td></td>
<td><a href="{{ route('checkedouts.edit', $checkedOut->id)}}" class="btn btn-primary">Bearbeiten</a></td>
<td><a href="{{ route('checkedouts.show', $checkedOut->id)}}" class="btn btn-primary">Anzeigen</a></td>
<td>
<form action="{{ route('checkedouts.destroy', $checkedOut->id)}}" method="post">
@csrf
@method('DELETE')
<button class="btn btn-danger" type="submit">Löschen</button>
</form>
</td>
</tr>
@endforeach
</tbody>
</table>
<div>
@endsection

迁移:

<?php
use IlluminateDatabaseMigrationsMigration;
use IlluminateDatabaseSchemaBlueprint;
use IlluminateSupportFacadesSchema;
class CreateCheckedOutsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('checked_outs', 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('checked_outs');
}
}

createblade.php

@extends('layout')

@section('title')
<title>Buch verleihen</title>
@section('stylesheets')
<script src="http://code.jquery.com/jquery-3.4.1.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/select2@4.0.13/dist/js/select2.min.js"></script>
<link href="https://cdn.jsdelivr.net/npm/select2@4.0.13/dist/css/select2.min.css" rel="stylesheet" />

@endsection
@section('content')
<style>
.uper {
margin-top: 40px;
}
</style>
<div class="card uper">
<div class="card-header">
Buch verleihen
</div>
<div class="card-body">
<form method="post" action="{{ route('checkedouts.store') }}">
<div class="form-group">
@csrf
<label for="book_id">Buch:</label>
<select name="book_id" class="form-control select2-single <!-- @error('book_id') is-invalid @enderror -->">
@foreach ($books as $book)
<option value="{{ $book->id }}">{{ $book->title }}</option>
@endforeach
</select>
@error('book_id')
<div class="alert alert-danger">{{ $message }}</div>
@enderror
</div>
<div class="form-group">
<label for="reader_id">Verleihen an:</label>
<select name="reader_id" class="form-control select2-single <!-- @error('reader_id') is-invalid @enderror -->">
@foreach ($readers as $reader)
<option value="{{ $reader->id }}">{{ $reader->name }}</option>
@endforeach
</select>
@error('reader_id')
<div class="alert alert-danger">{{ $message }}</div>
@enderror
</div>
<div class="form-group">
<label for="maxreturndate">Zurückbringen bis:</label>
<input type="date" class="form-control" name="maxreturndate" />
@error('name')
<div class="alert alert-danger">{{ $message }}</div>
@enderror
</div>
<button type="submit" class="btn btn-primary">Verleihen</button>
</form>
</div>
</div>
<script type="text/javascript">
$(".select2-single").select2();
</script>
@endsection

三种模型之间的关系:

书籍:

public function checkedOut(){
return $this->hasOne(CheckedOut::class);
}

读卡器:

public function checkedOut()
{
return $this->belongsTo(CheckedOut::class);
}

签出:

public function book(){
return $this->belongsTo(Book::class);
}
public function reader(){
return $this->belongsTo(Reader::class);
}

我的建议是设置具有多对多关系的BooksReaders。现在,你的模型可能是这样的:

<?php
namespace App;
use IlluminateDatabaseEloquentModel;
use IlluminateDatabaseEloquentRelationsPivot;
class Book extends Model
{
public function readers()
{
return $this
->belongsToMany(AppReader::class, 'checked_outs')
->using(AppCheckout::class)
->withPivot(['returndate', 'maxreturndate']);
}
}
class Reader extends Model
{
public function books()
{
return $this
->belongsToMany(AppBook::class, 'checked_outs')
->using(AppCheckout::class)
->withPivot(['returndate', 'maxreturndate']);
}
}
class Checkout extends Pivot
{
// this should be named `book_reader` but we override it here
$table = "checked_outs";
$dates = [
"maxreturndate",
"returndate",
];
}

我创建了一个数据透视模型,这是不必要的,但允许您直接对数据透视表进行操作,并将额外的属性自动转换为日期。这是否有用取决于意见。您应该将checked_outs表重命名为book_reader,这是Laravel期望的透视表的命名约定。

使用doesntHave方法来检查是否存在关系,获取未签出的书籍非常简单,如下所示。

public function create()
{
$books = Book::doesntHave("readers")->get();
$readers = Reader::all();
return view('checkedouts/create', compact('books','readers'));
}

"查看"一本书可能是这样的:

public function store(Request $request)
{
$reader = Reader::find($request->reader_id);
$reader
->books()
->attach(
$request->book_id,
["returndate" => CarbonCarbon::now()->addDays(7)]
);
}

当一本书设置了属性"maxreturndate"时,它不会显示

由于您没有在迁移中指定,我将在这里假设您的books表中有一个maxreturndate可为null的字段,那么当您想要"未租用"图书列表时,您应该能够简单地创建一个本地作用域。

以下是创建notRented作用域的示例:

// in your Book model define the local scope
public function scopeNotRented($query){
return $query->whereNotNull('maxreturndate');
}
// in the create method of your controller
public function create()
{
$books = Book::notRented()->get();
$readers = Reader::all();
return view('checkedouts/create', compact('books','readers'));
}

最新更新