CakePHP Calendar Helper

About six months ago I wrote a post about a Simple PHP calendar function I had written and how it was also really easy to use as a CakePHP helper.

Calendar Screenshot

I didn’t actually write the calendar specifically with Cake in mind, but I was working on a Cake site at the same time and I had a flash of inspiration. I was working on a project that needed a calendar, so I looked through all my old code but all the Calendars I had were all tied up in a terrible mess with bits of logic and SQL queries and layout all rolled into one. I looked on Google and still couldn’t find anything really easy to use – I wanted something I could just drop into place.

I suddenly realised that the way to do it was to stop trying to put any decision making into the calendar at all. The calendar only needs to display the right layout for the month and manage back and forward links. I decided to just dump the data in an array where the index corresponded to the day number (1 to 31) – the idea being that you can put anything in the array – plain text, html, javascript hooks for ajax etc.

It was in part influenced by some work I was doing using the The Yahoo! User Interface Library (YUI)
but I am very dubious about the whole notion of creating embedded calendars solely through Javascript when it could far more easily be done server side. (There is clearly a place for Javascript pop up calendars e.g. date pickers – I’m particularly fond of Marc Grabanski and Keith Woods’ version jQuery UI Datepicker)

At the time I had just moved over to using CakePHP as the main vehicle for my development work and it was clearly a great fit with the MVC setup of CakePHP – the calendar is just a shell that shows whatever you pour into it.

This is the first time I have had to go back and revisit the code, I have fixed the bugs, added some comments and set up a working example. At the moment all the logic is just sitting in the controller – but I am working on a component to tidy everything up and make it nice and portable (watch this space).

Thanks to everybody who commented or emailed me about the first version in September.

Calendar Helper

	$str .= '';
	$str .= '';
	$str .= $this->Html->link(__(‘prev’, true), array($prev_year, $prev_month));
	$str .= '' . ucfirst($month) . ' ' . $year . '';
	$str .= $this->Html->link(__(‘next’, true), array($next_year, $next_month));

	$str .= '';
	$str .= '';
		for($i = 0; $i < 7;$i++) {
				$str .= '' . $day_list[$i] . '';
	$str .= '';
	$str .= '';
	$str .= '';
	while($day <= $days_in_month) {
		$str .= '';
		for($i = 0; $i < 7; $i ++) {
			$cell = ' ';
			if(isset($data[$day])) {
				$cell = $data[$day];
			$class = '';
			if($i > 4) {
				$class = ' class="cell-weekend" ';
			if($day == $today) {
				$class = ' class="cell-today" ';
                        $first_day_in_month = strtolower($first_day_in_month);
			if(($first_day_in_month == $day_list[$i] || $day > 1) && ($day <= $days_in_month)) {
				$str .= '
' . $day . '
' . $cell . '
'; $day++; } else { $str .= ' '; } } $str .= ''; } $str .= ''; $str .= ''; return $str; } } ?>

Calendar Controller

The controller is responsible for creating the data array containing the calendar ‘events’ and then passing this on to the view from where the calendar is called.

Event->recursive = 0;
		$month_list = array('january', 'february', 'march', 'april', 'may', 'june', 'july', 'august', 'september', 'october', 'november', 'december');
		$day_list = array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun');
		$base_url = $this->webroot . 'events/calendar'; // NOT not used in the current helper version but used in the data array
		$view_base_url = $this->webroot. 'events';
		$data = null;
		if(!$year || !$month) {
			$year = date('Y');
			$month = date('M');
			$month_num = date('n');
			$item = null;
		$flag = 0;
		for($i = 0; $i < 12; $i++) { // check the month is valid if set
			if(strtolower($month) == $month_list[$i]) {
				if(intval($year) != 0) {
					$flag = 1;
					$month_num = $i + 1;
					$month_name = $month_list[$i];
		if($flag == 0) { // if no date set, then use the default values
			$year = date('Y');
			$month = date('M');
			$month_name = date('F');
			$month_num = date('m');
		$fields = array('id', 'name', 'DAY(event_date) AS event_day');
		$var = $this->Event->findAll('MONTH(Event.event_date) = ' . $month_num . ' AND YEAR(Event.event_date) = ' . $year, $fields, 'Event.event_date ASC');
		* loop through the returned data and build an array of 'events' that is passes to the view
		* array key is the day of month 
		foreach($var as $v) {
			if(isset($v[0]['event_day'])) {

				$day = $v[0]['event_day'];
				if(isset($data[$day])) {
					$data[$day] .= '
' . $v['Event']['name'] . ''; } else { $data[$day] = '' . $v['Event']['name'] . ''; } } } $this->set('year', $year); $this->set('month', $month); $this->set('base_url', $base_url); $this->set('data', $data); } } ?>

Event Model

			'rule' => array('minLength', 2),
			'message' => 'Name must be at least 2 characters long',
			'required' => true 
		'notes' => array(
			'rule' => array('minLength', 2),
			'message' => 'Please add some notes',
			'required' => true 


Calendar View

calendar($year, $month, $data, $base_url); ?>

events SQL

CREATE TABLE `events` (
  `id` int(11) NOT NULL auto_increment,
  `name` varchar(255) default NULL,
  `event_date` datetime default NULL,
  `notes` text,
  `created` datetime default NULL,
  `modified` datetime default NULL,
  PRIMARY KEY  (`id`)


/* calendar CSS */
table.calendar {width: auto; border: 1px solid #cccccc; border-collapse: collapse; margin: 0px; padding: 0px; background-color: #ffffff;}
table.calendar th {background-color: #eeeeee; text-transform: none; color: #444444; padding: 4px; text-align: center; border: 1px solid #eeeeee;}
table.calendar th.cell-prev {text-align: left;}
table.calendar th.cell-next {text-align: right;}
table.calendar th.cell-header {width: 70px; border-bottom: 1px solid #cccccc;}
table.calendar td.cell-today {background-color: #e2e8f6;} /* today in the current month */
table.calendar td.cell-weekend {background-color: #F3F5EB;}
table.calendar td {border: 1px solid #cccccc;}
table.calendar td div.cell-number {text-align: right; font-size: 8px; color: #444444; display: block;}
table.calendar td div {display: block; font-size: 10px; text-align: left;}
table.calendar thead th {border: 1px solid #cccccc;}

To Do List

I’m feeling a little less time poor at the moment and want to do a bit of work on this. If anybody has any comments or suggestions, please let me know. At the moment my plans are as follows (in no particular order).

  • add support for internationalisation
  • put the checking date checking (and possibly data array construction into a component)
  • add built in AJAX support (haven’t decided on jQuery or Prototype yet though)
  • look at using Cake 1.2 routes as part of date checking using regular expressions (how easy would it be to combine this with the internationalisation?)

Examples & Downloads

Check out the Working Calendar Helper Example

52 thoughts to “CakePHP Calendar Helper”

  1. Pingback: Web 2.0 Announcer
  2. Nicely done – this will be really great once you’ve added the final things to it. I would have thought Prototype would be the way to go with it. Keep us updated anyway.

    I’ve just redesigned our blog, and the sort of approach we both have with designs currently is very similar, it’s quite amusing.

  3. I know – its a hard choice I like jquery – but will probably use prototype as it comes out of the box with cake…

  4. Hi, I’m relatively new to CakePHP and I’m having a bit of trouble figuring out where all these files should go and what conventions they should follow. I’m using CakePHP 1.2, and I have the files here:

    Calendar Helper: /app/views/helpers/calendar.php
    Calendar View: /app/views/calendar.php
    Event Model: /app/models/event.php
    Calendar Controller: /cakebox/app/controllers/events_controller.php

    When I go to /events/calendar in my browser I get the following error:
    Class ‘Event’ not found in /home/httpd/html/cake/libs/class_registry.php

    If you have any advice or insights they would be appreciated. Thanks!

  5. Hi William

    Calendar Controller: /cakebox/app/controllers/events_controller.php looks a bit weird – the cakebox part of the address – I am guessing though that this is just your development directory and you edited all the other paths for clarity.

    When something goes wrong I always firstly check for Typos, then clear the app/tmp/cache/models

    Also what debug level have you got set in core/config.php ?

    Other than that I’m not sure – but I will have a think about it. I’ll also try and zip up all the files as a working download over the next few days.

    Hope this helps.

  6. I’ve just zipped up all the files and uploaded them, so it should now be very easy to get it up and running.

  7. Very nice.

    I wrote a DateHelper and CalendarHelper 2 years ago specifically for cake, which is of course dearly in need of a refactoring, that does a lot of what you plan on adding.

    I’m going to dive in this week on it, as I need an international calendar for a project. Feel like merging resources? :)

    Love it, well done!

  8. Hi Tommy

    Thanks for getting in touch – potentially I am definitely up for joining forces, but I am am really snowed under at the moment and wouldn’t be able to contribute that much at the moment.

    I’ve been giving it a lot of thought though recently and have decided that I want in this kind of direction – how does this tie in with your ideas?

    I want to extend the helper so you can specify how many calendars you want to show at a time – so you could show say 12 little calendars one for each month or 1 or 4 or whatever – I quite like some of the things you can do with Yahoo YUI, just not the implementation – and I have thought of this very much in terms of a server rather than client side thing.

    The main change from that would be the input data array would have to change from a just an array with key 0-31 to a more complex array probably [year][month][day]

    I thought it would be good to hive off all the code for checking the validity of a month (from the url) into a component and also functions for generating the data array, so you have a very clean controller.

    Then integrating built in AJAX support for scrolling back and forth between calendar months that you can toggle on / off.

    I’m still uming and ahhhing about whether to leave the actual content for a given day as just a container where people can put what they want into it….

    On the internationalisation front – especially in Cake 1.2 shouldn’t be that hard should it ? (not that I’ve ever had call to do any) – the main thing would just be the elements in month names array…


    BTW – I think the first thing I’m going to do is add support for multiple calendars.

  9. Very useful Flipflops ! Thanks for sharing your work :)

    I just add the possibility to check if an event is private or public so you can both have a public or private events.
    Add a ‘private’ field in your events table : TINYINT (NOT NULL,0)
    And in your event controller :

    $fields = array(‘id’, ‘name’, ‘DAY(event_date) AS event_day’,’private’);

    $varPublic = $this->Event->findAll(‘MONTH(Event.event_date) = ‘ . $month_num . ‘ AND YEAR(Event.event_date) = ‘ . $year . ‘ AND (private=0)’, $fields, ‘Event.event_date ASC’);
    $varPrivate = $this->Event->findAll(‘MONTH(Event.event_date) = ‘ . $month_num . ‘ AND YEAR(Event.event_date) = ‘ . $year . ‘ AND (private=1 OR private=0)’, $fields, ‘Event.event_date ASC’);

    Check if a session exist or not :
    if (!$this->Session->check(‘User’)) {$check = $varPublic;} else {$check = $varPrivate;}

  10. Nice stuff bro . Been trying to re-do but hitting walls , op ill shoot it . can u explain why you use the $base_url = $this->webroot. Think its the one giving me hell .

  11. Hey ‘FlipFlop’,

    I would 1st like to say I really enjoyed your helper! I also wanted to let you knw i’ve converted the calendar to work 100% in Ajax form, you can switch months via ‘Ajax’, you can view an event in a ‘pop-up modal’ and even click edit in there and edit in a different modal. Once i have it on the internet I can share it you. Well thank you very much for such a nice calnendar!


  12. @Ron Cheers – glad you liked it, are you using any particular framework for the Ajax? One of the (many) reasons I never did this was because I couldn’t decide whether to go jQuery or Prototype…

    For the record I’m now firmly in the jQuery camp, I use it almost every day, it makes the little things so much easier. Giod it makes me shudder when I think of the hoops I used to jump through only a couple of years ago… thinking in particular of a car booking system I wrote about 2 1/2 years ago for a car share club – looping through a table with every hour for an entire week and adding event listeners to watch for clicks… hundreds of lines of javascript and all that browser forking code – in jQuery the whole thing would probably be 10 lines.

    p.s. any links back to the site greatly appreciated.

  13. @mzee

    Sorry the $base_url is a kind of orphan from the previous version – in some ways it should have been re factored out but I left in because I thought I might end up needing it so I just left a comment in there.

  14. I installed everything on my application.
    Where should I go to get the calendar? if I write myroot/events I get an error. I need to go to myroot/events/calendar/November/2008 to get the page. And even in this case in the end of the page i receive this error:
    Notice: Array to string conversion in C:\Programmi\EasyPHP 2.0b1\www\cake\libs\view\helpers\html.php on line 179
    And when I click on “add” i get:
    Fatal: Confirm you have created the EventsController::Array() in file : app\controllers\events_controller.php

    All the file are in the right folders. What’ s the matter?

  15. Flipflops,

    This looks like a great solution to my problem, but I’m new to cakePHP and I was wondering what you meant when you said “slot it into place” as far as installing the app is concerned.


  16. @Brian – Slot it into place kinda means it shouldn’t be too hard to get working – but you also have to bear in mind that Cake on the whole is a little more involved than something like say Joomla or WordPress where you litterally can just get a plugin or component and drop it into place.

    I would say download the example and get it running as a first step. I just checked and the vesion it uses is beta – so I would initially try installing it on a test server like that.

  17. @Max – I’m guessing that this is because it makes uses of depreceated code – hi try just downloading the example and setting that up – but also download a copy of Cake beta – as this is the version the example online uses – so it really should ‘just work’ when you have set up a site on your dev machine. Then I would recommend downloading the latest version of Cake and fixing the errors that come up.

    However thanks for pointing out the error – I’ll look at this and update the example to run on RC3.

  18. Hello John,

    I thought I’d mention that I liked your calendar helper, but needed something slightly different, so I modified your helper so that it now can also generate a weekly hour by hour calendar. My version of the helper now has two methods, “month” (your “calendar” method, renamed), and “week”.

    The week method generates a weekly view, and you can specify the day, month, and year, and it will display the week that it falls on starting on monday. The week method also takes min_hour and max_hour which lets you specify which hours to display (for most applications, you wont need to show the entire day, for instance, you can set it to display 9:00 – 17:00, the typical workday). The data array is specified like this $data[day][hour] so that you can place an event on any given hour of any given day.

    The mod was surprisingly simple, and doesnt really change much else. It even uses the same CSS file with no modifications.

    John, please contact me by email if you’d like the source to post on your website.

    — Mark Roy

  19. Hi Mark

    Thanks for posting that comment up about the Calendar Helper. I’m really glad that it has been useful to you.

    I’d love to add your code to the site, thanks for offering to make it available.


  20. Hi John,

    Great helper, just what I was looking for.

    I have one problem, in that I have a start date and and end date for bookings, I have got the calendar working with just the start date but I’m not sure how to show the booking on all dates between the start and end.

    Thanks for a great helper and any suggestions you have on my problem would be much appreciated.


  21. Hi Duncan

    Sorry- completely forgot to respond to you.

    Well basically that is more of a how you build your array question, rather than the helper per-se. There is going to be a different solution for everybody, but basically when you build your array in the model or controller you just need to make usre that the intervening dates are also selected.

    I did say it rather minimal ;)

  22. Great work.

    I used your controller and helper as a starting point for a scheduling application I’m building.

    I made some changes to the controller because I did not like the fact that you are injecting html inside the controller.
    the controller now returns a multidimensional array containing all the data still using the daynumber as the first key

    also, I modified it so that months are always handled as numbers, otherwise I could not translate the month names into any other language…

    But you did save me a huge amount of time.. thanks

  23. Hello,

    Learning CakePHP and I think you did a great job on creating the helper. I have also seen a post above by Mark Roy offering to share the code for the modification he made on your helper to get a week view. Please if you have it would you upload it on you site for download. It will help me and may other learners like may benefit from it. I apprecaiate the effort you put in creating the helper and also sharing it with us.


  24. Hi Albert

    Glad you like the helper. I’m afraid that I don’t have the amended code that Mark wrote – although I know it was available to download from his site

    One thing to be aware of though is that I originally I wrote the code that turned into this helper about 2 years ago. The aim was to make something really easy to use (which I hope it is) – but if I was writing this now I would definitely approach it another way and probably split it into a Helper and either a Component or Behaviour, as generating HTML in the controller is generally frowned upon for breaking MVC convention.


  25. Hello,

    I am trying to schedule an event without going through the link at the bottom of calendar page. Basic what I want to archieve is create a calendar in which the click on day on calendar and you will be redirected to add event page. On the add event page the date shown is the day selected from the calendar rather than todays date. Which you can then use to save the event.

    Current I have added a radio button to the cell of day in calendar which would contain the date selected.

    I have added a submit button at the bottom to calendar page so that if I submit the day submited would be the value of the selected button. After get here i realise that I am in trouble. Is there away to pass the value of the button to add function? Is there another way of doing what I am trying to do? Any suggestion are welcome.


  26. Hi Albert

    First I would use a GET request rather than a POST via a radio button, I think it is simply more elegant.

    So you would want to create in each table cell something like /events/add/2009/07/03 this is clear and you can validate the date parts in your routes too.

    Then your add method would look something like this:

    function add($year = null, $month = null, $day = null){
    if($year && $month && $day){
    // validate the date
    // send the date to the view
    // etc.

    If you continue with the radio button method then the date you need to set each days date as the value of that radio button, which will then be sent to the add method and be accessible in it as $this->data, of course you will then have to distinguish as to whether or not it is a POST from the calendar (i.e. just the date) or a POST from the add form (i.e. date + other data)

    Hope this helps


  27. I read your website every week, its great and got lots of information to take in and lots of interesting articles.

  28. i implement your helper and it’s work , but i want the calendar.ctp to become an element, i tried but i got an error but i read this link “” to implement my work i manage don’t get an error but but every time i click the prev link i get an error , and all the events doesn’t show, please help :) if you want to see where it implement please e-mail me and i give you the link :) thank you

  29. Hi! I implement your helper, but I need to show a link each day from the start date to end date. In the database I have two fields, with the dates. I’ve been looking but have not found anything. It works in cases where the event begins and ends in the same month, but in other cases I have no solution. I would appreciate any help or advice.

    Thank you,

  30. Hmmm. This isn’t really a helper problem, but more of model / controller problem. Its up to you how you get your data into the right format. Sorry I can’t be more help right now but its very late here, maybe tomorrow!

  31. The code in the controller:

    $events = $this->Evento->find(‘all’, array(
    ‘conditions’ => array(‘MONTH(Evento.fecha_inicio) = ‘ . $month . ‘ AND YEAR(Evento.fecha_inicio) = ‘ . $year),
    ‘fields’ => array(‘fecha_inicio’, ‘fecha_fin’),
    ‘order’ => ‘Evento.fecha_inicio ASC’

    foreach($events as $event) {
    $start = date(‘j’, strtotime($event[‘Evento’][‘fecha_inicio’]));
    $end = date(‘j’, strtotime($event[‘Evento’][‘fecha_fin’]));

    $start_month = date(‘m’, strtotime($event[‘Evento’][‘fecha_inicio’]));
    $end_month = date(‘m’, strtotime($event[‘Evento’][‘fecha_fin’]));

    $start_year = date(‘Y’, strtotime($event[‘Evento’][‘fecha_inicio’]));
    $end_year = date(‘Y’, strtotime($event[‘Evento’][‘fecha_fin’]));

    if($start_month == $end_month && $start_year == $end_year) {
    while($start ‘. $start .’‘;
    } else {
    // ¿Code?

    Any ideas?

    Thank you,

  32. if($start_month == $end_month && $start_year == $end_year) {
    while($start ‘. $start .’‘;
    } else {
    // ¿Code?

  33. Sorry, the condition into the while not copied correctly… I have tried to paste it twice, but that part is working properly.

  34. nice work
    but it needs some heavy refacturing
    especially for cake 1.2 /1.3

    for everybody that ran into the same “inf. loop” in the helper:

    $first_day_in_month = strtolower($first_day_in_month);
    is missing prior to check them against the array
    because “fri” != “Fri” in PHP5.x etc!

    then, the base_url is not needed
    drop it and just use the build in Html->link():

    $str .= $this->Html->link(__(‘prev’, true), array($prev_year, $prev_month));

    $str .= $this->Html->link(__(‘next’, true), array($next_year, $next_month));

    the controller model query should also be changed to a cleaner cake structure
    and the html should be moved to the helper too

    other than that a great helper :)

  35. I know this is an old post, but thought to update people as I was recently working on my own calendar and decided to not reinvent the wheel, heh. I am converting the code into a plugin and doing a few upgrades, but since I’m as busy as everyone else, feel free to fork and contribute.

    Planned or Completed changes:
    – All code packaged as plugin
    – Controller code moved to component
    – Component auto-includes helper (?)
    – HTML will not be rendered in C, instead returning data array tweak will be added.
    – Code is being abstracted to work with any model in conjunction with optional configuration (convention over configuration)
    – Spanned events tweak will be added.
    – Helper will be expanded/refactored to break down areas of code into their own areas (day/week/month generation + extra methods / options when rendering)
    – Improved markup / css ( tags? Really? come on! display: block)

  36. @mark, @proloser

    Thanks for your comments guys. Apologies for the appallingly long time it has taken me to respond.

    What can I say… it is a very old post and the coed was a quick hack written as a rush job and then dumped into Cake 1.1

    Maybe one day I’ll get to sort it out.

  37. hai its very nice but when i try to display by monthwise the event data not shown ….please help me on this
    /home/rekha/Desktop/Screenshot-CakePHP: the rapid development php framework: Events – Mozilla Firefox.png

  38. Hi,

    when i apply this ui am getting the following error.
    And if i change in helper if loop which is inside while-for-loop.
    i get mismatched data.
    but not getting below error.

    Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 127664085 bytes) in /var/www/cakephp-1.3.3/app/views/helpers/calendar.php on line 151

    please clarify on this.


  39. I know this is an old post, and I know this is mostly only compatible with cake V 1.2.

    But I’m now using the latest version of Cake and findAll no longer works as it used to…

    $var = $this->Event->findAll(‘MONTH(Event.event_date) = ‘ . $month_num . ‘ AND YEAR(Event.event_date) = ‘ . $year, $fields, ‘Event.event_date ASC’);

    Do you have a solution to this?

  40. Hi Chris

    Sorry, I haven’t really done anything with Cake for over a year, so I’m a little out of touch. But (from memory) has findAll been depreceated in favour of something along the lines of $this->find(‘all’, array(‘conditions’ => $conditions)); ?


  41. To make it work in CakePHP 1.3, you can replace this line:
    $var = $this->Event->findAll(‘MONTH(Event.event_date) = ‘ . $month_num . ‘ AND YEAR(Event.event_date) = ‘ . $year, $fields, ‘Event.event_date ASC’);

    With this:

    $conditions = array(“AND” => array(
    ‘MONTH(Event.event_date) = ‘ . $month_num,
    ‘YEAR(Event.event_date) = ‘ . $year

    $params = array(
    ‘conditions’ => $conditions,
    ‘fields’ => $fields

    $var = $this->Event->find(‘all’, $params);

    Thanks for making an awesome helper, and I apologize for the ugliness of my code.

  42. @Mike. You are welcome and far to kind. Thanks for the notes. Haven’t used 1.3 yet.


  43. I like your calendar and approach. However, it’s nice to have the numbers for the previous month that start on days before the first. So say June 1 starts on a wednesday. Monday and tuesday should have 29, 30 respectively and those days might have a different background color indicating there not part of the current month. On the other end, if June 30 ends on a Thursday, then Fri, Sat and Sun should have 1,2,3 in them.

    My thought for the day.

  44. Hi, I like your calendar, I was trying use, but don’t work :'(

    When I write: path/events/calendar , this appears:

    Warning (512): Method CalendarHelper::calendar does not exist [CORE\cake\libs\view\helper.php, line 154]

    I have this files:

    controllers: events_controller.php
    Models: event.php
    helpers: calendar.php
    views: calendar.ctp

    Now, I believe that the problem is in calendar.ctp:
    calendar($year, $month, $data, $base_url);
    I don’t understand why use $calendar as object?

    You can help me? What is wrong and how could it right?


  45. Hi,

    Superb helper,Easy to customize each thing helper,controller css

    Laxman Parmar

Comments are closed.