1*a1a3b679SAndreas Boehler<?php 2*a1a3b679SAndreas Boehler 3*a1a3b679SAndreas Boehlernamespace Sabre\CalDAV\Xml\Property; 4*a1a3b679SAndreas Boehler 5*a1a3b679SAndreas Boehleruse Sabre\Xml\Element; 6*a1a3b679SAndreas Boehleruse Sabre\Xml\Reader; 7*a1a3b679SAndreas Boehleruse Sabre\Xml\Writer; 8*a1a3b679SAndreas Boehleruse Sabre\CalDAV\Plugin; 9*a1a3b679SAndreas Boehleruse Sabre\CalDAV\SharingPlugin; 10*a1a3b679SAndreas Boehler 11*a1a3b679SAndreas Boehler/** 12*a1a3b679SAndreas Boehler * Invite property 13*a1a3b679SAndreas Boehler * 14*a1a3b679SAndreas Boehler * This property encodes the 'invite' property, as defined by 15*a1a3b679SAndreas Boehler * the 'caldav-sharing-02' spec, in the http://calendarserver.org/ns/ 16*a1a3b679SAndreas Boehler * namespace. 17*a1a3b679SAndreas Boehler * 18*a1a3b679SAndreas Boehler * @see https://trac.calendarserver.org/browser/CalendarServer/trunk/doc/Extensions/caldav-sharing-02.txt 19*a1a3b679SAndreas Boehler * @copyright Copyright (C) 2007-2015 fruux GmbH (https://fruux.com/). 20*a1a3b679SAndreas Boehler * @author Evert Pot (http://evertpot.com/) 21*a1a3b679SAndreas Boehler * @license http://sabre.io/license/ Modified BSD License 22*a1a3b679SAndreas Boehler */ 23*a1a3b679SAndreas Boehlerclass Invite implements Element { 24*a1a3b679SAndreas Boehler 25*a1a3b679SAndreas Boehler /** 26*a1a3b679SAndreas Boehler * The list of users a calendar has been shared to. 27*a1a3b679SAndreas Boehler * 28*a1a3b679SAndreas Boehler * @var array 29*a1a3b679SAndreas Boehler */ 30*a1a3b679SAndreas Boehler protected $users; 31*a1a3b679SAndreas Boehler 32*a1a3b679SAndreas Boehler /** 33*a1a3b679SAndreas Boehler * The organizer contains information about the person who shared the 34*a1a3b679SAndreas Boehler * object. 35*a1a3b679SAndreas Boehler * 36*a1a3b679SAndreas Boehler * @var array 37*a1a3b679SAndreas Boehler */ 38*a1a3b679SAndreas Boehler protected $organizer; 39*a1a3b679SAndreas Boehler 40*a1a3b679SAndreas Boehler /** 41*a1a3b679SAndreas Boehler * Creates the property. 42*a1a3b679SAndreas Boehler * 43*a1a3b679SAndreas Boehler * Users is an array. Each element of the array has the following 44*a1a3b679SAndreas Boehler * properties: 45*a1a3b679SAndreas Boehler * 46*a1a3b679SAndreas Boehler * * href - Often a mailto: address 47*a1a3b679SAndreas Boehler * * commonName - Optional, for example a first and lastname for a user. 48*a1a3b679SAndreas Boehler * * status - One of the SharingPlugin::STATUS_* constants. 49*a1a3b679SAndreas Boehler * * readOnly - true or false 50*a1a3b679SAndreas Boehler * * summary - Optional, description of the share 51*a1a3b679SAndreas Boehler * 52*a1a3b679SAndreas Boehler * The organizer key is optional to specify. It's only useful when a 53*a1a3b679SAndreas Boehler * 'sharee' requests the sharing information. 54*a1a3b679SAndreas Boehler * 55*a1a3b679SAndreas Boehler * The organizer may have the following properties: 56*a1a3b679SAndreas Boehler * * href - Often a mailto: address. 57*a1a3b679SAndreas Boehler * * commonName - Optional human-readable name. 58*a1a3b679SAndreas Boehler * * firstName - Optional first name. 59*a1a3b679SAndreas Boehler * * lastName - Optional last name. 60*a1a3b679SAndreas Boehler * 61*a1a3b679SAndreas Boehler * If you wonder why these two structures are so different, I guess a 62*a1a3b679SAndreas Boehler * valid answer is that the current spec is still a draft. 63*a1a3b679SAndreas Boehler * 64*a1a3b679SAndreas Boehler * @param array $users 65*a1a3b679SAndreas Boehler */ 66*a1a3b679SAndreas Boehler function __construct(array $users, array $organizer = null) { 67*a1a3b679SAndreas Boehler 68*a1a3b679SAndreas Boehler $this->users = $users; 69*a1a3b679SAndreas Boehler $this->organizer = $organizer; 70*a1a3b679SAndreas Boehler 71*a1a3b679SAndreas Boehler } 72*a1a3b679SAndreas Boehler 73*a1a3b679SAndreas Boehler /** 74*a1a3b679SAndreas Boehler * Returns the list of users, as it was passed to the constructor. 75*a1a3b679SAndreas Boehler * 76*a1a3b679SAndreas Boehler * @return array 77*a1a3b679SAndreas Boehler */ 78*a1a3b679SAndreas Boehler function getValue() { 79*a1a3b679SAndreas Boehler 80*a1a3b679SAndreas Boehler return $this->users; 81*a1a3b679SAndreas Boehler 82*a1a3b679SAndreas Boehler } 83*a1a3b679SAndreas Boehler 84*a1a3b679SAndreas Boehler /** 85*a1a3b679SAndreas Boehler * The xmlSerialize metod is called during xml writing. 86*a1a3b679SAndreas Boehler * 87*a1a3b679SAndreas Boehler * Use the $writer argument to write its own xml serialization. 88*a1a3b679SAndreas Boehler * 89*a1a3b679SAndreas Boehler * An important note: do _not_ create a parent element. Any element 90*a1a3b679SAndreas Boehler * implementing XmlSerializble should only ever write what's considered 91*a1a3b679SAndreas Boehler * its 'inner xml'. 92*a1a3b679SAndreas Boehler * 93*a1a3b679SAndreas Boehler * The parent of the current element is responsible for writing a 94*a1a3b679SAndreas Boehler * containing element. 95*a1a3b679SAndreas Boehler * 96*a1a3b679SAndreas Boehler * This allows serializers to be re-used for different element names. 97*a1a3b679SAndreas Boehler * 98*a1a3b679SAndreas Boehler * If you are opening new elements, you must also close them again. 99*a1a3b679SAndreas Boehler * 100*a1a3b679SAndreas Boehler * @param Writer $writer 101*a1a3b679SAndreas Boehler * @return void 102*a1a3b679SAndreas Boehler */ 103*a1a3b679SAndreas Boehler function xmlSerialize(Writer $writer) { 104*a1a3b679SAndreas Boehler 105*a1a3b679SAndreas Boehler $cs = '{' . Plugin::NS_CALENDARSERVER . '}'; 106*a1a3b679SAndreas Boehler 107*a1a3b679SAndreas Boehler if (!is_null($this->organizer)) { 108*a1a3b679SAndreas Boehler 109*a1a3b679SAndreas Boehler $writer->startElement($cs . 'organizer'); 110*a1a3b679SAndreas Boehler $writer->writeElement('{DAV:}href', $this->organizer['href']); 111*a1a3b679SAndreas Boehler 112*a1a3b679SAndreas Boehler if (isset($this->organizer['commonName']) && $this->organizer['commonName']) { 113*a1a3b679SAndreas Boehler $writer->writeElement($cs . 'common-name', $this->organizer['commonName']); 114*a1a3b679SAndreas Boehler } 115*a1a3b679SAndreas Boehler if (isset($this->organizer['firstName']) && $this->organizer['firstName']) { 116*a1a3b679SAndreas Boehler $writer->writeElement($cs . 'first-name', $this->organizer['firstName']); 117*a1a3b679SAndreas Boehler } 118*a1a3b679SAndreas Boehler if (isset($this->organizer['lastName']) && $this->organizer['lastName']) { 119*a1a3b679SAndreas Boehler $writer->writeElement($cs . 'last-name', $this->organizer['lastName']); 120*a1a3b679SAndreas Boehler } 121*a1a3b679SAndreas Boehler $writer->endElement(); // organizer 122*a1a3b679SAndreas Boehler 123*a1a3b679SAndreas Boehler } 124*a1a3b679SAndreas Boehler 125*a1a3b679SAndreas Boehler foreach ($this->users as $user) { 126*a1a3b679SAndreas Boehler 127*a1a3b679SAndreas Boehler $writer->startElement($cs . 'user'); 128*a1a3b679SAndreas Boehler $writer->writeElement('{DAV:}href', $user['href']); 129*a1a3b679SAndreas Boehler if (isset($user['commonName']) && $user['commonName']) { 130*a1a3b679SAndreas Boehler $writer->writeElement($cs . 'common-name', $user['commonName']); 131*a1a3b679SAndreas Boehler } 132*a1a3b679SAndreas Boehler switch ($user['status']) { 133*a1a3b679SAndreas Boehler 134*a1a3b679SAndreas Boehler case SharingPlugin::STATUS_ACCEPTED : 135*a1a3b679SAndreas Boehler $writer->writeElement($cs . 'invite-accepted'); 136*a1a3b679SAndreas Boehler break; 137*a1a3b679SAndreas Boehler case SharingPlugin::STATUS_DECLINED : 138*a1a3b679SAndreas Boehler $writer->writeElement($cs . 'invite-declined'); 139*a1a3b679SAndreas Boehler break; 140*a1a3b679SAndreas Boehler case SharingPlugin::STATUS_NORESPONSE : 141*a1a3b679SAndreas Boehler $writer->writeElement($cs . 'invite-noresponse'); 142*a1a3b679SAndreas Boehler break; 143*a1a3b679SAndreas Boehler case SharingPlugin::STATUS_INVALID : 144*a1a3b679SAndreas Boehler $writer->writeElement($cs . 'invite-invalid'); 145*a1a3b679SAndreas Boehler break; 146*a1a3b679SAndreas Boehler } 147*a1a3b679SAndreas Boehler 148*a1a3b679SAndreas Boehler $writer->startElement($cs . 'access'); 149*a1a3b679SAndreas Boehler if ($user['readOnly']) { 150*a1a3b679SAndreas Boehler $writer->writeElement($cs . 'read'); 151*a1a3b679SAndreas Boehler } else { 152*a1a3b679SAndreas Boehler $writer->writeElement($cs . 'read-write'); 153*a1a3b679SAndreas Boehler } 154*a1a3b679SAndreas Boehler $writer->endElement(); // access 155*a1a3b679SAndreas Boehler 156*a1a3b679SAndreas Boehler if (isset($user['summary']) && $user['summary']) { 157*a1a3b679SAndreas Boehler $writer->writeElement($cs . 'summary', $user['summary']); 158*a1a3b679SAndreas Boehler } 159*a1a3b679SAndreas Boehler 160*a1a3b679SAndreas Boehler $writer->endElement(); //user 161*a1a3b679SAndreas Boehler 162*a1a3b679SAndreas Boehler } 163*a1a3b679SAndreas Boehler 164*a1a3b679SAndreas Boehler } 165*a1a3b679SAndreas Boehler 166*a1a3b679SAndreas Boehler /** 167*a1a3b679SAndreas Boehler * The deserialize method is called during xml parsing. 168*a1a3b679SAndreas Boehler * 169*a1a3b679SAndreas Boehler * This method is called statictly, this is because in theory this method 170*a1a3b679SAndreas Boehler * may be used as a type of constructor, or factory method. 171*a1a3b679SAndreas Boehler * 172*a1a3b679SAndreas Boehler * Often you want to return an instance of the current class, but you are 173*a1a3b679SAndreas Boehler * free to return other data as well. 174*a1a3b679SAndreas Boehler * 175*a1a3b679SAndreas Boehler * You are responsible for advancing the reader to the next element. Not 176*a1a3b679SAndreas Boehler * doing anything will result in a never-ending loop. 177*a1a3b679SAndreas Boehler * 178*a1a3b679SAndreas Boehler * If you just want to skip parsing for this element altogether, you can 179*a1a3b679SAndreas Boehler * just call $reader->next(); 180*a1a3b679SAndreas Boehler * 181*a1a3b679SAndreas Boehler * $reader->parseInnerTree() will parse the entire sub-tree, and advance to 182*a1a3b679SAndreas Boehler * the next element. 183*a1a3b679SAndreas Boehler * 184*a1a3b679SAndreas Boehler * @param Reader $reader 185*a1a3b679SAndreas Boehler * @return mixed 186*a1a3b679SAndreas Boehler */ 187*a1a3b679SAndreas Boehler static function xmlDeserialize(Reader $reader) { 188*a1a3b679SAndreas Boehler 189*a1a3b679SAndreas Boehler $cs = '{' . Plugin::NS_CALENDARSERVER . '}'; 190*a1a3b679SAndreas Boehler 191*a1a3b679SAndreas Boehler $users = []; 192*a1a3b679SAndreas Boehler 193*a1a3b679SAndreas Boehler foreach ($reader->parseInnerTree() as $elem) { 194*a1a3b679SAndreas Boehler 195*a1a3b679SAndreas Boehler if ($elem['name'] !== $cs . 'user') 196*a1a3b679SAndreas Boehler continue; 197*a1a3b679SAndreas Boehler 198*a1a3b679SAndreas Boehler $user = [ 199*a1a3b679SAndreas Boehler 'href' => null, 200*a1a3b679SAndreas Boehler 'commonName' => null, 201*a1a3b679SAndreas Boehler 'readOnly' => null, 202*a1a3b679SAndreas Boehler 'summary' => null, 203*a1a3b679SAndreas Boehler 'status' => null, 204*a1a3b679SAndreas Boehler ]; 205*a1a3b679SAndreas Boehler 206*a1a3b679SAndreas Boehler foreach ($elem['value'] as $userElem) { 207*a1a3b679SAndreas Boehler 208*a1a3b679SAndreas Boehler switch ($userElem['name']) { 209*a1a3b679SAndreas Boehler case $cs . 'invite-accepted' : 210*a1a3b679SAndreas Boehler $user['status'] = SharingPlugin::STATUS_ACCEPTED; 211*a1a3b679SAndreas Boehler break; 212*a1a3b679SAndreas Boehler case $cs . 'invite-declined' : 213*a1a3b679SAndreas Boehler $user['status'] = SharingPlugin::STATUS_DECLINED; 214*a1a3b679SAndreas Boehler break; 215*a1a3b679SAndreas Boehler case $cs . 'invite-noresponse' : 216*a1a3b679SAndreas Boehler $user['status'] = SharingPlugin::STATUS_NORESPONSE; 217*a1a3b679SAndreas Boehler break; 218*a1a3b679SAndreas Boehler case $cs . 'invite-invalid' : 219*a1a3b679SAndreas Boehler $user['status'] = SharingPlugin::STATUS_INVALID; 220*a1a3b679SAndreas Boehler break; 221*a1a3b679SAndreas Boehler case '{DAV:}href' : 222*a1a3b679SAndreas Boehler $user['href'] = $userElem['value']; 223*a1a3b679SAndreas Boehler break; 224*a1a3b679SAndreas Boehler case $cs . 'common-name' : 225*a1a3b679SAndreas Boehler $user['commonName'] = $userElem['value']; 226*a1a3b679SAndreas Boehler break; 227*a1a3b679SAndreas Boehler case $cs . 'access' : 228*a1a3b679SAndreas Boehler foreach ($userElem['value'] as $accessHref) { 229*a1a3b679SAndreas Boehler if ($accessHref['name'] === $cs . 'read') { 230*a1a3b679SAndreas Boehler $user['readOnly'] = true; 231*a1a3b679SAndreas Boehler } 232*a1a3b679SAndreas Boehler } 233*a1a3b679SAndreas Boehler break; 234*a1a3b679SAndreas Boehler case $cs . 'summary' : 235*a1a3b679SAndreas Boehler $user['summary'] = $userElem['value']; 236*a1a3b679SAndreas Boehler break; 237*a1a3b679SAndreas Boehler 238*a1a3b679SAndreas Boehler } 239*a1a3b679SAndreas Boehler 240*a1a3b679SAndreas Boehler } 241*a1a3b679SAndreas Boehler if (!$user['status']) { 242*a1a3b679SAndreas Boehler throw new \InvalidArgumentException('Every user must have one of cs:invite-accepted, cs:invite-declined, cs:invite-noresponse or cs:invite-invalid'); 243*a1a3b679SAndreas Boehler } 244*a1a3b679SAndreas Boehler 245*a1a3b679SAndreas Boehler $users[] = $user; 246*a1a3b679SAndreas Boehler 247*a1a3b679SAndreas Boehler } 248*a1a3b679SAndreas Boehler 249*a1a3b679SAndreas Boehler return new self($users); 250*a1a3b679SAndreas Boehler 251*a1a3b679SAndreas Boehler } 252*a1a3b679SAndreas Boehler} 253