PageRenderTime 47ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/kronolith/lib/FreeBusy/View.php

https://github.com/sgtcarneiro/horde
PHP | 359 lines | 214 code | 48 blank | 97 comment | 16 complexity | dc0c4ec2b894b03056734caee90c8b6b MD5 | raw file
  1. <?php
  2. /**
  3. * This class represent a view of multiple free busy information sets.
  4. *
  5. * Copyright 2003-2011 The Horde Project (http://www.horde.org/)
  6. *
  7. * See the enclosed file COPYING for license information.
  8. *
  9. * @author Mike Cochrane <mike@graftonhall.co.nz>
  10. * @author Jan Schneider <jan@horde.org>
  11. * @package Kronolith
  12. */
  13. abstract class Kronolith_FreeBusy_View
  14. {
  15. protected $_requiredMembers = array();
  16. protected $_optionalMembers = array();
  17. protected $_requiredResourceMembers = array();
  18. protected $_optionalResourceMembers = array();
  19. protected $_timeBlocks = array();
  20. protected $_startHour;
  21. protected $_endHour;
  22. protected $_start;
  23. protected $_end;
  24. /**
  25. * Adds a required attendee
  26. *
  27. * @param Kronolith_Freebusy $vFreebusy
  28. */
  29. public function addRequiredMember(Kronolith_Freebusy $vFreebusy)
  30. {
  31. $this->_requiredMembers[] = clone $vFreebusy;
  32. }
  33. /**
  34. * Adds an optional attendee
  35. *
  36. * @param Kronolith_Freebusy $vFreebusy
  37. */
  38. public function addOptionalMember(Kronoolith_Freebusy $vFreebusy)
  39. {
  40. $this->_optionalMembers[] = clone $vFreebusy;
  41. }
  42. /**
  43. * Adds an optional resource
  44. *
  45. * @param Kronolith_Freebusy $vFreebusy
  46. */
  47. public function addOptionalResourceMember(Kronolith_Freebusy $vFreebusy)
  48. {
  49. $this->_optionalResourceMembers[] = clone $vFreebusy;
  50. }
  51. /**
  52. * Adds a required resource
  53. *
  54. * @param Kronolith_Freebusy $vFreebusy
  55. */
  56. public function addRequiredResourceMember(Kronolith_Freebusy $vFreebusy)
  57. {
  58. $this->_requiredResourceMembers[] = clone $vFreebusy;
  59. }
  60. /**
  61. * Renders the fb view
  62. *
  63. * @global Horde_Prefs $prefs
  64. * @param Horde_Date $day The day to render
  65. *
  66. * @return string The html of the rendered fb view.
  67. */
  68. public function render(Horde_Date $day = null)
  69. {
  70. global $prefs;
  71. $this->_startHour = floor($prefs->getValue('day_hour_start') / 2);
  72. $this->_endHour = floor(($prefs->getValue('day_hour_end') + 1) / 2);
  73. $this->_render($day);
  74. $vCal = new Horde_Icalendar();
  75. /* Required members */
  76. $required = Horde_Icalendar::newComponent('vfreebusy', $vCal);
  77. foreach ($this->_requiredMembers as $member) {
  78. $required->merge($member, false);
  79. }
  80. foreach ($this->_requiredResourceMembers as $member) {
  81. $required->merge($member, false);
  82. }
  83. $required->simplify();
  84. /* Optional members */
  85. $optional = Horde_Icalendar::newComponent('vfreebusy', $vCal);
  86. foreach ($this->_optionalMembers as $member) {
  87. $optional->merge($member, false);
  88. }
  89. foreach ($this->_optionalResourceMembers as $member) {
  90. $optional->merge($member, false);
  91. }
  92. $optional->simplify();
  93. /* Optimal time calculation */
  94. $optimal = Horde_Icalendar::newComponent('vfreebusy', $vCal);
  95. $optimal->merge($required, false);
  96. $optimal->merge($optional);
  97. $base_url = Horde::selfUrl()
  98. ->remove('date')
  99. ->remove('fbview')
  100. ->add('fbview', $this->view);
  101. $template = $GLOBALS['injector']->createInstance('Horde_Template');
  102. $template->set('title', $this->_title());
  103. $html = $template->fetch(KRONOLITH_TEMPLATES . '/fbview/header.html') .
  104. '<div class="fbgrid">';
  105. $hours_html = $this->_hours();
  106. // Set C locale to avoid localized decimal separators during CSS width
  107. // calculation.
  108. $lc = setlocale(LC_NUMERIC, 0);
  109. setlocale(LC_NUMERIC, 'C');
  110. // Required to attend.
  111. if (count($this->_requiredMembers) > 0) {
  112. $rows = '';
  113. foreach ($this->_requiredMembers as $member) {
  114. $member->simplify();
  115. $blocks = $this->_getBlocks($member, $member->getBusyPeriods(), 'busyblock.html', _("Busy"));
  116. $template = $GLOBALS['injector']->createInstance('Horde_Template');
  117. $template->set('blocks', $blocks);
  118. $template->set('name', $member->getName());
  119. $rows .= $template->fetch(KRONOLITH_TEMPLATES . '/fbview/row.html');
  120. }
  121. $template = $GLOBALS['injector']->createInstance('Horde_Template');
  122. $template->set('title', _("Required Attendees"));
  123. $template->set('rows', $rows);
  124. $template->set('span', count($this->_timeBlocks));
  125. $template->set('hours', $hours_html);
  126. $template->set('legend', '');
  127. $html .= $template->fetch(KRONOLITH_TEMPLATES . '/fbview/section.html');
  128. }
  129. // Optional to attend.
  130. if (count($this->_optionalMembers) > 0) {
  131. $rows = '';
  132. foreach ($this->_optionalMembers as $member) {
  133. $member->simplify();
  134. $blocks = $this->_getBlocks($member, $member->getBusyPeriods(), 'busyblock.html', _("Busy"));
  135. $template = $GLOBALS['injector']->createInstance('Horde_Template');
  136. $template->set('blocks', $blocks);
  137. $template->set('name', $member->getName());
  138. $rows .= $template->fetch(KRONOLITH_TEMPLATES . '/fbview/row.html');
  139. }
  140. $template = $GLOBALS['injector']->createInstance('Horde_Template');
  141. $template->set('title', _("Optional Attendees"));
  142. $template->set('rows', $rows);
  143. $template->set('span', count($this->_timeBlocks));
  144. $template->set('hours', $hours_html);
  145. $template->set('legend', '');
  146. $html .= $template->fetch(KRONOLITH_TEMPLATES . '/fbview/section.html');
  147. }
  148. // Resources
  149. if (count($this->_requiredResourceMembers) > 0 || count($this->_optionalResourceMembers) > 0) {
  150. $template = $GLOBALS['injector']->createInstance('Horde_Template');
  151. $rows = '';
  152. foreach ($this->_requiredResourceMembers as $member) {
  153. $member->simplify();
  154. $blocks = $this->_getBlocks($member, $member->getBusyPeriods(), 'busyblock.html', _("Busy"));
  155. $template = $GLOBALS['injector']->createInstance('Horde_Template');
  156. $template->set('blocks', $blocks);
  157. $template->set('name', $member->getName());
  158. $rows .= $template->fetch(KRONOLITH_TEMPLATES . '/fbview/row.html');
  159. }
  160. foreach ($this->_optionalResourceMembers as $member) {
  161. $member->simplify();
  162. $blocks = $this->_getBlocks($member, $member->getBusyPeriods(), 'busyblock.html', _("Busy"));
  163. $template = $GLOBALS['injector']->createInstance('Horde_Template');
  164. $template->set('blocks', $blocks);
  165. $template->set('name', $member->getName());
  166. $rows .= $template->fetch(KRONOLITH_TEMPLATES . '/fbview/row.html');
  167. }
  168. $template = $GLOBALS['injector']->createInstance('Horde_Template');
  169. $template->set('title', _("Required Resources"));
  170. $template->set('rows', $rows);
  171. $template->set('span', count($this->_timeBlocks));
  172. $template->set('hours', $hours_html);
  173. $template->set('legend', '');
  174. $html .= $template->fetch(KRONOLITH_TEMPLATES . '/fbview/section.html');
  175. }
  176. // Possible meeting times.
  177. $optimal->setAttribute('ORGANIZER', _("All Attendees"));
  178. $blocks = $this->_getBlocks($optimal,
  179. $optimal->getFreePeriods($this->_start->timestamp(), $this->_end->timestamp()),
  180. 'meetingblock.html', _("All Attendees"));
  181. $template = $GLOBALS['injector']->createInstance('Horde_Template');
  182. $template->set('name', _("All Attendees"));
  183. $template->set('blocks', $blocks);
  184. $rows = $template->fetch(KRONOLITH_TEMPLATES . '/fbview/row.html');
  185. // Possible meeting times.
  186. $required->setAttribute('ORGANIZER', _("Required Attendees"));
  187. $blocks = $this->_getBlocks($required,
  188. $required->getFreePeriods($this->_start->timestamp(), $this->_end->timestamp()),
  189. 'meetingblock.html', _("Required Attendees"));
  190. $template = $GLOBALS['injector']->createInstance('Horde_Template');
  191. $template->set('name', _("Required Attendees"));
  192. $template->set('blocks', $blocks);
  193. $rows .= $template->fetch(KRONOLITH_TEMPLATES . '/fbview/row.html');
  194. // Possible meeting times.
  195. // $resource->setAttribute('ORGANIZER', _("Required Attendees"));
  196. // $blocks = $this->_getBlocks($required,
  197. // $required->getFreePeriods($this->_start->timestamp(), $this->_end->timestamp()),
  198. // 'meetingblock.html', _("Required Attendees"));
  199. //
  200. // $template = $GLOBALS['injector']->createInstance('Horde_Template');
  201. // $template->set('name', _("Required Attendees"));
  202. // $template->set('blocks', $blocks);
  203. // $rows .= $template->fetch(KRONOLITH_TEMPLATES . '/fbview/row.html');
  204. // Reset locale.
  205. setlocale(LC_NUMERIC, $lc);
  206. $template = $GLOBALS['injector']->createInstance('Horde_Template');
  207. $template->set('rows', $rows);
  208. $template->set('title', _("Overview"));
  209. $template->set('span', count($this->_timeBlocks));
  210. $template->set('hours', $hours_html);
  211. if ($prefs->getValue('show_fb_legend')) {
  212. $template->setOption('gettext', true);
  213. $template->set('legend', $template->fetch(KRONOLITH_TEMPLATES . '/fbview/legend.html'));
  214. } else {
  215. $template->set('legend', '');
  216. }
  217. return $html . $template->fetch(KRONOLITH_TEMPLATES . '/fbview/section.html') . '</div>';
  218. }
  219. /**
  220. * Attempts to return a concrete Kronolith_FreeBusy_View instance based on
  221. * $view.
  222. *
  223. * @param string $view The type of concrete Kronolith_FreeBusy_View
  224. * subclass to return.
  225. *
  226. * @return mixed The newly created concrete Kronolith_FreeBusy_View
  227. * instance, or false on an error.
  228. */
  229. static public function factory($view)
  230. {
  231. $driver = basename($view);
  232. $class = 'Kronolith_FreeBusy_View_' . $driver;
  233. if (class_exists($class)) {
  234. return new $class($user, $params);
  235. }
  236. return false;
  237. }
  238. /**
  239. * Attempts to return a reference to a concrete Kronolith_FreeBusy_View
  240. * instance based on $view. It will only create a new instance if no
  241. * Kronolith_FreeBusy_View instance with the same parameters currently
  242. * exists.
  243. *
  244. * This method must be invoked as:
  245. * $var = &Kronolith_FreeBusy_View::singleton()
  246. *
  247. * @param string $view The type of concrete Kronolith_FreeBusy_View
  248. * subclass to return.
  249. *
  250. * @return mixed The created concrete Kronolith_FreeBusy_View instance, or
  251. * false on an error.
  252. */
  253. static public function &singleton($view)
  254. {
  255. static $instances = array();
  256. if (!isset($instances[$view])) {
  257. $instances[$view] = Kronolith_FreeBusy_View::factory($view);
  258. }
  259. return $instances[$view];
  260. }
  261. /**
  262. * Render the blocks
  263. *
  264. * @param Horde_Icalendar_Vfreebusy $member Member's freebusy info
  265. * @param array $periods Free periods
  266. * @param string $blockfile Template file to use for blocks
  267. * @param string $label Label to use
  268. *
  269. * @return string The block html
  270. */
  271. protected function _getBlocks($member, $periods, $blockfile, $label)
  272. {
  273. $template = $GLOBALS['injector']->createInstance('Horde_Template');
  274. $template->set('label', $label);
  275. reset($periods);
  276. list($periodStart, $periodEnd) = each($periods);
  277. $blocks = '';
  278. foreach ($this->_timeBlocks as $span) {
  279. /* Horde_Icalendar_Vfreebusy only supports timestamps at the
  280. * moment. */
  281. $start = $span[0]->timestamp();
  282. $end = $span[1]->timestamp();
  283. if ($member->getStart() > $start ||
  284. $member->getEnd() < $end) {
  285. $blocks .= $template->fetch(KRONOLITH_TEMPLATES . '/fbview/unknownblock.html');
  286. continue;
  287. }
  288. while ($start > $periodEnd &&
  289. list($periodStart, $periodEnd) = each($periods));
  290. if (($periodStart <= $start && $periodEnd >= $start) ||
  291. ($periodStart <= $end && $periodEnd >= $end) ||
  292. ($periodStart <= $start && $periodEnd >= $end) ||
  293. ($periodStart >= $start && $periodEnd <= $end)) {
  294. $l_start = ($periodStart < $start) ? $start : $periodStart;
  295. $l_end = ($periodEnd > $end) ? $end : $periodEnd;
  296. $plen = ($end - $start) / 100.0;
  297. $left = ($l_start - $start) / $plen;
  298. $width = ($l_end - $l_start) / $plen;
  299. $template->set('left', $left . '%');
  300. $template->set('width', $width . '%');
  301. $blocks .= $template->fetch(KRONOLITH_TEMPLATES . '/fbview/' . $blockfile);
  302. } else {
  303. $blocks .= $template->fetch(KRONOLITH_TEMPLATES . '/fbview/emptyblock.html');
  304. }
  305. }
  306. return $blocks;
  307. }
  308. abstract protected function _title();
  309. abstract protected function _hours();
  310. abstract protected function _render(Horde_Date $day = null);
  311. }