Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

Loomix's avatar

Using FullCalendar with MySQL Database as a source

I want to use FullCalendar (https://fullcalendar.io/docs/events-json-feed) in my Laravel project but I am unsure how to get the data for the calendar from the database. The manual says: "An event source is anything that provides FullCalendar with data about events. It can be a simple array, an event-generating function that you define, a URL to a json feed, or a Google Calendar feed."

So what about a DB as a source? Do I really have to create a JSON file each time I fetch data from my database? What about writing back the data to the DB (e.g. after a user extended the time period of an event by drag and drop)? The manual says

var calendar = new Calendar(calendarEl, {
  events: '/myfeed.php'
});

But usually DB access in Laravel is like

    public function index(User $model)
    {
        return view('users.index', ['users' => $model->with('role')->get()]);
    }

so I can access the data in my view like @foreach($users as $user)and do anything. Could someone give a me a hint here how to proceed? What is it about this JSON feed in FullCalendar, is it even the right way? Thanks.

0 likes
15 replies
bobbybouwmann's avatar

What they mean with a JSON feed is that you have an endpoint that converts your database records to JSON and returns that as a result. So instead of returning a view you simply return JSON

public function index(User $model)
{
    return response()->json(['users' => $model->with('role')->get()]);
}

In your case you probably don't want to return users, you want to return events. You also probably don't need all the fields that are available in the database for that record. Laravel has something called API-resources that are perfect for this. You can use it to convert an object or model to a certain array format. Laravel will then automatically convert it to JSON for you.

You can read more about it here: https://laravel.com/docs/7.x/eloquent-resources

1 like
Loomix's avatar

Thanks, I read the docs about Eloquent Resources and I now understand what is meant by JSON feed. But I still don't get it about the "other end" of the process: When I pass the array with JSON info to my view or fullcalendar js, how do I process it? The manual of fullcalendar speaks of a my-resource-script.php

var calendar = new Calendar(calendarEl, {
  resources: '/my-resource-script.php'
});

but what does this php file contain in case of Laravel, do they mean the resource file like

namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\ResourceCollection;

class TestResourceCollection extends ResourceCollection
{
    /**
     * Transform the resource collection into an array.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return array
     */
    public function toArray($request)
    {
        return parent::toArray($request);
    }
}

Or in other words: How do I fetch the JSON array in my view with fullcalendar and display the data?

guybrush_threepwood's avatar

Hi @loomix

FullCalendar will do that for you automatically as long as you initialize it and provide the resources parameter.

From the Docs:

A URL of a JSON feed that the calendar will fetch Event Objects from.

FullCalendar will visit the URL whenever it needs new event data. This happens when the user clicks prev/next or changes views. FullCalendar will determine the date-range it needs events for and will pass that information along in GET parameters.

The GET parameter names will be determined by the startParam and endParam options. ("start" and "end" by default).

The values of these parameters will be ISO8601 date strings (like 2013-12-01T00:00:00-05:00). For precise behavior, see the timeZone docs.

Consider the following script:

var calendar = new Calendar(calendarEl, { events: '/myfeed.php' });

Here is a URL that FullCalendar might visit:

/myfeed.php?start=2013-12-01T00:00:00-05:00&end=2014-01-12T00:00:00-05:00

The only thing you need to worry about is setting up the route/controller for the Feed, filtering the events by the start and end datetime parameter provided and formatting the output to be compatible with FullCalendar:

  timeZone: 'UTC',
  events: [
    {
      id: 'a',
      title: 'my event',
      start: '2018-09-01'
    }
  ]

More info on available fields: https://fullcalendar.io/docs/event-object

Loomix's avatar

Could you give a code example assuming I have a table "events" with the fields "id", "title", "start", "end"? I have read the doc you are quoting and I understand the info is passed as a parameter but I don't see how I could use that. Still, I also don't understand what myfeed.php is or contains when using Laravel.

guybrush_threepwood's avatar

From the top of my head:

Initialize your calendar element ("calendarEl"):

var calendar = new Calendar(calendarEl, {
  events: '/event-feed'
});

Add the route:

Route::get('/event-feed', 'EventController@feed');

Add the feed() method to your EventController:

public function feed()
{
    $start = Carbon::create($request->input('start'));
    $end = Carbon::create($request->input('end'));

    $events = UserEvent::select('id', 'title', 'start', 'end')
        ->whereDate('start', '>=', $start)->whereDate('end', '<=', $end)->get();

    $eventOutput = [
        'timeZone' => 'UTC',
        'events' => $events
    ];

    return json_encode($eventOutput);
}

I'm sure there's some extra work to be done such as converting the event output dates to ISO8601 format.

You can do that by adding extra accesors to your Event model: https://stackoverflow.com/a/40401083

1 like
Loomix's avatar

Thanks a lot, that's some meat I can put my teeth in. Will take that as a starting point and report back.

1 like
Loomix's avatar

There is an issue with the request and the event feed. The request 'start' and 'end' from the calendar to the controller contains always (no matter what day, week,month I select) the same dates (both 2019-12-31T23:00:00.000000Z) and the events do not show up in the calendar.

My calendar:

var FEED_URL = "{{url('/')}}" + "/event-feed";
var calendar = new FullCalendar.Calendar(calendarEl, {
plugins: [ 'interaction', 'resourceTimeline' ],
timeZone: 'UTC',
defaultView: 'resourceTimelineWeek',
(...)
  resources: [
    {
      id: 'a',
      title: 'Room A'
    }
  ],
  events: [
    {
      url: FEED_URL,
      failure: function() {
        alert('there was an error while fetching events!');
      },
    }]
        });
        calendar.render();
});

My controller:

    public function feed(Request $request)
    {
      $left = Carbon::create($request->input('start'));
        // left = 2019-12-31T23:00:00.000000Z (always)
      $right = Carbon::create($request->input('end'));
        // right = 2019-12-31T23:00:00.000000Z (always)

    //only for testing:      
    $events = array();
    $events['id'] = 1;
    $events['resourceId'] = 'a';
    $events['title'] = 'Test';
    $events['start'] = '2020-06-12T23:00:00.000000Z';
    $events['end'] = '2020-06-13T23:00:00.000000Z';
    //only for testing the request:
    $events['left'] = $left;
    $events['right'] = $right;
     
     return json_encode($events);
    }

My route:

Route::get('/event-feed', 'EventController@feed');

FEED_URL is correctly http://localhost/matpro/public/event-feed and contains {"id":1,"resourceId":"a","title":"Test","start":"2020-06-12T23:00:00.000000Z","end":"2020-06-13T23:00:00.000000Z"}

When I enter the event directly to the calendar everything is working fine. What am I missing?

guybrush_threepwood's avatar

Hi @loomix

Could you show me the start/end parameters before being converted to Carbon (so I can tell if it's a FullCalendar problem or a Carbon problem)?

dd($request->input('start'));
dd($request->input('end'));

Could you also paste the entire FullCalendar initialization script so I can see how you're setting the initial date?

By the way, the FEED_URL has an extra starting slash. It should be:

var FEED_URL = "/event-feed";

Another thing I noticed is that your events array seems to be missing a level.

Try something like:

$events = [
    [
        'id' => 1,
        'resourceId' => 'a',
        'title' => 'Test',
        'start' => '2020-06-12T23:00:00.000000Z',
        'end' => '2020-06-13T23:00:00.000000Z'
    ]
];
Loomix's avatar

The parameters directly from $request->input('start') and $request->input('end')are null. From Carbon both start and end are 2019-12-31T23:00:00.000000Z. So obviously, there's an issue with the request. I converted the $requestto JSON and there's nothing in:

{"attributes":{},"request":{},"query":{},"server":{},"files":{},"cookies":{},"headers":{}}

The slash you mention is also in my URL. If using var FEED_URL = "/event-feed"; or var FEED_URL = "{{url('/')}}" + "/event-feed"; makes no difference, it results in the URL http://localhost/matpro/public/event-feed, which is how it should be, right?

Your approach adding another level throws a failure from the calendar but I added it by

$eventOutput = [
  'events' => $events
];
return json_encode($eventOutput);

and now the JSON is:

{"events":{"id":1,"title":"Test","start":"2020-06-12T23:00:00.000000Z","end":"2020-06-13T23:00:00.000000Z","left":null,"right":null}}

Here is my full calendar. I don't set initial date, because the manual says "defaultDate: When not specified, this value defaults to the current date."

var FEED_URL = "{{url('/')}}" + "/event-feed";
alert (FEED_URL);
document.addEventListener('DOMContentLoaded', function() {
        var calendarEl = document.getElementById('calendar');
        var calendar = new FullCalendar.Calendar(calendarEl, {
        schedulerLicenseKey: 'GPL-My-Project-Is-Open-Source',
        locale: 'de',
         plugins: [ 'interaction', 'resourceTimeline' ],
          timeZone: 'UTC',
         defaultView: 'resourceTimelineWeek',
          editable: true,
          titleFormat: { year: 'numeric', month: '2-digit', day: '2-digit' },  
          views: {
            week: {
              type: 'resourceTimelineWeek',
              duration: { weeks: 1 },
              slotDuration: {days: 1},
              buttonText: 'Woche'
            },
            d14: {
              type: 'resourceTimelineWeek',
              duration: { weeks: 2 },
              slotDuration: {days: 1},
              buttonText: '14 Tage'
            },
            month: {
              type: 'resourceTimelineWeek',
              duration: { days: 31 },
              slotDuration: {days: 1},
              buttonText: 'Monat'
            } 
          }, 
          header: {
            center: 'week,d14,month',
            right: 'today prev,next'
          },
          slotLabelFormat: [
            { month: 'long', year: 'numeric' }, // top level of text
            { weekday: 'short', day: '2-digit' } // lower level of text
          ],
          resourceLabelText: 'Ressource',
  resources: [
    {
      id: 'a',
      title: 'Room A'
    }
  ],
  events: {
    url: FEED_URL,
    method: 'GET',
    dateType:'json',
    failure: function() {
      alert('there was an error while fetching events!');
    },
    success: function() {
      alert('we have the data');
    },
  }          
 });
calendar.render();
});
guybrush_threepwood's avatar

I guess it has something to do with one of the plugins you're using. I've made a basic implementation and it worked as expected:

Route

use Carbon\Carbon;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;

Route::get('/event-feed', function (Request $request) {
    $left = Carbon::create($request->input('start'));
    // left = 2019-12-31T23:00:00.000000Z (always)
    $right = Carbon::create($request->input('end'));
    // right = 2019-12-31T23:00:00.000000Z (always)

    //only for testing:
    $eventOutput = [
        [
            'id' => 1,
            'resourceId' => 'a',
            'title' => 'Test',
            'start' => '2020-06-11T00:00:00.000000Z',
            'end' => '2020-06-11T02:00:00.000000Z',
            'left' => $left,
            'right' => $right,
        ]
     ];

    return json_encode($eventOutput);
});

Blade file

<!doctype html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">

    <!-- CSRF Token -->
    <meta name="csrf-token" content="{{ csrf_token() }}">

    <title>{{ config('app.name', 'Laravel') }}</title>

    <!-- Scripts -->
    <script src="https://unpkg.com/@fullcalendar/[email protected]/main.min.js"></script>
    <script src="https://unpkg.com/@fullcalendar/[email protected]/main.min.js"></script>

    <!-- Styles -->
    <link href="https://unpkg.com/@fullcalendar/[email protected]/main.min.css" rel="stylesheet">
    <link href="https://unpkg.com/@fullcalendar/[email protected]/main.min.css" rel="stylesheet">
</head>
<body>
    <div id="app">
        <main class="py-4">
            <div class="container">
                <div class="row justify-content-center">
                    <div class="col-md-8">
                        <div class="card">
                            <div id="calendar">
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </main>
    </div>

<script>
    document.addEventListener('DOMContentLoaded', function() {
        var FEED_URL = "{{url('/')}}" + "/event-feed";

        var calendarEl = document.getElementById('calendar');

        var calendar = new FullCalendar.Calendar(calendarEl, {
            plugins: [ 'dayGrid' ],
            events: {
                url: FEED_URL
            }
        });

        calendar.render();
    });
</script>

</body>
</html>

The calendar initialized correctly and the contents were requested to http://test.test/event-feed?start=2020-05-31T00%3A00%3A00-03%3A00&end=2020-07-12T00%3A00%3A00-03%3A00.

The response of the request was:

[{"id":1,"resourceId":"a","title":"Test","start":"2020-06-11T00:00:00.000000Z","end":"2020-06-11T02:00:00.000000Z","left":"2020-05-31T03:00:00.000000Z","right":"2020-07-12T03:00:00.000000Z"}]

Notice I had to make a small change to the event-feed output in order to return an array of event objects.

1 like
Loomix's avatar

It's working now here, event appears in calendar and it's not a plugin issue but the format of the event-feed:

    $eventOutput = [
        [
            'id' => 1,
            'resourceId' => 'a',
            'title' => 'Test',
            'start' => '2020-06-11T00:00:00.000000Z',
            'end' => '2020-06-11T02:00:00.000000Z',
            'left' => $left,
            'right' => $right,
        ]
     ];

works but

    $events = array();
    $events['id'] = 1;
    $events['resourceId'] = 'a';
    $events['title'] = 'Test';
    $events['start'] = '2020-06-12T23:00:00.000000Z';
    $events['end'] = '2020-06-13T23:00:00.000000Z';
    //only for testing the request:
    $events['left'] = $request->input('start');
    $events['right'] = $request->input('end');
          $eventOutput = [
        'events' => $events
      ]; 
return json_encode($eventOutput);

does not. I think it's the {"events":in my json feed that prevents it from working.

But still my request variables are null. And what version of fullcalendar are you using, I am using 4 (final).

1 like
Loomix's avatar

Still my request variables are null. And what version of fullcalendar are you using, I am using 4 (final).

guybrush_threepwood's avatar

Hi @loomix

I used 4.4.2, but just the core JS + dayGrid plugin for a basic demo:

    <!-- Scripts -->
    <script src="https://unpkg.com/@fullcalendar/[email protected]/main.min.js"></script>
    <script src="https://unpkg.com/@fullcalendar/[email protected]/main.min.js"></script>

    <!-- Styles -->
    <link href="https://unpkg.com/@fullcalendar/[email protected]/main.min.css" rel="stylesheet">
    <link href="https://unpkg.com/@fullcalendar/[email protected]/main.min.css" rel="stylesheet">

Please or to participate in this conversation.