PageRenderTime 27ms CodeModel.GetById 10ms RepoModel.GetById 1ms app.codeStats 0ms

/rainloop/v/0.0.0/app/libraries/SabreForRainLoop/VObject/FreeBusyGenerator.php

https://gitlab.com/wuhang2003/rainloop-webmail
PHP | 322 lines | 168 code | 71 blank | 83 comment | 37 complexity | 63c8694cfc21608cb7a8dde1f9632bc5 MD5 | raw file
  1. <?php
  2. namespace SabreForRainLoop\VObject;
  3. use
  4. SabreForRainLoop\VObject\Component\VCalendar;
  5. /**
  6. * This class helps with generating FREEBUSY reports based on existing sets of
  7. * objects.
  8. *
  9. * It only looks at VEVENT and VFREEBUSY objects from the sourcedata, and
  10. * generates a single VFREEBUSY object.
  11. *
  12. * VFREEBUSY components are described in RFC5545, The rules for what should
  13. * go in a single freebusy report is taken from RFC4791, section 7.10.
  14. *
  15. * @copyright Copyright (C) 2007-2013 fruux GmbH (https://fruux.com/).
  16. * @author Evert Pot (http://evertpot.com/)
  17. * @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
  18. */
  19. class FreeBusyGenerator {
  20. /**
  21. * Input objects
  22. *
  23. * @var array
  24. */
  25. protected $objects;
  26. /**
  27. * Start of range
  28. *
  29. * @var DateTime|null
  30. */
  31. protected $start;
  32. /**
  33. * End of range
  34. *
  35. * @var DateTime|null
  36. */
  37. protected $end;
  38. /**
  39. * VCALENDAR object
  40. *
  41. * @var Component
  42. */
  43. protected $baseObject;
  44. /**
  45. * Creates the generator.
  46. *
  47. * Check the setTimeRange and setObjects methods for details about the
  48. * arguments.
  49. *
  50. * @param DateTime $start
  51. * @param DateTime $end
  52. * @param mixed $objects
  53. * @return void
  54. */
  55. public function __construct(\DateTime $start = null, \DateTime $end = null, $objects = null) {
  56. if ($start && $end) {
  57. $this->setTimeRange($start, $end);
  58. }
  59. if ($objects) {
  60. $this->setObjects($objects);
  61. }
  62. }
  63. /**
  64. * Sets the VCALENDAR object.
  65. *
  66. * If this is set, it will not be generated for you. You are responsible
  67. * for setting things like the METHOD, CALSCALE, VERSION, etc..
  68. *
  69. * The VFREEBUSY object will be automatically added though.
  70. *
  71. * @param Component $vcalendar
  72. * @return void
  73. */
  74. public function setBaseObject(Component $vcalendar) {
  75. $this->baseObject = $vcalendar;
  76. }
  77. /**
  78. * Sets the input objects
  79. *
  80. * You must either specify a valendar object as a strong, or as the parse
  81. * Component.
  82. * It's also possible to specify multiple objects as an array.
  83. *
  84. * @param mixed $objects
  85. * @return void
  86. */
  87. public function setObjects($objects) {
  88. if (!is_array($objects)) {
  89. $objects = array($objects);
  90. }
  91. $this->objects = array();
  92. foreach($objects as $object) {
  93. if (is_string($object)) {
  94. $this->objects[] = Reader::read($object);
  95. } elseif ($object instanceof Component) {
  96. $this->objects[] = $object;
  97. } else {
  98. throw new \InvalidArgumentException('You can only pass strings or \\SabreForRainLoop\\VObject\\Component arguments to setObjects');
  99. }
  100. }
  101. }
  102. /**
  103. * Sets the time range
  104. *
  105. * Any freebusy object falling outside of this time range will be ignored.
  106. *
  107. * @param DateTime $start
  108. * @param DateTime $end
  109. * @return void
  110. */
  111. public function setTimeRange(\DateTime $start = null, \DateTime $end = null) {
  112. $this->start = $start;
  113. $this->end = $end;
  114. }
  115. /**
  116. * Parses the input data and returns a correct VFREEBUSY object, wrapped in
  117. * a VCALENDAR.
  118. *
  119. * @return Component
  120. */
  121. public function getResult() {
  122. $busyTimes = array();
  123. foreach($this->objects as $object) {
  124. foreach($object->getBaseComponents() as $component) {
  125. switch($component->name) {
  126. case 'VEVENT' :
  127. $FBTYPE = 'BUSY';
  128. if (isset($component->TRANSP) && (strtoupper($component->TRANSP) === 'TRANSPARENT')) {
  129. break;
  130. }
  131. if (isset($component->STATUS)) {
  132. $status = strtoupper($component->STATUS);
  133. if ($status==='CANCELLED') {
  134. break;
  135. }
  136. if ($status==='TENTATIVE') {
  137. $FBTYPE = 'BUSY-TENTATIVE';
  138. }
  139. }
  140. $times = array();
  141. if ($component->RRULE) {
  142. $iterator = new RecurrenceIterator($object, (string)$component->uid);
  143. if ($this->start) {
  144. $iterator->fastForward($this->start);
  145. }
  146. $maxRecurrences = 200;
  147. while($iterator->valid() && --$maxRecurrences) {
  148. $startTime = $iterator->getDTStart();
  149. if ($this->end && $startTime > $this->end) {
  150. break;
  151. }
  152. $times[] = array(
  153. $iterator->getDTStart(),
  154. $iterator->getDTEnd(),
  155. );
  156. $iterator->next();
  157. }
  158. } else {
  159. $startTime = $component->DTSTART->getDateTime();
  160. if ($this->end && $startTime > $this->end) {
  161. break;
  162. }
  163. $endTime = null;
  164. if (isset($component->DTEND)) {
  165. $endTime = $component->DTEND->getDateTime();
  166. } elseif (isset($component->DURATION)) {
  167. $duration = DateTimeParser::parseDuration((string)$component->DURATION);
  168. $endTime = clone $startTime;
  169. $endTime->add($duration);
  170. } elseif (!$component->DTSTART->hasTime()) {
  171. $endTime = clone $startTime;
  172. $endTime->modify('+1 day');
  173. } else {
  174. // The event had no duration (0 seconds)
  175. break;
  176. }
  177. $times[] = array($startTime, $endTime);
  178. }
  179. foreach($times as $time) {
  180. if ($this->end && $time[0] > $this->end) break;
  181. if ($this->start && $time[1] < $this->start) break;
  182. $busyTimes[] = array(
  183. $time[0],
  184. $time[1],
  185. $FBTYPE,
  186. );
  187. }
  188. break;
  189. case 'VFREEBUSY' :
  190. foreach($component->FREEBUSY as $freebusy) {
  191. $fbType = isset($freebusy['FBTYPE'])?strtoupper($freebusy['FBTYPE']):'BUSY';
  192. // Skipping intervals marked as 'free'
  193. if ($fbType==='FREE')
  194. continue;
  195. $values = explode(',', $freebusy);
  196. foreach($values as $value) {
  197. list($startTime, $endTime) = explode('/', $value);
  198. $startTime = DateTimeParser::parseDateTime($startTime);
  199. if (substr($endTime,0,1)==='P' || substr($endTime,0,2)==='-P') {
  200. $duration = DateTimeParser::parseDuration($endTime);
  201. $endTime = clone $startTime;
  202. $endTime->add($duration);
  203. } else {
  204. $endTime = DateTimeParser::parseDateTime($endTime);
  205. }
  206. if($this->start && $this->start > $endTime) continue;
  207. if($this->end && $this->end < $startTime) continue;
  208. $busyTimes[] = array(
  209. $startTime,
  210. $endTime,
  211. $fbType
  212. );
  213. }
  214. }
  215. break;
  216. }
  217. }
  218. }
  219. if ($this->baseObject) {
  220. $calendar = $this->baseObject;
  221. } else {
  222. $calendar = new VCalendar();
  223. }
  224. $vfreebusy = $calendar->createComponent('VFREEBUSY');
  225. $calendar->add($vfreebusy);
  226. if ($this->start) {
  227. $dtstart = $calendar->createProperty('DTSTART');
  228. $dtstart->setDateTime($this->start);
  229. $vfreebusy->add($dtstart);
  230. }
  231. if ($this->end) {
  232. $dtend = $calendar->createProperty('DTEND');
  233. $dtend->setDateTime($this->end);
  234. $vfreebusy->add($dtend);
  235. }
  236. $dtstamp = $calendar->createProperty('DTSTAMP');
  237. $dtstamp->setDateTime(new \DateTime('now', new \DateTimeZone('UTC')));
  238. $vfreebusy->add($dtstamp);
  239. foreach($busyTimes as $busyTime) {
  240. $busyTime[0]->setTimeZone(new \DateTimeZone('UTC'));
  241. $busyTime[1]->setTimeZone(new \DateTimeZone('UTC'));
  242. $prop = $calendar->createProperty(
  243. 'FREEBUSY',
  244. $busyTime[0]->format('Ymd\\THis\\Z') . '/' . $busyTime[1]->format('Ymd\\THis\\Z')
  245. );
  246. $prop['FBTYPE'] = $busyTime[2];
  247. $vfreebusy->add($prop);
  248. }
  249. return $calendar;
  250. }
  251. }