diff --git a/.editorconfig b/.editorconfig index b9f9286..05c83fe 100755 --- a/.editorconfig +++ b/.editorconfig @@ -15,10 +15,6 @@ charset = utf-8 trim_trailing_whitespace = true insert_final_newline = true -[*.feature] -indent_style = space -indent_size = 2 - [*.json] indent_style = space indent_size = 2 @@ -34,14 +30,15 @@ indent_size = 4 indent_style = space indent_size = 4 -[*.yml] +[*.yaml] indent_style = space indent_size = 4 trim_trailing_whitespace = false -[.circleci/config.yml] +[*.yml] indent_style = space -indent_size = 2 +indent_size = 4 +trim_trailing_whitespace = false [.gitmodules] indent_style = tab @@ -50,7 +47,7 @@ indent_style = tab indent_style = space indent_size = 4 -[.styleci.yml] +[.php_cs.xml.dist] indent_style = space indent_size = 2 @@ -58,14 +55,6 @@ indent_size = 2 indent_style = space indent_size = 2 -[appveyor.yml] -indent_style = space -indent_size = 2 - -[behat.yml] -indent_style = space -indent_size = 2 - [composer.json] indent_style = space indent_size = 4 diff --git a/README.md b/README.md index 8774071..b162075 100755 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ The source of the documentation is stored in the `src/Resources/doc/` folder in ### Installation 1. [Download CalendarBundle using composer](#1-download-calendarbundle-using-composer) -2. [Create the listener](#2-create-the-listener) +2. [Create the subscriber](#2-create-the-subscriber) 3. [Add styles and scripts in your template](#3-add-styles-and-scripts-in-your-template) #### 1. Download CalendarBundle using composer @@ -45,42 +45,49 @@ calendar: resource: "@CalendarBundle/Resources/config/routing.yaml" ``` -#### 2. Create the listener -You need to create a listener class to load your data into the calendar and register it as a service. +#### 2. Create the subscriber +You need to create a subscriber class to load your data into the calendar. -This listener must be called when the event `calendar.set_data` is launched. +This subscriber must be registered only if autoconfigure is false. ```yaml # config/services.yaml services: # ... - App\EventListener\CalendarListener: - tags: - - { name: 'kernel.event_listener', event: 'calendar.set_data', method: load } + App\EventSubscriber\CalendarSubscriber: ``` -Then, create the listener class to fill the calendar +Then, create the subscriber class to fill the calendar -See the [doctrine listener example](src/Resources/doc/doctrine-crud.md#full-listener) +See the [doctrine subscriber example](src/Resources/doc/doctrine-crud.md#full-subscriber) ```php -// src/EventListener/CalendarListener.php +// src/EventSubscriber/CalendarSubscriber.php 'onCalendarSetData', + ]; + } + + public function onCalendarSetData(CalendarEvent $calendar) { $start = $calendar->getStart(); $end = $calendar->getEnd(); $filters = $calendar->getFilters(); - // You may want to make a custom query to fill the calendar + // You may want to make a custom query from your database to fill the calendar $calendar->addEvent(new Event( 'Event 1', diff --git a/composer.json b/composer.json index bb40708..c96622a 100644 --- a/composer.json +++ b/composer.json @@ -2,7 +2,12 @@ "name": "tattali/calendar-bundle", "type": "symfony-bundle", "description": "Provides event calendar for your Symfony 4 project. Compatible with Doctrine ORM & ODM, and API like Google Calendar.", - "keywords": ["fullcalendar", "calendar", "symfony", "symfony calendar"], + "keywords": [ + "fullcalendar", + "calendar", + "symfony", + "symfony calendar" + ], "homepage": "https://github.com/tattali/CalendarBundle", "license": "MIT", "authors": [ diff --git a/phpcs.xml.dist b/phpcs.xml.dist old mode 100644 new mode 100755 index 28757da..7167a3b --- a/phpcs.xml.dist +++ b/phpcs.xml.dist @@ -3,7 +3,6 @@ - @@ -13,7 +12,6 @@ - @@ -21,4 +19,7 @@ + + src/ + tests/ diff --git a/phpunit.xml.dist b/phpunit.xml.dist index f53d464..39d3796 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -9,7 +9,7 @@ - + diff --git a/src/Controller/CalendarController.php b/src/Controller/CalendarController.php index 01ac9af..6997d95 100755 --- a/src/Controller/CalendarController.php +++ b/src/Controller/CalendarController.php @@ -11,6 +11,7 @@ use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; +use Symfony\Contracts\EventDispatcher\EventDispatcherInterface as ContractsEventDispatcherInterface; class CalendarController extends AbstractController { @@ -39,9 +40,9 @@ public function loadAction(Request $request): Response $filters = $request->get('filters', '{}'); $filters = \is_array($filters) ? $filters : json_decode($filters, true); - $event = $this->eventDispatcher->dispatch( - CalendarEvents::SET_DATA, - new CalendarEvent($start, $end, $filters) + $event = $this->dispatchWithBC( + new CalendarEvent($start, $end, $filters), + CalendarEvents::SET_DATA ); $content = $this->serializer->serialize($event->getEvents()); @@ -52,4 +53,13 @@ public function loadAction(Request $request): Response return $response; } + + public function dispatchWithBC($event, string $eventName) + { + if ($this->eventDispatcher instanceof ContractsEventDispatcherInterface) { + return $this->eventDispatcher->dispatch($event, $eventName); + } + + return $this->eventDispatcher->dispatch($eventName, $event); + } } diff --git a/src/Event/CalendarEvent.php b/src/Event/CalendarEvent.php index 2e6fee9..905955c 100644 --- a/src/Event/CalendarEvent.php +++ b/src/Event/CalendarEvent.php @@ -5,9 +5,14 @@ namespace CalendarBundle\Event; use CalendarBundle\Entity\Event; +use CalendarBundle\Event\Event as BaseEvent; use DateTimeInterface; -use Symfony\Component\EventDispatcher\Event as BaseEvent; +/** + * This event is triggered before the serialization of the events. + * + * This event allows you to fill the calendar with your data. + */ class CalendarEvent extends BaseEvent { /** diff --git a/src/Event/Event.php b/src/Event/Event.php new file mode 100644 index 0000000..8b148e0 --- /dev/null +++ b/src/Event/Event.php @@ -0,0 +1,22 @@ +addOption( ); ``` -#### Full listener +#### Full subscriber -Full listener with `Booking` entity. Modify it to fit your needs. +Full subscriber with `Booking` entity. Modify it to fit your needs. ```php -// src/EventListener/CalendarListener.php +// src/EventSubscriber/CalendarSubscriber.php router = $router; } - public function load(CalendarEvent $calendar): void + public static function getSubscribedEvents() + { + return [ + CalendarEvents::SET_DATA => 'onCalendarSetData', + ]; + } + + public function onCalendarSetData(CalendarEvent $calendar) { $start = $calendar->getStart(); $end = $calendar->getEnd(); @@ -280,7 +287,7 @@ class CalendarListener // Change booking.beginAt by your start date property $bookings = $this->bookingRepository ->createQueryBuilder('booking') - ->where('booking.beginAt BETWEEN :start and :end') + ->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() @@ -325,16 +332,19 @@ class CalendarListener Then create the calendar template add a link to the `booking_new` form + ```twig Create new booking ``` and include the `calendar-holder` + ```twig {% include '@Calendar/calendar.html' %} ``` Full template: + ```twig {# templates/booking/calendar.html.twig #} {% extends 'base.html.twig' %} @@ -389,13 +399,14 @@ Full template: {% endblock %} ``` -* Now visit: http://localhost:8000/booking/calendar + +* 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 listener: +* 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 diff --git a/tests/Controller/CalendarControllerTest.php b/tests/Controller/CalendarControllerTest.php index 302d2e5..86a741a 100755 --- a/tests/Controller/CalendarControllerTest.php +++ b/tests/Controller/CalendarControllerTest.php @@ -14,6 +14,7 @@ use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; +use Symfony\Contracts\EventDispatcher\EventDispatcherInterface as ContractsEventDispatcherInterface; class CalendarControllerTest extends TestCase { @@ -46,10 +47,18 @@ public function testItProvidesAnEventsFeedForACalendar() $this->calendarEvent->getEvents()->willReturn([$this->event]); - $this->eventDispatcher - ->dispatch(CalendarEvents::SET_DATA, Argument::type(CalendarEvent::class)) - ->willReturn($this->calendarEvent) - ; + $dispatcher = $this->getEventDispatcherMock(); + if ($dispatcher instanceof ContractsEventDispatcherInterface) { + $this->eventDispatcher + ->dispatch(Argument::type(CalendarEvent::class), CalendarEvents::SET_DATA) + ->willReturn($this->calendarEvent) + ; + } else { + $this->eventDispatcher + ->dispatch(CalendarEvents::SET_DATA, Argument::type(CalendarEvent::class)) + ->willReturn($this->calendarEvent) + ; + } $data = json_encode([ [ @@ -85,11 +94,18 @@ public function testItNotFindAnyEvents() $this->request->get('filters', '{}')->willReturn('{}'); $this->calendarEvent->getEvents()->willReturn([$this->event]); - - $this->eventDispatcher - ->dispatch(CalendarEvents::SET_DATA, Argument::type(CalendarEvent::class)) - ->willReturn($this->calendarEvent) - ; + $dispatcher = $this->getEventDispatcherMock(); + if ($dispatcher instanceof ContractsEventDispatcherInterface) { + $this->eventDispatcher + ->dispatch(Argument::type(CalendarEvent::class), CalendarEvents::SET_DATA) + ->willReturn($this->calendarEvent) + ; + } else { + $this->eventDispatcher + ->dispatch(CalendarEvents::SET_DATA, Argument::type(CalendarEvent::class)) + ->willReturn($this->calendarEvent) + ; + } $data = ''; @@ -105,4 +121,11 @@ public function testItNotFindAnyEvents() $this->assertEquals($data, $response->getContent()); $this->assertEquals(Response::HTTP_NO_CONTENT, $response->getStatusCode()); } + + private function getEventDispatcherMock() + { + return $this->getMockBuilder(EventDispatcherInterface::class) + ->disableOriginalConstructor() + ->getMock(); + } }