Win a new Mac Book Air laptop

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
 
<?php	
 
/**
* Calendar Helper for CakePHP
*
* Copyright 2007-2008 John Elliott
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice.
*
*
* @author John Elliott
* @copyright 2008 John Elliott
* @link http://www.flipflops.org More Information
* @license http://www.opensource.org/licenses/mit-license.php The MIT License
*
*/
 
class CalendarHelper extends Helper
{
 
	var $helpers = array('Html', 'Form');
 
/**
* Generates a Calendar for the specified by the month and year params and populates it with the content of the data array
*
* @param $year string
* @param $month string
* @param $data array
* @param $base_url
* @return string - HTML code to display calendar in view
*
*/
 
function calendar($year = '', $month = '', $data = '', $base_url ='')
	{
	$str = '';
	$month_list = array('january', 'febuary', 'march', 'april', 'may', 'june', 'july', 'august', 'september', 'october', 'november', 'december');
	$day_list = array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun');
	$day = 1;
	$today = 0;
 
	if($year == '' || $month == '') { // just use current yeear & month
		$year = date('Y');
		$month = date('M');
	}
 
 
 
	$flag = 0;
 
	for($i = 0; $i < 12; $i++) {
		if(strtolower($month) == $month_list[$i]) {
			if(intval($year) != 0) {
				$flag = 1;
				$month_num = $i + 1;
				break;
			}
		}
	}
 
 
	if($flag == 0) {
		$year = date('Y');
		$month = date('F');
		$month_num = date('m');
	}
 
	$next_year = $year;
	$prev_year = $year;
 
	$next_month = intval($month_num) + 1;
	$prev_month = intval($month_num) - 1;
 
	if($next_month == 13) {
		$next_month = 'january';
		$next_year = intval($year) + 1;
	} else {
		$next_month = $month_list[$next_month -1];
	}
 
	if($prev_month == 0) {
		$prev_month = 'december';
		$prev_year = intval($year) - 1;
	} else {
		$prev_month = $month_list[$prev_month - 1];
	}
 
	if($year == date('Y') && strtolower($month) == strtolower(date('F'))) {	
	// set the flag that shows todays date but only in the current month - not past or future...
		$today = date('j');
	}
 
	$days_in_month = date("t", mktime(0, 0, 0, $month_num, 1, $year));
 
	$first_day_in_month = date('D', mktime(0,0,0, $month_num, 1, $year)); 
 
	$str .= '<table class="calendar">';
 
	$str .= '<thead>';
 
	$str .= '<tr><th class="cell-prev">';
 
	$str .= $this->Html->link(__('prev', true), 'calendar/' . $prev_year . '/' . $prev_month); 
 
	$str .= '</th><th colspan="5">' . ucfirst($month) . ' ' . $year . '</th><th class="cell-next">';
 
	$str .= $this->Html->link(__('next', true), 'calendar/' . $next_year . '/' . $next_month); 
 
	$str .= '</th></tr>';
 
	$str .= '<tr>';
 
		for($i = 0; $i < 7;$i++) {
				$str .= '<th class="cell-header">' . $day_list[$i] . '</th>';
		}
 
	$str .= '</tr>';
 
	$str .= '</thead>';
 
	$str .= '<tbody>';
 
	while($day <= $days_in_month) {
		$str .= '<tr>';
 
		for($i = 0; $i < 7; $i ++) {
 
			$cell = '&nbsp;';
 
			if(isset($data[$day])) {
				$cell = $data[$day];
			}
 
			$class = '';
 
			if($i > 4) {
				$class = ' class="cell-weekend" ';
			}
 
			if($day == $today) {
				$class = ' class="cell-today" ';
			}
 
			if(($first_day_in_month == $day_list[$i] || $day > 1) && ($day <= $days_in_month)) {
				$str .= '<td ' . $class . '><div class="cell-number">' . $day . '</div><div class="cell-data">' . $cell . '</div></td>';
				$day++;
			} else {
				$str .= '<td ' . $class . '>&nbsp;</td>';
			}
		}
		$str .= '</tr>';
		}
 
	$str .= '</tbody>';
 
	$str .= '</table>';
 
	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.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
 
<?php
 
/**
* Example controller for the Calendar Helper
*
*	Copyright 2008 John Elliott
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice.
*
*
* @author John Elliott
* @copyright 2008 John Elliott
* @link http://www.flipflops.org More Information
* @license			http://www.opensource.org/licenses/mit-license.php The MIT License
*
*/
 
uses('sanitize');
 
class EventsController extends AppController {
 
	var $name = 'Events';
	var $helpers = array('Html', 'Form', 'Calendar');
 
	/**
	* the idea is that the calendar helper itself is purely a shell
	* the calendar will just display whatever is sent to it
	* anything you want to do to it is put togthere here in the controller or in a component when I get around to writing it
	*
	* @param $year string
	* @param $month string
	*
	**/
 
	function calendar($year = null, $month = null) {
 
		$this->Event->recursive = 0;
 
		$month_list = array('january', 'febuary', '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];
					break;
				}
			}
		}
 
		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] .= '<br /><a href="' . $view_base_url . '/view/' . $v['Event']['id'] . '">' . $v['Event']['name'] . '</a>';
				} else {
					$data[$day] = '<a href="' . $view_base_url . '/view/' . $v['Event']['id'] . '">' . $v['Event']['name'] . '</a>';
				}
			}
		}
 
		$this->set('year', $year);
		$this->set('month', $month);
		$this->set('base_url', $base_url);
		$this->set('data', $data);
 
	}
}
 
 
?>

Event Model

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
 
<?php
class Event extends AppModel {
 
	var $name = 'Event';
	var $useTable = 'events';
	var $validate = array(
 
		'name' => array(
			'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

1
2
3
4
5
6
7
8
9
 
<h2><?php __('Events');?></h2>
 
 
<?php 
 
	echo $calendar->calendar($year, $month, $data, $base_url);
 
?>

events SQL

1
2
3
4
5
6
7
8
9
10
 
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`)
) ENGINE=MyISAM AUTO_INCREMENT=15 DEFAULT CHARSET=latin1;

CSS

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
 
/* 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

Download all the files calendar-helper.zip - this is a zipped copy of the app directory, just set up you database, edit /app/core/database.php and slot it into place. (Note Cake 1.2 only)

20 Responses to “CakePHP Calendar Helper”

  1. Richard@Home Says:

    Nice job! :-)

  2. Web 2.0 Announcer Says:

    Flipflops.org » Blog Archive » CakePHP Calendar Helper…

    […][…]…

  3. Darfuria Says:

    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.

  4. Flipflops Says:

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

  5. William Says:

    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!

  6. Flipflops Says:

    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.

  7. Flipflops Says:

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

  8. TommyO Says:

    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!

  9. Flipflops Says:

    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…

    Cheers

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

  10. Fred Says:

    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;}

  11. mzee.richo Says:

    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 .

  12. Ron Says:

    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!

    -Ron

  13. Flipflops Says:

    @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.

  14. Flipflops Says:

    @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.

  15. mzee.richo Says:

    sure . thks bro

  16. Max Says:

    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?

  17. Brian Says:

    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.

    Thanks,
    Brian

  18. Flipflops Says:

    @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 1.2.0.6311 beta - so I would initially try installing it on a test server like that.

  19. Flipflops Says:

    @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 1.2.0.6311 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.

  20. Mark Roy Says:

    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

Leave a Reply

purchase accutane buy levitra no rx order accutane no prescription required viagra approved cheap propecia overnight delivery find accutane no prescription required buy cheap accutane levitra india accutane online pharmacy buy generic propecia compare cialis prices online cheap accutane from uk buy cheap viagra online buy levitra online cheap cheapest generic viagra online sale cialis fda approved levitra order cialis cheap online purchase accutane overnight delivery order accutane without prescription pharmacy levitra drug propecia online purchase find propecia online purchase viagra online where to order propecia overnight accutane order generic accutane viagra cheap drug order accutane find cheap accutane online buy propecia without prescription buy cialis from india cialis online pharmacy propecia in us order accutane no prescription buy discount viagra find discount viagra order discount viagra online cheap cialis in uk order viagra no prescription order propecia where to order viagra cialis india buy cheap viagra internet accutane for order viagra side effects discount levitra buy accutane overnight delivery viagra overnight delivery certified cialis viagra buy online overnight levitra levitra australia buy propecia on internet accutane cheap price buy discount propecia online find discount cialis order cialis on internet drug cialis online purchase buy levitra without prescription no prescription cialis order levitra from us buy no rx cialis find viagra on internet buy levitra from canada lowest price propecia buy cheapest propecia on line propecia free sample cialis malaysia drug levitra cost accutane order cialis viagra in australia cialis in bangkok cheap cialis without prescription cheapest viagra online buy propecia from canada levitra cost cialis drug cheap viagra pill find cialis without prescription tablet propecia cheapest levitra cheap levitra tablet levitra vendors viagra online pharmacy order cialis overnight delivery buy propecia online order accutane in canada levitra order pharmacy cialis low cost propecia propecia generic order viagra online viagra information generic propecia cheap propecia approved overnight propecia order discount levitra online levitra buy online online cialis levitra internet accutane tablets propecia without rx viagra in malaysia where to order accutane cialis uk order discount levitra cost of accutane cheapest cialis find discount propecia order levitra on internet levitra no prescription accutane online viagra sales buy levitra in canada propecia overnight cheap levitra from usa cheap accutane without prescription cialis purchase find accutane on internet propecia pill lowest price for accutane discount propecia cialis pill buying generic viagra cialis canada approved accutane pharmacy buying generic levitra best price accutane buy viagra generic buy accutane online cheap accutane without prescription accutane us cheapest cialis price propecia from india propecia internet cheap price cialis viagra in bangkok cheap levitra in canada buy cialis no prescription required discount cialis online free levitra buy cheap viagra no rx cialis accutane online review levitra sales lowest price viagra propecia without prescription free viagra cheap cialis pill cheap viagra online buy cheapest cialis viagra for order cost propecia buy generic viagra order propecia no prescription required no rx accutane cost cialis order discount propecia online cheap viagra from uk online pharmacy accutane find no rx cialis buy viagra in canada generic viagra propecia pharmacy online cheap price levitra buy cialis in us buy cheapest levitra cheapest generic accutane buy propecia overnight delivery order cheap viagra accutane purchase purchase propecia online buy no rx accutane discount cialis without prescription buy accutane from india find cheap cialis find accutane without prescription no rx levitra viagra from india accutane canada best price viagra accutane pills levitra online pharmacy buy accutane online buy cialis low price order levitra no rx buy levitra internet cheapest accutane online order cheap propecia online best price for propecia cialis no rx required discount propecia overnight delivery find cheap cialis online buying accutane drug viagra online purchase online pharmacy propecia viagra no rx discount viagra online buy generic propecia online cheap propecia without prescription propecia in bangkok buy cheapest viagra drug viagra cheapest generic levitra online overnight cialis cheap cialis tablet purchase viagra without prescription cheap levitra accutane rx purchase accutane no rx buy accutane internet levitra for order levitra buy find cheap viagra online order generic cialis purchase cialis find discount viagra online buy cheapest viagra online viagra rx cheap propecia from uk buy accutane in us propecia us buy levitra from us no rx propecia cialis from india propecia buy lowest price accutane buy cialis no rx levitra pills levitra buy drug levitra bangkok order cialis from canada tablet accutane cialis cheap drug cheap levitra internet purchase cialis no rx cheap accutane no rx accutane price cialis overnight delivery order viagra in canada viagra in uk buying propecia order generic viagra viagra without rx online propecia drug propecia order viagra on internet propecia cheap price order discount viagra buy cialis internet order cheap cialis fda approved accutane discount viagra overnight delivery sale viagra viagra price find levitra no prescription required buying propecia online compare accutane prices online buy no rx viagra buy no rx levitra levitra purchase find cheap accutane discount viagra without prescription best price for accutane buying levitra propecia for order cheap propecia order propecia from us cheap levitra from uk order levitra in canada discount propecia online cheap cialis pharmacy accutane no rx buy viagra online cheap cheap propecia pill cialis australia viagra cheapest price buy cialis buy cheap propecia online cialis without prescription order viagra from us order propecia cheap online levitra medication viagra online without prescription order generic propecia cheap accutane buy accutane lowest price cialis without a prescription accutane no rx required viagra cheap price buy viagra in us cheap cialis overnight delivery propecia online pharmacy cheapest generic propecia discount levitra online accutane for sale cialis vendors buying viagra order viagra overnight delivery propecia uk free accutane cheap accutane in usa best price levitra propecia in malaysia order levitra from canada buy levitra in us accutane pharmacy viagra bangkok accutane free sample discount propecia without prescription cheapest generic cialis propecia in uk purchase levitra overnight delivery buy accutane low price buy levitra lowest price buy levitra from india find levitra without prescription pharmacy viagra purchase cialis without prescription low cost accutane accutane order purchase propecia no rx order viagra no rx levitra without rx order cheap levitra online cialis cheap price accutane from india accutane cost propecia bangkok find propecia levitra in bangkok accutane without a prescription find cialis no prescription required cheap price accutane buy cheapest levitra on line viagra us accutane india levitra overnight delivery propecia overnight delivery levitra in malaysia cialis in uk cialis without rx cheap accutane on internet cialis no rx levitra uk order no rx viagra propecia sales propecia drug drug accutane online purchase buy propecia lowest price levitra rx lowest price cialis cheap cialis no prescription buy levitra no prescription required order cialis online find no rx levitra propecia vendors order accutane online cheap levitra no prescription order levitra online certified levitra free cialis viagra india viagra no online prescription order propecia without prescription order levitra without prescription cheap cialis viagra no prescription buy cheapest cialis on line accutane australia find cialis on internet find viagra propecia cost cheap viagra from usa propecia no online prescription propecia cheapest price find discount levitra online where to order cialis buy cialis on internet order propecia on internet buy propecia us buy accutane no prescription required order levitra in us sale accutane propecia pills