๐ Backend routes details
and /rental/create
Linking to other pagesโ
When linking to other pages, you should always use relative links. This ensures that the link will work in any environment, regardless of the domain.
Details pageโ
This page is a child of the rentals
page, so the link should look like this:
/rental/<rental_id>
First let look at the route in config/routes.yaml:
rental_details:
path: /rental/{id}
controller: App\Controller\RentalController::details
methods: [GET]
The rental_id
is a dynamic value that will be replaced with the actual ID of the rental. This is how you link to the details page from another page:
<a href="{{ path('rental_details', {
'id': rental.id,
'city': currentCity,
'check_in': currentCheckIn,
'check_out': currentCheckOut
}) }}">{{ rental.name }}</a>
Now lets add the backend logic in the controller:
/**
* 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,
]
);
}
As you can see, the rental_id
is passed as a parameter to the path
function. This will generate the correct URL for the details page.
Lets see the twig page 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 %}
This page displays the rental details and allows the user to book a room. The booking form is submitted to the rental_book
route, which we will create next.
Create pageโ
This page is a child of the rentals
page, so the link should look like this:
/rentals/create
First let look at the route in config/routes.yaml:
rental_create:
path: /rental/create
controller: App\Controller\RentalController::create
methods: [GET, POST]
This is an admin functionality, but for simplicity, we will not add any security checks in this example. In a real-world application, you should always add proper security checks to protect sensitive functionality.
Lets add the backend logic in the controller:
/**
* 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(),
]
);
}
As you can see, the rental_create
route accepts both GET
and POST
requests. This is because the page contains a form to create a new rental. When the form is submitted, the data is sent to the same URL using a POST
request.
We need to build a form type file for the rental entity. Lets create a new file src/Form/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,
]
);
}
}
Lets see the twig page 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 %}
This page displays a form to create a new rental. The form is submitted to the same URL using a POST
request. If the form is submitted and valid, the rental is persisted and the user is redirected to the rentals page.
By now you should be able to create a new rental and view the details of a rental.โ
- Lets test clicking on the rental name and see the details of the rental.
- Lets test creating a new rental and see if it is added to the list of rentals.
Next we will add the functionality to book a room in a rental and view a booking confirmation.