BirthdayCalendarGenerator.php 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. <?php
  2. namespace Sabre\VObject;
  3. use Sabre\VObject\Component\VCalendar;
  4. /**
  5. * This class generates birthday calendars.
  6. *
  7. * @copyright Copyright (C) fruux GmbH (https://fruux.com/)
  8. * @author Dominik Tobschall (http://tobschall.de/)
  9. * @license http://sabre.io/license/ Modified BSD License
  10. */
  11. class BirthdayCalendarGenerator
  12. {
  13. /**
  14. * Input objects.
  15. *
  16. * @var array
  17. */
  18. protected $objects = [];
  19. /**
  20. * Default year.
  21. * Used for dates without a year.
  22. */
  23. const DEFAULT_YEAR = 2000;
  24. /**
  25. * Output format for the SUMMARY.
  26. *
  27. * @var string
  28. */
  29. protected $format = '%1$s\'s Birthday';
  30. /**
  31. * Creates the generator.
  32. *
  33. * Check the setTimeRange and setObjects methods for details about the
  34. * arguments.
  35. *
  36. * @param mixed $objects
  37. */
  38. public function __construct($objects = null)
  39. {
  40. if ($objects) {
  41. $this->setObjects($objects);
  42. }
  43. }
  44. /**
  45. * Sets the input objects.
  46. *
  47. * You must either supply a vCard as a string or as a Component/VCard object.
  48. * It's also possible to supply an array of strings or objects.
  49. *
  50. * @param mixed $objects
  51. */
  52. public function setObjects($objects)
  53. {
  54. if (!is_array($objects)) {
  55. $objects = [$objects];
  56. }
  57. $this->objects = [];
  58. foreach ($objects as $object) {
  59. if (is_string($object)) {
  60. $vObj = Reader::read($object);
  61. if (!$vObj instanceof Component\VCard) {
  62. throw new \InvalidArgumentException('String could not be parsed as \\Sabre\\VObject\\Component\\VCard by setObjects');
  63. }
  64. $this->objects[] = $vObj;
  65. } elseif ($object instanceof Component\VCard) {
  66. $this->objects[] = $object;
  67. } else {
  68. throw new \InvalidArgumentException('You can only pass strings or \\Sabre\\VObject\\Component\\VCard arguments to setObjects');
  69. }
  70. }
  71. }
  72. /**
  73. * Sets the output format for the SUMMARY.
  74. *
  75. * @param string $format
  76. */
  77. public function setFormat($format)
  78. {
  79. $this->format = $format;
  80. }
  81. /**
  82. * Parses the input data and returns a VCALENDAR.
  83. *
  84. * @return Component/VCalendar
  85. */
  86. public function getResult()
  87. {
  88. $calendar = new VCalendar();
  89. foreach ($this->objects as $object) {
  90. // Skip if there is no BDAY property.
  91. if (!$object->select('BDAY')) {
  92. continue;
  93. }
  94. // We've seen clients (ez-vcard) putting "BDAY:" properties
  95. // without a value into vCards. If we come across those, we'll
  96. // skip them.
  97. if (empty($object->BDAY->getValue())) {
  98. continue;
  99. }
  100. // We're always converting to vCard 4.0 so we can rely on the
  101. // VCardConverter handling the X-APPLE-OMIT-YEAR property for us.
  102. $object = $object->convert(Document::VCARD40);
  103. // Skip if the card has no FN property.
  104. if (!isset($object->FN)) {
  105. continue;
  106. }
  107. // Skip if the BDAY property is not of the right type.
  108. if (!$object->BDAY instanceof Property\VCard\DateAndOrTime) {
  109. continue;
  110. }
  111. // Skip if we can't parse the BDAY value.
  112. try {
  113. $dateParts = DateTimeParser::parseVCardDateTime($object->BDAY->getValue());
  114. } catch (InvalidDataException $e) {
  115. continue;
  116. }
  117. // Set a year if it's not set.
  118. $unknownYear = false;
  119. if (!$dateParts['year']) {
  120. $object->BDAY = self::DEFAULT_YEAR.'-'.$dateParts['month'].'-'.$dateParts['date'];
  121. $unknownYear = true;
  122. }
  123. // Create event.
  124. $event = $calendar->add('VEVENT', [
  125. 'SUMMARY' => sprintf($this->format, $object->FN->getValue()),
  126. 'DTSTART' => new \DateTime($object->BDAY->getValue()),
  127. 'RRULE' => 'FREQ=YEARLY',
  128. 'TRANSP' => 'TRANSPARENT',
  129. ]);
  130. // add VALUE=date
  131. $event->DTSTART['VALUE'] = 'DATE';
  132. // Add X-SABRE-BDAY property.
  133. if ($unknownYear) {
  134. $event->add('X-SABRE-BDAY', 'BDAY', [
  135. 'X-SABRE-VCARD-UID' => $object->UID->getValue(),
  136. 'X-SABRE-VCARD-FN' => $object->FN->getValue(),
  137. 'X-SABRE-OMIT-YEAR' => self::DEFAULT_YEAR,
  138. ]);
  139. } else {
  140. $event->add('X-SABRE-BDAY', 'BDAY', [
  141. 'X-SABRE-VCARD-UID' => $object->UID->getValue(),
  142. 'X-SABRE-VCARD-FN' => $object->FN->getValue(),
  143. ]);
  144. }
  145. }
  146. return $calendar;
  147. }
  148. }