tattali / CalendarBundle

Provides event calendar for your Symfony project. Compatible with API like Google Calendar.
https://packagist.org/packages/tattali/calendar-bundle
MIT License
147 stars 22 forks source link

"There was an error while fetching FullCalendar!" #33

Closed missCorie closed 3 years ago

missCorie commented 4 years ago

I had already installed FullCalendar on an old symfony project and everything was working fine. I did the same installation in a new project but I have the error: "There was an error while fetching FullCalendar!" The only difference is the version of symfony 5.1.

tattali commented 4 years ago

the classnames have probably change.

if you provide me your code I probably can help you

missCorie commented 4 years ago
 App\EventSubscriber\CalendarSubscriber:
        tags:
         - { name: 'kernel.event_listener', event: 'calendar.set_data', method: onCalendarSetData}
<?php
namespace App\EventSubscriber;

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

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

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

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

    public function onCalendarSetData(CalendarEvent $calendar): void
    {
        $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
        $manifestations = $this->manifestationRepository
            ->createQueryBuilder('m')
            ->where('m.startDate BETWEEN :start and :end OR m.endDate 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 ($manifestations as $manifestation) {
            // this create the events with your data (here manifestation data) to fill calendar
            $manifestationEvent = new Event(
                $manifestation->getStartDate(),
                $manifestation->getEndDate()
            );

            /*
             * 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
             */
            $manifestationEvent->setOptions([
                'color' => '#18BC9C',
                'textColor'=> 'white',
            ]);
            $manifestationEvent->addOption('url',  $this->router->generate('booking', [
                'id' => $manifestation->getId(),
                ])
            );

            // finally, add the event to the CalendarEvent to fill the calendar
            $calendar->addEvent($manifestationEvent);
        }
    }
}
{% extends 'base.html.twig' %}

{% block body %}
<div class="container my-5">
    <h1 class="mb-5">Calendrier des Manifestations</h1>
    <div class="row">
    <div id="calendar-holder" class="col-md-8 col-sm-12"></div>
    <div id="display-event" class="col-md-4 col-sm-12"></div>
    </div>
</div>
{% endblock %}

{% block stylesheets %}
{{ parent() }}
<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">
{% endblock %}

{% block javascripts %}
{{ parent() }}
  <script src="https://cdn.jsdelivr.net/npm/@fullcalendar/core@4.1.0/main.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/@fullcalendar/daygrid@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, {
            locale: 'fr',
            defaultView: 'dayGridMonth',
            editable: false, // empêcher de déplacer et redimensionner l'évènement
            height: 'parent',
            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',
                center: 'title',
                right: 'dayGridMonth',
            },
            buttonText: {
                month: 'mois'
            },
            plugins: ['interaction', 'dayGrid'],
            eventMouseEnter: function(mouseEnterInfo) {
                const displayEvent = document.getElementById('display-event');
                let newDiv = document.createElement('div');
                newDiv.className = 'tooltip_event';

                let h5 = document.createElement('h5');
                h5.textContent = 'Votre manifestation :'

                let newP1 = document.createElement('p');
                //newP1.textContent =  mouseEnterInfo.event.start;
                let newP2 = document.createElement('p');
                newP2.textContent =  mouseEnterInfo.event.title ; 
                newDiv.append(h5);
                newDiv.append(newP1);
                newDiv.append(newP2);

                displayEvent.append(newDiv);
            },
            eventMouseLeave: function (mouseLeaveInfo) {
                const displayEvent = document.getElementById('display-event');
                let tooltip = document.querySelector('.tooltip_event');
                displayEvent.removeChild(tooltip);
            },

            timeZone: 'Europe/Paris'
        });
        calendar.render();
    });
</script>

{% endblock %}
<?php

namespace App\Entity;

use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;

/**
 * @ORM\Entity(repositoryClass="App\Repository\ManifestationRepository")
 * @ORM\HasLifecycleCallbacks
 */
class Manifestation
{
    /**
     * @ORM\Id()
     * @ORM\GeneratedValue()
     * @ORM\Column(type="integer")
     */
    private $id;

    /**
     * @ORM\Column(type="datetime")
     */
    private $startDate;

    /**
     * @ORM\Column(type="datetime")
     */
    private $endDate;

    /**
     * @ORM\OneToMany(targetEntity="App\Entity\Booking", mappedBy="manifestation")
     */
    private $bookings;

    /**
     * @ORM\ManyToMany(targetEntity=Formula::class, inversedBy="manifs")
     */
    private $formula;

    /**
     * @ORM\Column(type="smallint")
     */
    private $stock;

    /**
     * @ORM\Column(type="boolean")
     */
    private $wkendPrice;

    public function __construct($stock = 120)
    {
        $this->bookings = new ArrayCollection();
        $this->formula = new ArrayCollection();
        $this->stock = $stock;
    }

    /**
     * Permet d'obtenir un tableau des jours qui ne sont pas disponibles pour organiser une manifestation
     *
     * @return array Un tableau d'objets DateTime représentant les jours déjà pris
     */
    public function getNotAvailableDays(){
        $notAvailabledays = [];

        foreach($this->manifestations as $manifestation){
            // Calculer les jours entre le startDate et le endDate au format Timestamp
            $result = range(
                $manifestation->startDate()->getTimestamp(),
                $manifestation->endDate()->getTimestamp(),
                24*60*60*1000 // le step = nbre de millisecondes pour 1 jour
            );
            // transforme le tableau des jours Timestamp au format DateTime
            $days = array_map(function($dayTimestamp){
                return new \DateTime(date('Y-m-d', $dayTimestamp));
            }, $result);

            $notAvailabledays = array_merge($notAvailabledays, $days);
        }
        return $notAvailabledays;
        dump($notAvailabledays);
    }

    public function getId(): ?int
    {
        return $this->id;
    }

    public function getStartDate(): ?\DateTimeInterface
    {
        return $this->startDate;
    }

    public function setStartDate(\DateTimeInterface $startDate): self
    {
        $this->startDate = $startDate;

        return $this;
    }

    public function getEndDate(): ?\DateTimeInterface
    {
        return $this->endDate;
    }

    public function setEndDate(?\DateTimeInterface $endDate): self
    {
        $this->endDate = $endDate;

        return $this;
    }

    // pour retourner la date de la manifestation dans un select
    public function __toString()
    {
        return $this->startDate->format('d-m-Y H:i');
    }

    /**
     * @return Collection|Booking[]
     */
    public function getBookings(): Collection
    {
        return $this->bookings;
    }

    public function addBooking(Booking $booking): self
    {
        if (!$this->bookings->contains($booking)) {
            $this->bookings[] = $booking;
            $booking->setManifestation($this);
        }

        return $this;
    }

    public function removeBooking(Booking $booking): self
    {
        if ($this->bookings->contains($booking)) {
            $this->bookings->removeElement($booking);
            // set the owning side to null (unless already changed)
            if ($booking->getManifestation() === $this) {
                $booking->setManifestation(null);
            }
        }

        return $this;
    }

    /**
     * @return Collection|Formula[]
     */
    public function getFormula(): Collection
    {
        return $this->formula;
    }

    public function addFormula(Formula $formula): self
    {
        if (!$this->formula->contains($formula)) {
            $this->formula[] = $formula;
        }

        return $this;
    }

    public function removeFormula(Formula $formula): self
    {
        if ($this->formula->contains($formula)) {
            $this->formula->removeElement($formula);
        }

        return $this;
    }

    public function getStock(): ?int
    {
        return $this->stock;
    }

    public function setStock(int $stock): self
    {
        $this->stock = $stock;

        return $this;
    }

    public function getWkendPrice(): ?bool
    {
        return $this->wkendPrice;
    }

    public function setWkendPrice(bool $wkendPrice): self
    {
        $this->wkendPrice = $wkendPrice;

        return $this;
    }

    public function canImplementPromo(){
        $today = new \DateTime('now');
        $target = $this->startDate;
        $interval = $today->diff($target);
        if($interval->m >= 1){
            return true;
        }
    }
}
tattali commented 4 years ago

It seems to work for me when I comment the booking and formula entity dependencies that I don't have.

You still have a 404 or you have a 500 when you check your network console ?

plus I had to clean the cache by removing the var folder

Thanks for your answer

missCorie commented 4 years ago

https://127.0.0.1:8000/fc-load-events return error 500

\tattali\calendar-bundle\src\Controller\CalendarController.php (line 37) DateTime::__construct() expects parameter 1 to be string, null given $start = new \DateTime($request->get('start'));

missCorie commented 3 years ago

I finally found the solution !!! a 'string' was missing as the first parameter of new Event( 'string', startDate, enDate )