In the first part of this series we saw how to integrate fullCalendar and CakePHP so you can use the calendar in your Cake application. But obviously, a calendar is not very useful without events to show.
In this part, we’ll see how to populate fullCalendar with events from a MySQL table, served by CakePHP.
The first thing to do is to create an event table in the database you’re using with your cake application. You can use something along the following lines:
'id' INT(11) NOT NULL AUTO_INCREMENT,
'title' VARCHAR(50) NOT NULL,
'allday' tinyint(1) NOT NULL,
'start' datetime NOT NULL,
'end' datetime DEFAULT NULL,
'editable' tinyint(1) NOT NULL,
PRIMARY KEY ('id')
) ENGINE=MyISAM DEFAULT CHARSET=armscii8 AUTO_INCREMENT=1 ;
This table has most of what you need.
- id is CakePHP’s unique identifier. In the most simple implementation, we’ll use it as the event’s id in the events data we pass into fullCalendar. Notice that you can’t use this id directly for a recurring event – as fullCalendar handles those differently.
- title is the event’s title. This string is displayed on the calendar when you view it.
- allday is a flag to signal that the event spans a full day. If this flag is on, fullCalendar ignores the start and end fields.
- start and end are the event’s start and end time.
- editable is a flag we use to signal whether this event can be deleted, moved or edited. This isn’t required – I use it because I have a requirement to enter hard-coded events that users can’t change (e.g. Easter weekend).
To feed the table’s events to the calendar, you need to create the model file:
var $name = 'Event';
}
?>
There are several ways to feed the events into the calendar, but the most elegant way is to configure fullCalendar with a json event source. This way, the calendar asks the event source for events in a time range, and we can lazy-load the events to display in a nice and efficient way.
To configure an event source to fullCalendar, you’ll need to enter the following in the calendar’s init method:
$(document).ready(function() {
$('#calendar').fullCalendar({
events: "/events/feed",
});
}
// ]]></script>
Every time the calendar is loaded, or when you navigate to a different day, week or month – the calendar will fire an ajax call to /events/feed and ask for the set of events to display. The format of this call will be:
- The _ parameter is just to ensure that no caching is used.
- The start parameter is the Unix timestamp of the beginning of the required events date range.
- The end parameter is the Unix timestamp of the end of the required events date range.
The request above is fired by fullCalendar when it needs to display the month of March 2010. The 1267354800 Unix timestamp corresponds to 1/3/2010 00:00:00, and the 1270382400 timestamp is 31/3/2010 23:59:59.
As a response, fullCalendar expects a valid json array of events to display. We will use the feed() method in events_controller.php to create this array and return it to the calendar.
//1. Transform request parameters to MySQL datetime format.
$mysqlstart = date( 'Y-m-d H:i:s', $this->params['url']['start']);
$mysqlend = date('Y-m-d H:i:s', $this->params['url']['end']);
//2. Get the events corresponding to the time range
$conditions = array('Event.start BETWEEN ? AND ?'
=> array($mysqlstart,$mysqlend));
$events = $this->Event->find('all',array('conditions' =>$conditions));
}
After we do that, the $events array holds the set of events that begin somewhere in the date-range passed by fullCalendar on its ajax call. All that’s left now is to create a valid json array from $events and return it to fullCalendar.
$rows = array();
for ($a=0; count($events)> $a; $a++) {
//Is it an all day event?
$all = ($events[$a]['Event']['allday'] == 1);
//Create an event entry
$rows[] = array('id' => $events[$a]['Event']['id'],
'title' => $events[$a]['Event']['title'],
'start' => date('Y-m-d H:i', strtotime($events[$a]['Event']['start'])),
'end' => date('Y-m-d H:i',strtotime($events[$a]['Event']['end'])),
'allDay' => $all,
);
}
//4. Return as a json array
Configure::write('debug', 0);
$this->autoRender = false;
$this->autoLayout = false;
$this->header('Content-Type: application/json');
echo json_encode($rows);
The last four lines above are where the magic happens.
The first three tell Cake to not bother with a layout – and just return the result as pure json output.
The last line outputs the $rows array we created as a json array. The resulting ajax response sent to fullCalendar should resemble this:
The calendar should then display your events on its view.
If for some reason the calendar does not display your events, check that it receives a well-formed json array. The easiest way to validate it would be using firebug. Check the console, and see that it is able to parse the array you pass in:
The fullCalendar and CakePHP Series:
- Part 1: Set up
- Part 2: Creating an event source
- Part 3: Adding events
- Part 4: Editing events
- Part 5: Dragging and resizing
Popularity: 100% [?]
43 Responses to FullCalendar and CakePHP part 2 – Create events source
Leave a Reply Cancel reply
Recent Comments
- Medovarszki: This post saved my hair from falling out but yeah, I beat my head against the wall now too
- Shehryar: Probably the ebst spring web mvc tutorial I have read, explain everything in great detail. i loved it, this...
- armand: You do not resize the image. You just display it smaller using html tag attributes. It would be nice to...
- COTP: ** Just to clarify, in CakeErrorController.php (the copy in app/Controller/) public function beforeRender() {...
- COTP: For CakePHP 2.0+, you can copy lib/Cake/Controller/CakeErrorC ontroller.php to app/Controller/CakeErrorCon...
- Medovarszki: This post saved my hair from falling out but yeah, I beat my head against the wall now too
Categories
- Android (1)
- appengine (3)
- Be nice to your users (6)
- CakePHP (13)
- General (5)
- Googlemaps (3)
- Java (11)
- javaScript (4)
- jQuery (11)
- Seam (2)
- Security (4)
- Spring MVC (1)
- Spring Webflow (2)
- User Interface (5)
- Wordpress (2)
Archives
- January 2012 (2)
- December 2011 (1)
- July 2011 (2)
- June 2011 (4)
- May 2011 (1)
- December 2010 (3)
- November 2010 (1)
- August 2010 (2)
- July 2010 (2)
- June 2010 (4)
- May 2010 (4)
- April 2010 (5)
- March 2010 (3)


now interacting is what made this more interesting
Hi, someone can help me?
My events don’t appear in calendar.
I’m using cake 1.3 and jQ 1.3.2.
i don’t understand, i follow this tuto.
When i look firebug, i don’t see a JSON response…
@omer – I didn’t actually try this one in Cake 1.3 yet, or with jQuery 1.3.2.
What jQuery UI version are you using?
Are you seeing the Ajax request going to the server?
Hi,
thanks for your response
i’m using UI 1.7.3,
humm i don’t understand, now is working, i change anything … LoL
So far this guide has been excellent but I have hit a problem. I have a fresh install of CakePHP and Fullcalendar but i do not seem to be able to return a json array to the calendar. Instead Firebug reports:
“GET http://localhost:8888/testsite/events/feed?_=1280660112165&start=1280617200&end=1284246000 – 404 Not Found”.
Despite following this guide to the letter, I fear (as a CakePHP beginner) i have missed something core to the setup that might have been so simple, it was overlooked in this guide. I would really appreciate it if someone could take a look. As I could not find your email address anywhere, I have uploaded files here:
http://rapidshare.com/files/410350210/testsite.zip
Thanks for any help in advance!
@Matt – the 404 you are getting is because something isn’t found. I can’t download your files from rapidshare here, but I would guess that the feed method isn’t defined on your events controller.
Thanks for getting back to me, this is what i have in my events controller (/app/controllers/events_controller.php):
params['url']['start']);
$mysqlend = date(‘Y-m-d H:i:s’, $this->params['url']['end']);
//2. Get the events corresponding to the time range
$conditions = array(‘Event.start BETWEEN ? AND ?’
=> array($mysqlstart,$mysqlend));
$events = $this->Event->find(‘all’,array(‘conditions’ =>$conditions));
//3. Create the json array
$rows = array();
for ($a=0; count($events)> $a; $a++) {
//Is it an all day event?
$all = ($events[$a]['Event']['allday'] == 1);
//Create an event entry
$rows[] = array(‘id’ => $events[$a]['Event']['id'],
‘title’ => $events[$a]['Event']['title'],
‘start’ => date(‘Y-m-d H:i’, strtotime($events[$a]['Event']['start'])),
‘end’ => date(‘Y-m-d H:i’,strtotime($events[$a]['Event']['end'])),
‘allDay’ => $all,
);
}
//4. Return as a json array
Configure::write(‘debug’, 0);
$this->autoRender = false;
$this->autoLayout = false
$this->header(‘Content-Type: application/json’);
echo json_encode($rows);
}
?>
After playing around with it a little i think im making some progress, i now get a error 500 Internal Server error. From what i can tell, the events_controller is in the right place, but its not returning a json response. Im stuck at either my Database is not setup correctly or $this->header(‘Content-Type: application/json’); is not returning the type correctly or CakePHP doesnt understand what content type JSON is…?
Sorry seemed to loose the start of that copy+paste:
function feed() {
//1. Transform request parameters to MySQL datetime format.
$mysqlstart = date( ‘Y-m-d H:i:s’, $this->params['url']['start']);
$mysqlend = date(‘Y-m-d H:i:s’, $this->params['url']['end']);
//2. Get the events corresponding to the time range
$conditions = array(‘Event.start BETWEEN ? AND ?’
=> array($mysqlstart,$mysqlend));
$events = $this->Event->find(‘all’,array(‘conditions’ =>$conditions));
//3. Create the json array
$rows = array();
for ($a=0; count($events)> $a; $a++) {
//Is it an all day event?
$all = ($events[$a]['Event']['allday'] == 1);
//Create an event entry
$rows[] = array(‘id’ => $events[$a]['Event']['id'],
‘title’ => $events[$a]['Event']['title'],
‘start’ => date(‘Y-m-d H:i’, strtotime($events[$a]['Event']['start'])),
‘end’ => date(‘Y-m-d H:i’,strtotime($events[$a]['Event']['end'])),
‘allDay’ => $all,
);
}
//4. Return as a json array
Configure::write(‘debug’, 0);
$this->autoRender = false;
$this->autoLayout = false
$this->header(‘Content-Type: application/json’);
echo json_encode($rows);
}
@Matt – just to recap these comments:
The problem was not related to json but rather due to misconfigured controller.
To debug such errors, the first thing to do is setting debug level to 2 in app/config/core.php.
Hi, and thank you for these tutorials. I’m having a bit of a problem with part 2, and was hoping you’d be able to help.
I’ve got the calendar showing up (from part 1), and have added an event to the database and followed the steps above. However, when I load the page, the event is not there – I can still see the blank calendar, but the event is not listed.
I checked in Firebug, and I’m getting the following error:
Notice (8): Undefined variable: html [APP\views\elements\header.ctp, line 14]
The line in question is in the area of the page, and is:
css(‘school.css’); ?>
It worked fine until I added the calendar, so I suspect it may be that something’s interfering with the $html variable – could that be the case? Any ideas would be much appreciated.
Thanks again,
Sharon
Never mind – I’d missed out a couple of lines in copying the code across. Sorry!
@Sharon – No worries, have a good one
Thank you so much for posting this. Helped me integrate an existing event d.b. with FullCalendar *super* quickly!
Thank you for your detailed instruction.
Let me put tips for beginner like me.
Correct me if I am wrong.
If using this FullCalendar under bigger application.
Like, http://localhost/MyApplication/events/calendar
I needed to put .. two dot before /events/
events: “../events/feed”,
without it, will not call function feed , so data never show up.
(See fire bug saying http://localhost/events/feed?_= 404 not found.)
Because It is accessing wrong layer.
I should have read carefully…
It took me a day to figure out T.T
I do not want any beginner stuck like me.
Good luck !!
@MikeMF – good one! Thanks for sharing
i follow the tutorial, and got a weird bug.
I’m using cake 1.3.7 and jquery 1.4.
When i do
$mysqlend = date(‘Y-m-d H:i:s’, $this->params['url']['end']);
$this->params['url']['start'] is empty
if i try to echo it, it’s just
@luc – I haven’t tried this with Cake 1.3.7.
Did you try printing $this->params with print_r ? See what you actually get?
Also – Can you have a look with firebug – see what is the actual request that gets sent from your browser to the server?
Cheers
Duck,
Excellent work! I’m using it on my project and everything is working fine. But im facing a problem to update the calendar events. Lets say after loading there is a drop down box at the top and depends on that it supposed to update the calendar event. How do i do it? Also when i go to next or prev month and i try to use drop down it goes back to the current month. What am i missing?
Thanks
Junal
@Junal – is there an ajax happening on change of the drop down?
If so, then you need to update the date range returned from the events feed.
Hi,
i have a problem. my json is correct e.g
0: {id:1, titulo:TESTE, start:2011-07-13 22:00, end:2011-07-13 23:00, todo_dia:true,…}
detalhes: “TESTEEEEEEEE”
end: “2011-07-13 23:00″
id: “1″
start: “2011-07-13 22:00″
titulo: “TESTE”
todo_dia: true
url: “/consultas/view/1″
1: {id:2, titulo:teste2, start:2011-07-13 23:04, end:2011-07-13 00:04, todo_dia:false,…}
detalhes: “testando2″
end: “2011-07-13 00:04″
id: “2″
start: “2011-07-13 23:04″
titulo: “teste2″
todo_dia: false
url: “/consultas/view/2″
But i have a problem in a console debug.
103Uncaught TypeError: Cannot call method ‘replace’ of undefined
Lafullcalendar.min.js:103
ffullcalendar.min.js:83
afullcalendar.min.js:81
afullcalendar.min.js:65
aafullcalendar.min.js:21
lafullcalendar.min.js:21
Ffullcalendar.min.js:28
l.ajax.successfullcalendar.min.js:29
d.extend._Deferred.f.resolveWithjquery-1.5.2.min.js:16
vjquery-1.5.2.min.js:16
d.support.ajax.d.ajaxTransport.send.cjquery
@lucas – this seems like a fullcalendar issue. What version are you using there?
how do I make recurring events, and how do I Use a feed method?
thanks!!!
@Yecenia: http://code.google.com/p/fullcalendar/issues/detail?id=116 – this seems to still be an open issue on the client side, and I am of the opinion that recurring events should be handled server side anyway.
As for the feed method: there’s an example in the post here of how you define a URL that feeds events into fullcalendar.
cheers
Hello: I need filter events by user_id, but I don’t know, I should happen to the feed function to perform this query, so I select the user which is in a combobox.
this is my code:
//1. Transform request parameters to MySQL datetime format.
$mysqlstart = date('Y-m-d H:i:s', $this->params['url']['start']);
$mysqlend = date('Y-m-d H:i:s', $this->params['url']['end']);
//2. Get the events corresponding to the time range
//$conditions = array('Event.start BETWEEN ? AND ?' => array($mysqlstart, $mysqlend),'Event.user_id'=>'19');
//$events = $this->Event->find('all', array('conditions' => $conditions));
$conditions = array('Event.user_id'=>$id);
$events=$this->Event->find('all',array('conditions'=>$conditions));
//3. Create the json array
$rows = array();
for ($a = 0; count($events) > $a; $a++) {
//Is it an all day event?
$all = ($events[$a]['Event']['allday'] == 1);
//Create an event entry
$rows[] = array('id' => $events[$a]['Event']['id'], 'title' => $events[$a]['Event']['title'], 'start' => date('Y-m-d H:i', strtotime($events[$a]['Event']['start'])), 'end' => date('Y-m-d H:i', strtotime($events[$a]['Event']['end'])), 'allDay' => $all);
}
// This controller returns an url that is used by
// javascript to redirect the form to the main page
//4. Return as a json array
Configure::write('debug', 0);
$this->autoRender = false;
$this->autoLayout = false;
$this->header('Content-Type: application/json');
echo json_encode($rows);
}
thanks, for the help!!!
@Yecenia – ok, if you store the user id on the Event row in the table, then this should limit your query to events belonging to the user.
However, I think that you removed the conditions that set a timeframe – so you get back all the events belonging to the user, regardless of the date range in fulcalendar. Is that what you are trying to do?
Hello, and fix the part of the collection time, and here is where my doubt, having the time of start and a end, and the user query as follows:
$conditions = array('Event.start BETWEEN ? AND ?' => array($mysqlstart, $mysqlend),'Event.user_id'=>'18');
$events = $this->Event->find('all', array('conditions' => $conditions));
then I want to query, the event corresponding to the selected user id, which you choose from a combobox
dependent I do with jquery, I want to do is uqe aprtir selected user, appears in the calendar of events associated with that user.
I sent the code of the functions I use to perform these combos works between dependent and feed.
//1. Transform request parameters to MySQL datetime format.
$mysqlstart = date('Y-m-d H:i:s', $this->params['url']['start']);
$mysqlend = date('Y-m-d H:i:s', $this->params['url']['end']);
//2. Get the events corresponding to the time range
$conditions = array('Event.start BETWEEN ? AND ?' => array($mysqlstart, $mysqlend),'Event.user_id'=>'18');
$events = $this->Event->find('all', array('conditions' => $conditions));
//$var=$this->Event->find('all',array('fields'=>array('Event.user_id','Event.start'),'conditions'=>array('Event.user_id'=>'17')));
//$conditions = array('Event.user_id' => '18');
//$events = $this->Event->find('all', array('conditions' => $conditions));
//3. Create the json array
$rows = array();
for ($a = 0; count($events) > $a; $a++) {
//Is it an all day event?
$all = ($events[$a]['Event']['allday'] == 1);
//Create an event entry
$rows[] = array('id' => $events[$a]['Event']['id'], 'title' => $events[$a]['Event']['title'], 'start' => date('Y-m-d H:i', strtotime($events[$a]['Event']['start'])), 'end' => date('Y-m-d H:i', strtotime($events[$a]['Event']['end'])), 'allDay' => $all);
}
// This controller returns an url that is used by
// javascript to redirect the form to the main page
//4. Return as a json array
Configure::write('debug', 0);
$this->autoRender = false;
$this->autoLayout = false;
$this->header('Content-Type: application/json');
echo json_encode($rows);
}
function index($idnumber=null) {
$this->Event->recursive = 0;
/**
* Se obtiene el numero de identificacion del paciente
* proveniente del registro del mismo, y se envia a la vista
*/
$this->Patient->id = $this->params['pass'];
$this->set('patient', $this->Event->read(null, 'id'));
$this->set('id', $idnumber);
$this->set('idnumber', $idnumber);
$specialties = $this->Event->Charge->find('list', array('conditions' => array('Charge.profile_id' => '4')));
$this->set('specialties', $specialties);
$var = $this->Event->find('all', array('fields' => array('Event.user_id', 'Event.start'), 'conditions' => array('Event.user_id' => '17')));
$this->set(compact('specialties', 'doctors'));
$this->set('events', $this->paginate());
}
/*
* Permite generar un array con cada uno de los doctores
* asociados a dicha especialidad
*/
function user($id=null) {
$users = $this->User->find('list', array('conditions' => array('User.charge_id' => $id), 'fields' => 'username'));
$this->set('listado_doctor', $users);
$this->layout = false;
}
Thanks for the help!
@Yecenia – I’ve sent you an email
Here is the code if you want to show events that span multiple months and by user id.
'DATE(Event.start) <=' => $selected_date_end,
'DATE(Event.end) >=' => $selected_date_start
);
Might be nice to update the tutorial above with this function
This was extremely helpful! Thank you.
Good Afternoon:
Anyone know how I can disable the day Sunday, so do not add events.
thanks
@Liceth – have a look at fullcalendar’s documentation:
http://arshaw.com/fullcalendar/docs/display/weekends/
Hello:
How Can I implement thickbox in fullcalendar with cakephp??
thanks!!!
I got only the resulting ajax response :
[{"id":"1","title":"Garde chez les julian","start":"2011-06-22 10:36","end":"2011-06-22 00:36","allDay":false},{"id":"2","title":"qwefqwef","start":"2011-06-22 11:05","end":"2011-06-22 11:05","allDay":false},{"id":"3","title":"qwefqwef qw ef","start":"2011-06-22 11:05","end":"2011-06-23 11:05","allDay":false},{"id":"4","title":"qwerfqwrv","start":"2011-06-22 14:51","end":"2011-06-22 14:51","allDay":false},{"id":"5","title":"qrfqwrf","start":"2011-06-29 10:30","end":"2011-06-29 10:30","allDay":false},{"id":"6","title":"test","start":"2011-09-13 11:01","end":"2011-09-13 12:01","allDay":false}]
But the calendar is not appear !
Someone can help me ?
@Cyril – does the calendar appear if you don’t use an event feed source? (So – can you get the calendar to appear without anything?)
Hello:
how can I implement colors events in this fullcalendar?
Thanks.
@Liceth – in fullcalendar documentation and fullcalendar.css – look for the className attribute.
In the feed, you can add a className attribute to the event. Similar to this:
$rows[] = array('id'=>$events['Event']['id'], 'title'=>$events['Event']['title'], 'start'=>$sdate, 'end'=>$edate, 'allDay'=>$all, 'className'=>'fc-blue');
} else {
$rows[] = array('id'=>$events[$a]['Event']['id'], 'title'=>$events[$a]['Event']['title'], 'start'=>$sdate, 'end'=>$edate, 'allDay'=>$all, 'className'=>'fc-green');
}
Hello:
How I can Prevent overlapping events in FullCalendar?
Thaks for your help!!
@Liceth – prevent them from being saved in the database.
Hi,
I got this error :
Undefined index: start [APP\controllers\rates_controller.php, line 70]
Undefined index: end [APP\controllers\rates_controller.php, line 71]
What’s the problem? Thanks.
Hello:
I don’t understand your answer about, How I can Prevent overlapping events in FullCalendar?
Thanks!!
@nOLL – looks like your array does not have a ‘start’ or ‘end’ index. Debug and see why.
@Liceth – If you don’t let the user save overlapping events to the database, then Fullcalendar will not display them.
Thnx Duck for Your great callendar integration with Cake.
Little fix for CakePHP 2.0.x:
before:
//1. Transform request parameters to MySQL datetime format.
$mysqlstart = date( ‘Y-m-d H:i:s’, $this->params['url']['start']);
$mysqlend = date(‘Y-m-d H:i:s’, $this->params['url']['end']);
after:
$mysqlstart = date( ‘Y-m-d H:i:s’, $this->params->query['start']);
$mysqlend = date(‘Y-m-d H:i:s’, $this->params->query['end']);
Maybe this helps someone