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)

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

Leave a Reply

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