Pracuję nad aplikacją biblioteczną i chcę stworzyć funkcję, w której użytkownik może wypożyczyć książkę klientowi. Jednak chcę, aby wypożyczone książki nie pojawiały się w polu wyboru podczas wypożyczania kolejnej książki. Wyszukałem kilka artykułów na ten temat, ale nie mogłem znaleźć rozwiązania, więc byłbym zadowolony z jakiejkolwiek pomocy. Chodzi o to, że jeśli książka ma ustawiony atrybut „maxreturndate”, nie zostanie wyświetlona.

CheckedOutController:

    <?php

    namespace App\Http\Controllers;

    use Illuminate\Http\Request;
    use App\CheckedOut;
    use App\Book;
    use App\Reader;



    class CheckedOutController extends Controller
    {
        /**
         * Display a listing of the resource.
         *
         * @return \Illuminate\Http\Response
         */
        public function index()
        {
            $checkedOuts = CheckedOut::with(['book', 'reader'])->get();

            return view('checkedouts/index', compact('checkedOuts'));
        }

        /**
         * Show the form for creating a new resource.
         *
         * @return \Illuminate\Http\Response
         */
        public function create()
        {
            $books = Book::all();
            $readers = Reader::all();

            return view('checkedouts/create', compact('books','readers'));
        }

        /**
         * Store a newly created resource in storage.
         *
         * @param  \Illuminate\Http\Request  $request
         * @return \Illuminate\Http\Response
         */
        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 \Illuminate\Http\Response
         */
        public function show($id)
        {
            //
        }

        /**
         * Show the form for editing the specified resource.
         *
         * @param  int  $id
         * @return \Illuminate\Http\Response
         */
        public function edit($id)
        {
            //
        }

        /**
         * Update the specified resource in storage.
         *
         * @param  \Illuminate\Http\Request  $request
         * @param  int  $id
         * @return \Illuminate\Http\Response
         */
        public function update(Request $request, $id)
        {
            //
        }

        /**
         * Remove the specified resource from storage.
         *
         * @param  int  $id
         * @return \Illuminate\Http\Response
         */
        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

Migracje:

<?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('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');
    }
}

create.blade.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

Relacja między trzema modelami:

Książka:

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

Czytelnik:

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

Wyrejestrowany:

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

}

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

}
0
mekol 10 marzec 2020, 23:21

2 odpowiedzi

Najlepsza odpowiedź

Sugeruję, aby skonfigurować Books i Readers z relacja wiele-do-wielu. Teraz twoje modele mogą wyglądać tak:

<?php
namespace App;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\Pivot;

class Book extends Model
{
    public function readers()
    {
        return $this
            ->belongsToMany(\App\Reader::class, 'checked_outs')
            ->using(\App\Checkout::class)
            ->withPivot(['returndate', 'maxreturndate']);
    }
}

class Reader extends Model
{
    public function books()
    {
        return $this
            ->belongsToMany(\App\Book::class, 'checked_outs')
            ->using(\App\Checkout::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",
    ];
}

utworzyłem model przestawny co nie jest konieczne, ale umożliwia działanie bezpośrednio na tabeli przestawnej i automatyczne rzutowanie dodatkowych atrybutów na daty. To, czy jest to przydatne, jest kwestią opinii. Powinieneś zmienić nazwę tabeli checked_outs na book_reader, co jest konwencją nazewnictwa, której Laravel oczekuje od tabeli przestawnej.

Pobieranie książek, które nie są wyewidencjonowane, jest wystarczająco proste, aby wykonać następujące czynności, używając doesntHave, aby sprawdzić brak relacji.

public function create()
{
    $books = Book::doesntHave("readers")->get();
    $readers = Reader::all();

    return view('checkedouts/create', compact('books','readers'));
}

A „pobranie” książki mogłoby wyglądać tak:

public function store(Request $request)
{
    $reader = Reader::find($request->reader_id);
    $reader
        ->books()
        ->attach(
            $request->book_id,
            ["returndate" => Carbon\Carbon::now()->addDays(7)]
        );
}
0
miken32 10 marzec 2020, 22:41

jeśli książka ma ustawiony atrybut „maxreturndate”, nie zostanie wyświetlona

Ponieważ nie określiłeś w swojej migracji, zakładam tutaj, że masz maxreturndate pole dopuszczające wartość null w swojej tabeli books, wtedy powinieneś być w stanie po prostu utworzyć lokalny zakres, jeśli chcesz mieć listę książek„ niewypożyczonych ”.

Oto przykład tworzenia zakresu 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'));
}
0
Helioarch 10 marzec 2020, 22:55