// 테이블 검증
$table = Table::findOrFail($request->table_id);
if ($request->guest_number > $table->guest_number) {
    return back()->with('warning', 'Please choose the table base on guests');
}

Table 모델에서 요청된 id로 데이터를 조회 한다.

특정 조건 값과 비교해서 다시 뒤로 넘긴다.

 

// 중복 예약 검증
$request_date = Carbon::parse($request->res_date);
foreach ($table->reservations as $res) {
    if ($res->res_date->format('Y-m-d') == $request_date->format('Y-m-d')) {
        return back()->with('warning', 'This table is reserved for this date.');
    }
}

넘겨 받은 날짜 데이터가 현재 Table 모델에 있는지 여부를 확인 한다. (이미 있는 값인지 확인하기)

폼 형태

<div class="sm:col-span-6">
    <label for="res_date" class="block text-sm font-medium text-gray-700"> Reservation Date </label>
    <div class="mt-1">
      <input type="datetime-local" id="res_date" name="res_date" class="block w-full transition duration-150 ease-in-out appearance-none bg-white border border-gray-400 rounded-md py-2 px-3 text-base leading-normal transition duration-150 ease-in-out sm:text-sm sm:leading-5
      @error('res_date') border-red-400 @enderror" />
    </div>
    @error('res_date')
      <div class="text-sm text-red-400">{{ $message }}</div>
    @enderror
</div>

 

조건 : res_date의 값은 오늘로부터 일주일 이내 여야 하고 시간은 17시부터 23시 사이여야 한다.

 

날짜를 검증하는 rule과 시간을 검증하는 rule 생성

php artisan make:rule DateBetween
php artisan make:rule TimeBetween

 

app > Rules > DateBetween.php

class DateBetween implements Rule
{
    public function __construct()
    {
        //
    }

    public function passes($attribute, $value)
    {
        $pickupDate = Carbon::parse($value);
        $lastDate = Carbon::now()->addWeek();

        return $value >= now() && $value <= $lastDate;
    }

    public function message()
    {
        return 'Please choose the date between a week from now.';
    }
}

 

app > Rules > TimeBetween.php

class TimeBetween implements Rule
{
    public function __construct()
    {
        //
    }

    public function passes($attribute, $value)
    {
        $pickupDate = Carbon::parse($value);
        $pickupTime = Carbon::createFromTime($pickupDate->hour, $pickupDate->minute, $pickupDate->second);
        // when the restaurant is open
        $earliesTime = Carbon::createFromTimeString('17:00:00');
        $lastTime = Carbon::createFromTimeString('23:00:00');

        return $pickupTime->between($earliesTime, $lastTime) ? true : false;
    }

    public function message()
    {
        return 'Please choose the time between 17:00-23:00.';
    }
}

 

app > Http > Requests > ReservationStoreRequest.php

위에서 작성한 rule을 request에서 사용한다.

 

날짜를 검증한 경우
시간을 검증한 경우

 

좌석(Table)은 여러 개의 예약(Reservation)을 갖을 수 있다.

 

Table Model

reservations 메서드에 Reservation에 대하여 hasMany()로 연결해준다.

Reservation Model

table() 메서드에 belongsTo() 메서드로 Table class와 연결 해준다.

 

Reservation 컨트롤러

 

컨트롤러에서 reservation에 대하여 연결된 모든 것을 조회 한다.

 

view 에서 reservation에 연결된 table 의 name 값을 보여줄 수 있다.

 
<div class="mt-1">
  <input type="text" id="name" name="name" 
    class="block w-full transition duration-150 ease-in-out appearance-none bg-white border border-gray-400 rounded-md py-2 px-3 text-base leading-normal transition duration-150 ease-in-out sm:text-sm sm:leading-5
    @error('name') border-red-400 @enderror" />
</div>
@error('name')
  <div class="text-sm text-red-400">{{ $message }}</div>
@enderror

 

 

아래 코드는 input 요소의 클래스에 넣어준다.

border-red-400은 수정해서 넣고싶은 스타일을 지정해주면 된다.

@error('name') border-red-400 @enderror

 

input 요소의 name 값에 맞춰 사용 할 수 있다.

@error('name')
  <div class="text-sm text-red-400">{{ $message }}</div>
@enderror

 

 

 

App의 하위경로에 폴더와 php파일을 생성한다.

Enums 폴더 생성

 

<?php

enum TableLocation: string
{
    case Front = 'front';
    case Inside = 'inside';
    case outside = 'outside';
}

 

Model에서 Enum 설정

use TableStatus;
use TableLocation;

class Table extends Model
{
    use HasFactory;

    protected $fillable = ['name', 'guest_number', 'status', 'location'];

    protected $casts = [
        'status' => TableStatus::class,
        'location' => TableLocation::class
    ];
}

$casts 변수에 Enum 클래스를 설정해주었다.

 

보통은 View에서 아래와 같은 방식으로 select 태그의 option 값을 지정 하지만

<select id="status" name="status" class="form-multiselect block w-full mt-1">
    <option value="pending">Pending</option>
    <option value="avaliable">Avalaiable</option>
    <option value="unavaliable">Unavaliable</option>
</select>

 

Enum에 지정한 값을 아래와 같이 불러와 사용 할 수 있다.

<select id="status" name="status" class="form-multiselect block w-full mt-1">
    @foreach (App\Enums\TableStatus::cases() as $status)
      <option value="{{ $status->value }}" @selected($table->status->value== $status->value)>{{ $status->name }}</option>
    @endforeach
</select>

 

 

-- 수정

데이터 수정 VIEW 페이지

<form method="POST" action="{{ route('admin.menus.update', $menu->id) }}" enctype="multipart/form-data">
  @csrf
  @method('PUT')
  <div class="sm:col-span-6">
    <label for="name" class="block text-sm font-medium text-gray-700"> Name </label>
    <div class="mt-1">
      <input type="text" id="name" name="name" value="{{ $menu->name }}"
        class="block w-full transition duration-150 ease-in-out appearance-none bg-white border border-gray-400 rounded-md py-2 px-3 text-base leading-normal transition duration-150 ease-in-out sm:text-sm sm:leading-5" />
    </div>
  </div>
  <div class="sm:col-span-6">
    <label for="title" class="block text-sm font-medium text-gray-700"> Image </label>
    <div>
      <img src="{{ Storage::url($menu->image) }}" alt="" class="w-32 h-32">
    </div>
    <div class="mt-1">
      <input type="file" id="image" name="image" 
        class="block w-full transition duration-150 ease-in-out appearance-none bg-white border border-gray-400 rounded-md py-2 px-3 text-base leading-normal transition duration-150 ease-in-out sm:text-sm sm:leading-5" />
    </div>
  </div>
  <div class="sm:col-span-6">
    <label for="price" class="block text-sm font-medium text-gray-700"> Price </label>
    <div class="mt-1">
      <input type="number" id="price" name="price" value="{{ $menu->price }}" 
        min="0.00" max="10000.00" step="0.01"
        class="block w-full transition duration-150 ease-in-out appearance-none bg-white border border-gray-400 rounded-md py-2 px-3 text-base leading-normal transition duration-150 ease-in-out sm:text-sm sm:leading-5" />
    </div>
  </div>
  <div class="sm:col-span-6 pt-5">
    <label for="description" class="block text-sm font-medium text-gray-700">Description</label>
    <div class="mt-1">
      <textarea id="description" rows="3" name="description" class="shadow-sm focus:ring-indigo-500 appearance-none bg-white border border-gray-400 rounded-md py-2 px-3 text-base leading-normal transition duration-150 ease-in-out focus:border-indigo-500 block w-full sm:text-sm border-gray-300 rounded-md">
        {{ $menu->description }}
      </textarea>
    </div>
  </div>
  <div class="sm:col-span-6 pt-5">
    <label for="categories" class="block text-sm font-medium text-gray-700">Categories</label>
    <div class="mt-1">
      <select id="categories" name="categories[]" multiple class="form-multiselect block w-full mt-1">
        @foreach ($categories as $category)
          <option value="{{ $category->id }}" @selected($menu->categories->contains($category))>{{ $category->name }}</option>
        @endforeach  
      </select>      
    </div>
  </div>
  <div class="mt-6 p-4">
    <button type="submit" class="px-4 py-2 bg-indigo-500 hover:bg-indigo-700 rounded-lg text-white">Update</button>
  </div>
</form>

 

컨트롤러에서 수정된 부분 처리

public function update(Request $request, Menu $menu)
{
    $request->validate([
        'name' => 'required',
        'description' => 'required',
        'price' => 'required',
    ]);

    $image = $menu->image;
    if ($request->hasFile('image')) {
        Storage::delete($menu->image);
        $image = $request->file('image')->store('public/menus');
    }

    $menu->update([
        'name' => $request->name,
        'description' => $request->description,
        'image' => $image,
        'price' => $request->price,
    ]);

    if ($request->has('categories')) {
        $menu->categories()->sync($request->categories);
    }

    return to_route('admin.menus.index');
}

 

Create에서 $menu->categories()->attach($request->categories); 이랬던 부분이
Update 에서는 $menu->categories()->sync($request->categories); 이렇게 변경 되었다.

 

 

카테고리와 메뉴 연결을 설정하는 migration 부분 역시 아래와 같이 변경

사실 안 해도 되긴 하는데 오류가 날 경우 이렇게 바꿔 주고 migration:refresh --seed 명령 한번 날려주자.

 

 

-- 삭제

삭제 VIEW 페이지

<form 
    class="px-4 py-2 bg-red-500 hover:bg-red-700 rounded-lg text-white"
    action="{{ route('admin.menus.destroy', $menu->id) }}"
    method="POST"
    onsubmit="return confirm('Are you sure?');">
    @csrf
    @method('DELETE')
    <button type="submit">Delete</button>
</form>

 

삭제 부분 처리하는 컨트롤러

public function destroy(Menu $menu)
{
    $menu->delete();
    Storage::delete($menu->image);

    return to_route('admin.menus.index');
}

 

+ Recent posts