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