Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 13 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save tattali/7a761a611c92e3ea556477c475af7dd6 to your computer and use it in GitHub Desktop.
Save tattali/7a761a611c92e3ea556477c475af7dd6 to your computer and use it in GitHub Desktop.
Use fullcalendar.js library in your Symfony project with doctrine

Use fullcalendar.js library in your Symfony 4 project with doctrine

FullCalendar.js is a JavaScript event calendar customizable and open source. You can display a full-size event calendar that also compatible with google calendar.

Installation

Download tattali/CalendarBundle using composer

$ 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

# config/routes/calendar.yaml
calendar:
    resource: "@CalendarBundle/Resources/config/routing.yaml"

NOTE : This guide explains how to use the bundle with doctrine ORM (composer req symfony/orm-pack) but you can use any other storage driver.

To load events into the calendar, you must create a listener class and select your events.

Edit the current query to select your own events

// src/EventSubscriber/CalendarSubscriber.php
<?php

namespace App\EventSubscriber;

use App\Repository\BookingRepository;
use CalendarBundle\CalendarEvents;
use CalendarBundle\Entity\Event;
use CalendarBundle\Event\CalendarEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;

class CalendarSubscriber implements EventSubscriberInterface
{
    private $bookingRepository;
    private $router;

    public function __construct(
        BookingRepository $bookingRepository,
        UrlGeneratorInterface $router
    ) {
        $this->bookingRepository = $bookingRepository;
        $this->router = $router;
    }

    public static function getSubscribedEvents()
    {
        return [
            CalendarEvents::SET_DATA => 'onCalendarSetData',
        ];
    }

    public function onCalendarSetData(CalendarEvent $calendar)
    {
        $start = $calendar->getStart();
        $end = $calendar->getEnd();
        $filters = $calendar->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
             * and: https://github.com/fullcalendar/fullcalendar/blob/master/src/core/options.ts
             */

            $bookingEvent->setOptions([
                'backgroundColor' => 'red',
                'borderColor' => 'red',
            ]);
            $bookingEvent->addOption(
                'url',
                $this->router->generate('booking_show', [
                    'id' => $booking->getId(),
                ])
            );

            // finally, add the event to the CalendarEvent to fill the calendar
            $calendar->addEvent($bookingEvent);
        }
    }
}

Include the calendar-holder were you want to display the calendar:

<div id="calendar-holder"></div>

Add styles and js. Click here to see other css and js download methods

{% block stylesheets %}
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fullcalendar/core@4.1.0/main.min.css">
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fullcalendar/daygrid@4.1.0/main.min.css">
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fullcalendar/timegrid@4.1.0/main.min.css">
{% endblock %}

{% block javascripts %}
    <script src="https://cdn.jsdelivr.net/npm/@fullcalendar/core@4.1.0/main.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/@fullcalendar/interaction@4.1.0/main.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/@fullcalendar/daygrid@4.1.0/main.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/@fullcalendar/timegrid@4.1.0/main.min.js"></script>

    <script type="text/javascript">
        document.addEventListener('DOMContentLoaded', () => {
            var calendarEl = document.getElementById('calendar-holder');

            var calendar = new FullCalendar.Calendar(calendarEl, {
                defaultView: 'dayGridMonth',
                editable: true,
                eventSources: [
                    {
                        url: "{{ path('fc_load_events') }}",
                        method: "POST",
                        extraParams: {
                            filters: JSON.stringify({})
                        },
                        failure: () => {
                            // alert("There was an error while fetching FullCalendar!");
                        },
                    },
                ],
                header: {
                    left: 'prev,next today',
                    center: 'title',
                    right: 'dayGridMonth,timeGridWeek,timeGridDay',
                },
                plugins: [ 'interaction', 'dayGrid', 'timeGrid' ], // https://fullcalendar.io/docs/plugin-index
                timeZone: 'UTC',
            });
            calendar.render();
        });
    </script>
{% endblock %}

You may want to customize the FullCalendar javascript to meet your applications needs. To do this, see the official fullcalendar documentation or also the allow create, update and delete events in the bundle.

@tattali
Copy link
Author

tattali commented May 13, 2020

Hi, I am not sure to understand what you need to do, but to pass extra parameters, you can use filters

in your front template

extraParams: {
    filters: JSON.stringify({ "property-index": "value" })
},

in the subscriber

// src/EventSubscriber/CalendarSubscriber.php
<?php

namespace App\EventSubscriber;

class CalendarSubscriber implements EventSubscriberInterface
{
    // ...
    public function onCalendarSetData(CalendarEvent $calendar)
    {
        $start = $calendar->getStart();
        $end = $calendar->getEnd();
        $filters = $calendar->getFilters();

        $filters['property-index']; // value
    }
}

@jwedrowycz
Copy link

I've already figured out it by myself with this 'filter' extra option, but thanks a lot for response and this bundle anyway!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment