Skip to main content

๐ŸŒŽ Full code

The full code can be found in the main github repo.

Lets verify full code of the following project :

.
โ”œโ”€โ”€ composer.json
โ”œโ”€โ”€ composer.lock
โ”œโ”€โ”€ symfony.lock
โ”œโ”€โ”€ .env
โ”œโ”€โ”€ src
โ”‚ย ย  โ”œโ”€โ”€ Controller
โ”‚ย ย  โ”‚ย ย  โ”œโ”€โ”€ BookingController.php
| | โ”œโ”€โ”€ RentalController.php
โ”‚ย ย  โ”œโ”€โ”€ Document
โ”‚ย ย  โ”‚ย ย  โ”œโ”€โ”€ Booking.php
โ”‚ย ย  โ”‚ย ย  โ”œโ”€โ”€ Rental.php
โ”‚ย ย  โ”‚ย ย  โ”œโ”€โ”€ Availability.php
โ”‚ย ย  โ”œโ”€โ”€ Form
โ”‚ย ย  โ”‚ย ย  โ”œโ”€โ”€ RentalType.php
โ”‚ย ย  โ”œโ”€โ”€
โ”œโ”€โ”€ config
โ”‚ย ย  โ”œโ”€โ”€ packages
โ”‚ย ย  โ”‚ย ย  โ”œโ”€โ”€ doctrine_mongodb.yaml
โ”‚ย ย  โ”‚ย ย  โ”œโ”€โ”€ framework.yaml
โ”‚ย ย  โ”‚ย ย  โ”œโ”€โ”€ twig.yaml
โ”‚ย ย  โ”‚ย ย  โ””โ”€โ”€ routing.yaml
โ”‚ย ย  โ”œโ”€โ”€ routes.yaml
โ”œโ”€โ”€ templates
โ”‚ย ย  โ”œโ”€โ”€ rental
โ”‚ย ย  โ”‚ย ย  โ”œโ”€โ”€ index.html.twig
| | โ”œโ”€โ”€ confirmaion.html.twig
| | โ”œโ”€โ”€ details.html.twig
| | โ”œโ”€โ”€ create.html.twig
| | โ”œโ”€โ”€ bookings.html.twig
| โ”œโ”€โ”€ base.html.twig
โ”œโ”€โ”€ public
โ”‚ย ย  โ”œโ”€โ”€ index.php
โ”‚ย ย  โ”œโ”€โ”€ css
โ”‚ย ย  โ”‚ย ย  โ””โ”€โ”€ styles.css

config/routes.yamlโ€‹

# controllers:
# resource:
# path: ../src/Controller/
# namespace: App\Controller
# type: attribute

# main routes
rental_index:
path: /
controller: App\Controller\RentalController::index
methods: [GET]

# create a new rental
rental_create:
path: /rental/create
controller: App\Controller\RentalController::create
methods: [GET, POST]

# show a rental
rental_details:
path: /rental/{id}
controller: App\Controller\RentalController::details
methods: [GET]

# book a rental
rental_book:
path: /rental/book/{rentalId}
controller: App\Controller\RentalController::book
methods: [POST]

# list all bookings
booking_index:
path: /booking
controller: App\Controller\BookingController::index
methods: [GET]

RentalController.phpโ€‹

<?php

/**
* RentalController
* ---------------------
*
* This class is responsible for handling the rental query and booking operations.
*
* @category Controller
* @package App\Controller
* @author pavel.duchovny
* @license apache-2.0
*/

declare(strict_types=1);

namespace App\Controller;

use App\Document\Booking;
use App\Document\Rental;
use App\Form\RentalType;
use DateTime;
use DateTimeImmutable;
use Doctrine\ODM\MongoDB\DocumentManager;
use MongoDB\BSON\Regex;
use Psr\Log\LoggerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
/**
* RentalController
* ---------------------
* This class is responsible for handling the rental query and booking operations.
*/

class RentalController extends AbstractController
{
// DocumentManager instance
private $_documentManager;
private $_logger;
/**
* __construct -
*
* This function is responsible for initializing the RentalController class.
*
* @param DocumentManager $_documentManager - The document manager
* @param LoggerInterface $_logger - The logger interface
*
* @return void
*/
public function __construct(DocumentManager $_documentManager, LoggerInterface $_logger)
{
$this->_documentManager = $_documentManager;
$this->_logger = $_logger;
}

// Index action to display all the rentals or filter by city and availability

#[Route('/', name: 'rental_index', methods: ['GET'])]
public function index(Request $request): Response
{
// Get the city, check-in and check-out dates from the query parameters
$city = $request->query->get('city');
$checkInInput = $request->query->get('check_in');
$checkOutInput = $request->query->get('check_out');

$checkIn = $checkInInput ? new DateTime($checkInInput) : null;
$checkOut = $checkOutInput ? new DateTime($checkOutInput) : null;
// Fetch all the rentals
if ($city && $checkIn && $checkOut) {
// Fetch rentals based on city and availability
// The availability field is an array of objects with start_date and end_date fields
// So we use elemMatch to query the availability array and see if the user requested dates are available
$rentalRepository = $this->_documentManager->getRepository(Rental::class);
$queryBuilder = $rentalRepository->createQueryBuilder();

$rentals = $queryBuilder
->field('location')->equals(new Regex($city, 'i'))
->field('availability')->elemMatch(
$queryBuilder->expr()
->field('startDate')->lte($checkIn)
->field('endDate')->gte($checkOut),
)
->getQuery()
->execute();
} else {
// Fetch all the rentals
$rentals = $this->_documentManager->getRepository(Rental::class)->findAll();
}

// Render the rentals page

return $this->render('rental/index.html.twig', ['rentals' => $rentals]);
}

/**
* Details action to display the details of a rental
*
* @param Request $request - The request object
* @param string $id - The rental id
*
* @return Response - The response object
*/
#[Route('/rental/{id}', name: 'rental_details', methods: ['GET'])]
public function details(Request $request, string $id): Response
{
$checkInInput = $request->query->get('check_in');
$checkOutInput = $request->query->get('check_out');

$checkIn = $checkInInput ? new DateTime($checkInInput) : null;
$checkOut = $checkOutInput ? new DateTime($checkOutInput) : null;
$rental = $this->_documentManager->getRepository(rental::class)->find($id);

// Calculate total price based on night cost and number of days
if ($checkIn && $checkOut) {
$interval = $checkIn->diff($checkOut);
$days = $interval->days;
$totalPrice = $days * $rental->nightCost;
} else {
$totalPrice= 0;
}



if (! $rental) {
throw $this->createNotFoundException('No rental found for id ' . $id);
}

// Render the rental details page
return $this->render(
'rental/details.html.twig', [
'rental' => $rental,
'totalPrice' => $totalPrice,
]
);
}

/**
* Create action to create a new rental
*
* @param Request $request - The request object
*
* @return Response - The response object
*/
#[Route('/rental/create', name: 'rental_create', methods: ['GET', 'POST'])]
public function create(Request $request): Response
{
// Create a new rental instance
$rental = new rental();
// print request
$this->_logger->info('Request: ' . $request->getContent());

// Create a form to create a new rental
$form = $this->createForm(RentalType::class, $rental);
$form->handleRequest($request);

// If the form is submitted and valid, persist the rental and redirect to the rentals page
if ($form->isSubmitted() && $form->isValid()) {
$this->_documentManager->persist($rental);
$this->_documentManager->flush();

return $this->redirectToRoute('rental_index');
}

// Render the create rental page
return $this->render(
'rental/create.html.twig', [
'form' => $form->createView(),
]
);
}

/**
* Book action to book a rental
*
* @param Request $request - The request object
* @param string $id - The rental id
*
* @return Response - The response object
*/
#[Route('/rental/book/{rentalId}', name: 'rental_book', methods: ['POST'])]
public function book(Request $request, $rentalId): Response
{
// Fetch the rental by id
$rental = $this->_documentManager->getRepository(Rental::class)->find($rentalId);

// If the rental is not found, throw a 404 exception
if (! $rental) {
throw $this->createNotFoundException('rental not found');
}

// Get the start and end dates from the request

$startDateInput = $request->request->get('startDate');
$endDateInput = $request->request->get('endDate');

$startDate = $startDateInput ? new DateTime($startDateInput) : null;
$endDate = $endDateInput ? new DateTime($endDateInput) : null;




// Calculate total price based on night cost and number of days
$interval = $startDate->diff($endDate);
$days = $interval->days;
$totalPrice = $days * $rental->nightCost;

// Calculate new availability based on the booking dates
$newAvailability = $rental->calcAvailabilitySlots($startDate, $endDate, $rental->availability->toArray());

// Create and persist the booking
$booking = new Booking();
$booking->rental = $rental;
$booking->rentalName = $rental->name;
$booking->startDate = DateTimeImmutable::createFromMutable($startDate);
$booking->endDate = DateTimeImmutable::createFromMutable($endDate);
$booking->totalCost = (int)$totalPrice;
$rental->availability = $newAvailability;

// Persist the booking and rental
$this->_documentManager->persist($booking);
$this->_documentManager->persist($rental);
$this->_documentManager->flush();

// Redirect to a confirmation page or show confirmation message
return $this->render(
'rental/confirmation.html.twig', [
'rental' => $rental,
'booking' => $booking,
'totalPrice' => $totalPrice,
]
);
}
}

BookingController.phpโ€‹

<?php
/**
* BookingController
* ---------------------
* This class is responsible for handling the booking query operations.
*
* @category Controller
* @package App\Controller
* @author pavel.duchovny
* @license apache-2.0
*/

declare(strict_types=1);

namespace App\Controller;

use App\Document\Booking;
use Doctrine\ODM\MongoDB\DocumentManager;
use Psr\Log\LoggerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;

/*
* BookingController
---------------------
* This class is responsible for handling the booking query operations.
*/
class BookingController extends AbstractController
{
// DocumentManager instance
private $_documentManager;
private $_logger;
/**
* __construct -
*
* This function is responsible for initializing the BookingController class.
*
* @param DocumentManager $_documentManager - The document manager
* @param LoggerInterface $_logger - The _logger interface
*/
public function __construct(DocumentManager $_documentManager, LoggerInterface $_logger)
{
$this->_documentManager = $_documentManager;
$this->_logger = $_logger;
}


/**
* index -
*
* This function is responsible for rendering the bookings page.
*
* @param Request $request - The request object
*
* @return Response
*/
#[Route('/booking', name: 'booking_index', methods: ['GET'])]
public function index(Request $request): Response
{
// Fetch all the bookings
$bookings = $this->_documentManager->getRepository(Booking::class)->findAll();

// Render the bookings page
return $this->render('rental/bookings.html.twig', ['bookings' => $bookings]);
}
}

Rental.phpโ€‹

<?php
/**
* Rental
* ---------------------
* This class is responsible for defining the rental document and its properties.
*
* @category Document
* @package App\Document
* @author pavel.duchovny
* @license apache-2.0
*/

declare(strict_types=1);

namespace App\Document;

use DateTime;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ODM\MongoDB\Mapping\Annotations as MongoDB;
use Doctrine\ODM\MongoDB\Mapping\Annotations as ODM;
use Doctrine\ODM\MongoDB\Types\Type;

/*
* Rental
---------------------
* This class is responsible for defining the rental document and its properties.
*/
#[
MongoDB\Document(collection: 'rentals')
]

class Rental
{
#[ODM\Id]
public $id;

#[ODM\Field(type: Type::STRING)]
public string $name;

#[ODM\Field(type: Type::STRING)]
public string $location;

#[ODM\Field(type: Type::INT)]
public int $nightCost;

#[ODM\EmbedMany(targetDocument: Availability::class)]
public Collection $availability;

/**
* __construct -
* This function is responsible for initializing the Rental class.
*
* @return void
*/
public function __construct()
{
$this->availability = new ArrayCollection();

// Create an instance of Availability and add it to the collection
$initialAvailability = new Availability();
$initialAvailability->startDate = new DateTime('2024-01-01');
$initialAvailability->endDate = new DateTime('2026-01-01');
$this->availability->add($initialAvailability);
}


/**
* Function : calcAvailabilitySlots
*
* This function is responsible for calculating the
* availability slots based on the booking start and end dates.
*
* @param DateTime $bookingStart - The booking start date
* @param DateTime $bookingEnd - The booking end date
* @param array $availability - The availability array
*
* @return ArrayCollection - The new availability slots
*/
public function calcAvailabilitySlots(DateTime $bookingStart,
DateTime $bookingEnd,
array $availability
): ArrayCollection {
// Create a new ArrayCollection to store the new availability
$newAvailability = new ArrayCollection();

// Loop through each period in the availability to calculate the new availability
foreach ($availability as $period) {
$periodStart = $period->startDate;
$periodEnd = $period->endDate;

// Booking is entirely before this period
if ($bookingEnd < $periodStart) {
$newAvailability->add($period);
continue;
}

// Booking is entirely after this period
if ($bookingStart > $periodEnd) {
$newAvailability->add($period);
continue;
}

// Booking starts before the period and ends within it
if ($bookingStart <= $periodStart && $bookingEnd < $periodEnd) {
$newPeriod = new Availability();
$newPeriod->startDate = $bookingEnd->modify('+1 day');
$newPeriod->endDate = $periodEnd;
$newAvailability->add($newPeriod);
continue;
}

// Booking starts during the period and ends after it
if ($bookingStart > $periodStart && $bookingEnd >= $periodEnd) {
$newPeriod = new Availability();
$newPeriod->startDate= $periodStart;
$newPeriod->endDate = $bookingStart->modify('-1 day');
$newAvailability->add($newPeriod);
continue;
}

// Booking is entirely within the period
if ($bookingStart > $periodStart && $bookingEnd < $periodEnd) {
$newPeriod1 = new Availability();
$newPeriod1->startDate = $periodStart;
$newPeriod1->endDate = $bookingStart->modify('-1 day');
$newAvailability->add($newPeriod1);

$newPeriod2 = new Availability();
$newPeriod2->startDate = $bookingEnd->modify('+1 day');
$newPeriod2->endDate = $periodEnd;
$newAvailability->add($newPeriod2);
continue;
}

// Booking covers the entire period
// Do not add the period to newAvailability (effectively removing it)
}

return $newAvailability;
}
}

Booking.phpโ€‹

<?php
/**
* Booking
* ---------------------
* This class is responsible for defining the booking document and its properties.
*
* @category Document
* @package App\Document
* @author pavel.duchovny
* @license apache-2.0
*/

declare(strict_types=1);

namespace App\Document;

use DateTime;
use DateTimeImmutable;
use Doctrine\ODM\MongoDB\Mapping\Annotations as MongoDB;
use Doctrine\ODM\MongoDB\Mapping\Annotations as ODM;
use Doctrine\ODM\MongoDB\Types\Type;

/*
* Booking
---------------------
* This class is responsible for defining the booking document and its properties.
*/
#[
MongoDB\Document(collection: 'bookings')
]
class Booking
{
#[ODM\Id]
public $id;

#[ODM\ReferenceOne(targetDocument: Rental::class)]
public Rental $rental;

#[ODM\Field(type: Type::STRING)]
public string $rentalName;

#[ODM\Field(type: Type::STRING)]
public string $location;

#[ODM\Field(type: Type::INT)]
public int $totalCost;

#[ODM\Field(type: Type::DATE_IMMUTABLE)]
public DateTimeImmutable $startDate;

#[ODM\Field(type: Type::DATE_IMMUTABLE)]
public DateTimeImmutable $endDate;

// Add getters and setters for each property

}

Availability.phpโ€‹

<?php
/**
* Availability
*
* This class is responsible for defining the availability
* sub document and its properties.
*
* @category Document
* @package App\Document
* @author pavel.duchovny
* @license apache-2.0
*/

declare(strict_types=1);

namespace App\Document;

use DateTime;
use Doctrine\ODM\MongoDB\Mapping\Annotations as ODM;
use Doctrine\ODM\MongoDB\Types\Type;
/*
* Availability
---------------------
* This class is responsible for defining the availability sub document and its properties.
*/

#[
ODM\EmbeddedDocument
]
class Availability
{
#[ODM\Field(type: Type::DATE)]
public DateTime $startDate;

#[ODM\Field(type: Type::DATE)]
public DateTime $endDate;


}

RentalType.phpโ€‹

<?php
/**
* RentalType - This class is responsible for creating the form for the rental entity.]
**/
declare(strict_types=1);

namespace App\Form;

use App\Document\Rental;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\NumberType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;

/**
* RentalType
---------------------
* This class is responsible for creating the form for the rental entity.
**/
class RentalType extends AbstractType
{
/**
* buildForm - This function is responsible for building the form for the rental entity.
*
* @param FormBuilderInterface $builder - The form builder interface
* @param array $options - The options for the form
*/
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder
->add('name', TextType::class)
->add('location', TextType::class)
->add('nightCost', NumberType::class);
// Add other fields as needed
}

/**
* configureOptions - This function is responsible for setting the default options for the form.
*
* @param OptionsResolver $resolver - The options resolver
* */
public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefaults(
[
'data_class' => Rental::class,
]
);
}
}

base.html.twigโ€‹

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>{% block title %}MongoDB Private Home aPartments Finder!{% endblock %}</title>
<!-- Bootstrap CSS -->
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css">
<link rel="icon" type="image/x-icon" href="{{ asset('favicon.png') }}">
<link href="{{ asset('css/styles.css') }}" rel="stylesheet">
<link href="https://use.fontawesome.com/releases/v5.15.3/css/all.css" rel="stylesheet">
{% block head %}{% endblock %}
</head>
<body>
<div class="header">
<a href="{{ path('rental_index') }}">
<img class="logo" src="{{ asset('php-logo.png') }}" alt="Private Home aPartments Logo"/>
</a>

<h1>Private Home aPartments</h1>
<a href="{{ path('booking_index') }}">My Bookings</a>
</div>
{% block body %}{% endblock %}
</body>
</html>

rental/index.html.twigโ€‹

{# templates/rental/index.html.twig #}
{% set currentCity = app.request.query.get('city') %}
{% set currentCheckIn = app.request.query.get('check_in') %}
{% set currentCheckOut = app.request.query.get('check_out') %}

{% extends 'base.html.twig' %}

{% block title %}Rental List{% endblock %}

{% block body %}
<div class="container">
<h2>Search Rentals</h2>
<form action="{{ path('rental_index') }}" method="get">
<div class="form-group">
<label for="city">Location:</label>
<input type="text" id="city" name="city" class="form-control" value="{{ app.request.query.get('city') }}" required>
</div>
<div class="form-group">
<label for="check_in">Check-in Date:</label>
<input type="date" id="check_in" name="check_in" class="form-control" value="{{ app.request.query.get('check_in') }}" required>
</div>
<div class="form-group">
<label for="check_out">Check-out Date:</label>
<input type="date" id="check_out" name="check_out" class="form-control" value="{{ app.request.query.get('check_out') }}" required>
</div>
<button type="submit" class="btn btn-primary">Search</button>
</form>



<a href="{{ path('rental_create') }}" class="btn btn-success my-3">Create New Rental</a>
<div class="row">
{% for rental in rentals %}
<div class="col-md-4 mb-4">
<div class="card">
<div class="card-body">
<h4>
<a href="{{ path('rental_details', {
'id': rental.id,
'city': currentCity,
'check_in': currentCheckIn,
'check_out': currentCheckOut
}) }}">{{ rental.name }}</a></h4>
<p class="card-text"><b>Location:</b> {{ rental.location }}</p>
<p class="card-text"><b>Per night:</b> {{ rental.nightCost }}$</p>

<!-- Add more rental details here -->
</div>
</div>
</div>
{% endfor %}
</div>
</div>
{% endblock %}

rental/details.html.twigโ€‹

{# templates/rental/details.html.twig #}



{% extends 'base.html.twig' %}

{% block title %}Rental Details{% endblock %}

{% block body %}
<div class="container mt-4">
<h2 class="mb-3"><i class="fas fa-rental"></i> {{ rental.name }}</h2>
<p><i class="fas fa-map-marker-alt"></i> {{ rental.location }}</p>
<p><i class="fas fa-tag"></i> <strong> Night Rate:</strong> {{ rental.nightCost }}$</p>
<p><i class="fas fa-tag"></i> <strong> Total Rate:</strong> {{ (totalPrice is not same as 0 )? totalPrice ~ '$' : 'N/A' }}</p>
<!-- Add more rental details here -->

<h3 class="mt-4">Book a Room</h3>
<form class="mt-3" action="{{ path('rental_book', {'rentalId': rental.id}) }}" method="post">
<div class="form-group">
<label for="start_date">Check In</label>
<input id="start_date" type="date" name="startDate" class="form-control" value="{{ app.request.query.get('check_in') }}">
</div>
<div class="form-group">
<label for="end_date">Check Out</label>
<input id="end_date" type="date" name="endDate" class="form-control" value="{{app.request.query.get('check_out') }}">
</div>
<button type="submit" class="btn btn-success">Book</button>
</form>
</div>
{% endblock %}

rental/create.html.twigโ€‹

{# templates/rental/create.html.twig #}

{% extends 'base.html.twig' %}

{% block title %}Create Rental{% endblock %}

{% block body %}
<div class="container">
<h2>Create Rental</h2>
{{ form_start(form, {'attr': {'class': 'form-horizontal'}}) }}

<div class="form-group">
{{ form_label(form.name) }}
{{ form_widget(form.name, {'attr': {'class': 'form-control'}}) }}
{{ form_errors(form.name) }}
</div>

<div class="form-group">
{{ form_label(form.location) }}
{{ form_widget(form.location, {'attr': {'class': 'form-control'}}) }}
{{ form_errors(form.location) }}
</div>

<div class="form-group">
{{ form_label(form.nightCost) }}
{{ form_widget(form.nightCost, {'attr': {'class': 'form-control'}}) }}
{{ form_errors(form.nightCost) }}
</div>
<div class="form-group">
<label for="start_date">Availability Start Date:</label>
<input type="date" id="start_date" name="start_date" class="form-control" value="2024-01-01" required>
</div>
<div class="form-group">
<label for="end_date">Availability End Date:</label>
<input type="date" id="end_date" name="end_date" class="form-control" value="2026-01-01" required>
</div>


<button type="submit" class="btn btn-success">Create</button>
{{ form_end(form) }}
</div>
{% endblock %}

rental/confirmation.html.twigโ€‹

{# templates/rental/confirmation.html.twig #}

{% extends 'base.html.twig' %}

{% block title %}Booking Confirmation{% endblock %}

{% block body %}
<div class="container">
<h2>Booking Confirmation</h2>
<p>Rental: {{ rental.name }}</p>
<p>Location: {{ rental.location }}</p>
<p>Check-in Date: {{ booking.startDate|date('Y-m-d') }}</p>
<p>Check-out Date: {{ booking.endDate|date('Y-m-d') }}</p>
<p>Total Price: {{ totalPrice }}$</p>

<a href="{{ path('rental_index') }}" class="btn btn-success my-3">Back</a>
</div>
{% endblock %}

rental/bookings.html.Twigโ€‹

{# templates/rental/bookings.html.twig #}

{% extends 'base.html.twig' %}

{% block title %}My Bookings{% endblock %}

{% block body %}
<div class="container">
<h2>My Bookings</h2>
<table class="table">
<thead>
<tr>
<th>Rental</th>
<th>Confirmation</th>
<th>Start Date</th>
<th>End Date</th>
<th>Total Cost</th>
</tr>
</thead>
<tbody>
{% for booking in bookings %}
<tr>
<td><a href="{{ path('rental_details', {'id': booking.rental.id}) }}">
{{booking.rentalName }}</a></td>
<td>{{booking.id}}</td>
<td>{{ booking.startDate|date('Y-m-d') }}</td>
<td>{{ booking.endDate|date('Y-m-d') }}</td>
<td>{{ booking.totalCost }}$</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% endblock %}