Skip to main content

๐Ÿ”— 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.