# Basic CRUD example with Doctrine and CalendarBundle This example allow you to create, update, delete & show events with `CalendarBundle` ## Installation 1. [Download CalendarBundle using composer](#1-download-calendarbundle-using-composer) 2. [Create the entity](#2-create-the-entity) 3. [Create the CRUD](#3-create-the-crud) 4. [Use an event subscriber to connect all of this together](#4-use-an-event-subscriber-to-connect-all-of-this-together) 5. [Display your calendar](#5-display-your-calendar) ### 1. Download CalendarBundle using composer This documentation assumes that doctrine is already installed. > **NOTE:** `composer req doctrine` then update the database url in your `.env` and run `bin/console d:d:c` ```sh composer require tattali/calendar-bundle ``` The recipe will import the routes for you Check the existence of the file `config/routes/calendar.yaml` or create it ```yaml # config/routes/calendar.yaml calendar: resource: '@CalendarBundle/config/routing.yaml' ``` ### 2. Create the entity Generate or create an entity with at least a *start date* and a *title*. You also can add an *end date* ```sh # Symfony flex (Need the maker: `composer req --dev maker`) php bin/console make:entity ``` In this example we call the entity `Booking` ```php // src/Entity/Booking.php id; } public function getBeginAt(): ?\DateTime { return $this->beginAt; } public function setBeginAt(\DateTime $beginAt): static { $this->beginAt = $beginAt; return $this; } public function getEndAt(): ?\DateTime { return $this->endAt; } public function setEndAt(?\DateTime $endAt): static { $this->endAt = $endAt; return $this; } public function getTitle(): ?string { return $this->title; } public function setTitle(string $title): static { $this->title = $title; return $this; } } ``` ```php // src/Repository/BookingRepository.php */ class BookingRepository extends ServiceEntityRepository { public function __construct(ManagerRegistry $registry) { parent::__construct($registry, Booking::class); } } ``` Then, update your database schema ``` php bin/console doctrine:migration:diff php bin/console doctrine:migration:migrate -n ``` ### 3. Create the CRUD You can now create or generate the CRUD of your entity The following command will generate a `BookingController` with `index()`, `new()`, `show()`, `edit()` and `delete()` actions And also the according `templates` and `form` (You may need to install additional packages) ```sh php bin/console make:crud Booking ``` Edit the `BookingController` by adding a `calendar()` action to display the calendar (must be placed before `show()` to be resolved correctly) ```php // src/Controller/BookingController.php render('booking/calendar.html.twig'); } // ... } ``` ### 4. Use an event subscriber to connect all of this together This subscriber must be registered only if autoconfigure is false. ```yaml # config/services.yaml services: # ... App\EventSubscriber\CalendarSubscriber: ``` We now have to link the CRUD to the calendar by adding the `app_booking_show` route in each events [TL;DR](#full-subscriber) To do this create a subscriber with access to the router component and your entity repository ```php // src/EventSubscriber/CalendarSubscriber.php addOption( 'url', $this->router->generate('app_booking_show', [ 'id' => $booking->getId(), ]) ); ``` #### Full subscriber Full subscriber with `Booking` entity. Modify it to fit your needs. ```php // src/EventSubscriber/CalendarSubscriber.php 'onCalendarSetData', ]; } public function onCalendarSetData(SetDataEvent $setDataEvent) { $start = $setDataEvent->getStart(); $end = $setDataEvent->getEnd(); $filters = $setDataEvent->getFilters(); // Modify the query to fit to your entity and needs // Change booking.beginAt by your start date property $bookings = $this->bookingRepository ->createQueryBuilder('booking') ->where('booking.beginAt BETWEEN :start and :end OR booking.endAt BETWEEN :start and :end') ->setParameter('start', $start->format('Y-m-d H:i:s')) ->setParameter('end', $end->format('Y-m-d H:i:s')) ->getQuery() ->getResult() ; foreach ($bookings as $booking) { // this create the events with your data (here booking data) to fill calendar $bookingEvent = new Event( $booking->getTitle(), $booking->getBeginAt(), $booking->getEndAt() // If the end date is null or not defined, a all day event is created. ); /* * Add custom options to events * * For more information see: https://fullcalendar.io/docs/event-object */ $bookingEvent->setOptions([ 'backgroundColor' => 'red', 'borderColor' => 'red', ]); $bookingEvent->addOption( 'url', $this->router->generate('app_booking_show', [ 'id' => $booking->getId(), ]) ); // finally, add the event to the CalendarEvent to fill the calendar $setDataEvent->addEvent($bookingEvent); } } } ``` ### 5. Display your calendar Then create the calendar template add a link to the `app_booking_new` form ```twig Create new booking ``` and include the `calendar-holder` ```twig
``` Full template: ```twig {# templates/booking/calendar.html.twig #} {% extends 'base.html.twig' %} {% block body %} Create new booking
{% endblock %} {% block javascripts %} {% endblock %} ``` You can use [Plugins](https://fullcalendar.io/docs/plugin-index) to reduce loadtime. * Now visit: * In the calendar when you click on an event it call the `show()` action that should contains an edit and delete link * And when you create a new `Booking` (or your custom entity name) it appear on the calendar * If you have created a custom entity don't forget to modify the subscriber: - Replace all `Booking` or `booking` by your custom entity name - In the query near the `where` modify `beginAt` to your custom start date property - Also when you create each `Event` in the `foreach` modify the getters to fit with your entity ### Next steps * You may want to customize the fullcalendar.js settings to meet your application needs. To do this, see the [official fullcalendar documentation](https://fullcalendar.io/docs#toc).
* To debug AJAX requests, show the Network monitor, then reload the page. Finally click on `fc-load-events` and select the `Response` or `Preview` tab - Firefox: `Ctrl + Shift + E` ( `Command + Option + E` on Mac ) - Chrome: `Ctrl + Shift + I` ( `Command + Option + I` on Mac )