1*a1a3b679SAndreas Boehler<?php 2*a1a3b679SAndreas Boehler 3*a1a3b679SAndreas Boehlernamespace Sabre\CardDAV; 4*a1a3b679SAndreas Boehler 5*a1a3b679SAndreas Boehleruse Sabre\DAV; 6*a1a3b679SAndreas Boehleruse Sabre\DAVACL; 7*a1a3b679SAndreas Boehler 8*a1a3b679SAndreas Boehler/** 9*a1a3b679SAndreas Boehler * The AddressBook class represents a CardDAV addressbook, owned by a specific user 10*a1a3b679SAndreas Boehler * 11*a1a3b679SAndreas Boehler * The AddressBook can contain multiple vcards 12*a1a3b679SAndreas Boehler * 13*a1a3b679SAndreas Boehler * @copyright Copyright (C) 2007-2015 fruux GmbH (https://fruux.com/). 14*a1a3b679SAndreas Boehler * @author Evert Pot (http://evertpot.com/) 15*a1a3b679SAndreas Boehler * @license http://sabre.io/license/ Modified BSD License 16*a1a3b679SAndreas Boehler */ 17*a1a3b679SAndreas Boehlerclass AddressBook extends DAV\Collection implements IAddressBook, DAV\IProperties, DAVACL\IACL, DAV\Sync\ISyncCollection, DAV\IMultiGet { 18*a1a3b679SAndreas Boehler 19*a1a3b679SAndreas Boehler /** 20*a1a3b679SAndreas Boehler * This is an array with addressbook information 21*a1a3b679SAndreas Boehler * 22*a1a3b679SAndreas Boehler * @var array 23*a1a3b679SAndreas Boehler */ 24*a1a3b679SAndreas Boehler protected $addressBookInfo; 25*a1a3b679SAndreas Boehler 26*a1a3b679SAndreas Boehler /** 27*a1a3b679SAndreas Boehler * CardDAV backend 28*a1a3b679SAndreas Boehler * 29*a1a3b679SAndreas Boehler * @var Backend\BackendInterface 30*a1a3b679SAndreas Boehler */ 31*a1a3b679SAndreas Boehler protected $carddavBackend; 32*a1a3b679SAndreas Boehler 33*a1a3b679SAndreas Boehler /** 34*a1a3b679SAndreas Boehler * Constructor 35*a1a3b679SAndreas Boehler * 36*a1a3b679SAndreas Boehler * @param Backend\BackendInterface $carddavBackend 37*a1a3b679SAndreas Boehler * @param array $addressBookInfo 38*a1a3b679SAndreas Boehler */ 39*a1a3b679SAndreas Boehler function __construct(Backend\BackendInterface $carddavBackend, array $addressBookInfo) { 40*a1a3b679SAndreas Boehler 41*a1a3b679SAndreas Boehler $this->carddavBackend = $carddavBackend; 42*a1a3b679SAndreas Boehler $this->addressBookInfo = $addressBookInfo; 43*a1a3b679SAndreas Boehler 44*a1a3b679SAndreas Boehler } 45*a1a3b679SAndreas Boehler 46*a1a3b679SAndreas Boehler /** 47*a1a3b679SAndreas Boehler * Returns the name of the addressbook 48*a1a3b679SAndreas Boehler * 49*a1a3b679SAndreas Boehler * @return string 50*a1a3b679SAndreas Boehler */ 51*a1a3b679SAndreas Boehler function getName() { 52*a1a3b679SAndreas Boehler 53*a1a3b679SAndreas Boehler return $this->addressBookInfo['uri']; 54*a1a3b679SAndreas Boehler 55*a1a3b679SAndreas Boehler } 56*a1a3b679SAndreas Boehler 57*a1a3b679SAndreas Boehler /** 58*a1a3b679SAndreas Boehler * Returns a card 59*a1a3b679SAndreas Boehler * 60*a1a3b679SAndreas Boehler * @param string $name 61*a1a3b679SAndreas Boehler * @return \ICard 62*a1a3b679SAndreas Boehler */ 63*a1a3b679SAndreas Boehler function getChild($name) { 64*a1a3b679SAndreas Boehler 65*a1a3b679SAndreas Boehler $obj = $this->carddavBackend->getCard($this->addressBookInfo['id'], $name); 66*a1a3b679SAndreas Boehler if (!$obj) throw new DAV\Exception\NotFound('Card not found'); 67*a1a3b679SAndreas Boehler return new Card($this->carddavBackend, $this->addressBookInfo, $obj); 68*a1a3b679SAndreas Boehler 69*a1a3b679SAndreas Boehler } 70*a1a3b679SAndreas Boehler 71*a1a3b679SAndreas Boehler /** 72*a1a3b679SAndreas Boehler * Returns the full list of cards 73*a1a3b679SAndreas Boehler * 74*a1a3b679SAndreas Boehler * @return array 75*a1a3b679SAndreas Boehler */ 76*a1a3b679SAndreas Boehler function getChildren() { 77*a1a3b679SAndreas Boehler 78*a1a3b679SAndreas Boehler $objs = $this->carddavBackend->getCards($this->addressBookInfo['id']); 79*a1a3b679SAndreas Boehler $children = []; 80*a1a3b679SAndreas Boehler foreach ($objs as $obj) { 81*a1a3b679SAndreas Boehler $obj['acl'] = $this->getChildACL(); 82*a1a3b679SAndreas Boehler $children[] = new Card($this->carddavBackend, $this->addressBookInfo, $obj); 83*a1a3b679SAndreas Boehler } 84*a1a3b679SAndreas Boehler return $children; 85*a1a3b679SAndreas Boehler 86*a1a3b679SAndreas Boehler } 87*a1a3b679SAndreas Boehler 88*a1a3b679SAndreas Boehler /** 89*a1a3b679SAndreas Boehler * This method receives a list of paths in it's first argument. 90*a1a3b679SAndreas Boehler * It must return an array with Node objects. 91*a1a3b679SAndreas Boehler * 92*a1a3b679SAndreas Boehler * If any children are not found, you do not have to return them. 93*a1a3b679SAndreas Boehler * 94*a1a3b679SAndreas Boehler * @param string[] $paths 95*a1a3b679SAndreas Boehler * @return array 96*a1a3b679SAndreas Boehler */ 97*a1a3b679SAndreas Boehler function getMultipleChildren(array $paths) { 98*a1a3b679SAndreas Boehler 99*a1a3b679SAndreas Boehler $objs = $this->carddavBackend->getMultipleCards($this->addressBookInfo['id'], $paths); 100*a1a3b679SAndreas Boehler $children = []; 101*a1a3b679SAndreas Boehler foreach ($objs as $obj) { 102*a1a3b679SAndreas Boehler $obj['acl'] = $this->getChildACL(); 103*a1a3b679SAndreas Boehler $children[] = new Card($this->carddavBackend, $this->addressBookInfo, $obj); 104*a1a3b679SAndreas Boehler } 105*a1a3b679SAndreas Boehler return $children; 106*a1a3b679SAndreas Boehler 107*a1a3b679SAndreas Boehler } 108*a1a3b679SAndreas Boehler 109*a1a3b679SAndreas Boehler /** 110*a1a3b679SAndreas Boehler * Creates a new directory 111*a1a3b679SAndreas Boehler * 112*a1a3b679SAndreas Boehler * We actually block this, as subdirectories are not allowed in addressbooks. 113*a1a3b679SAndreas Boehler * 114*a1a3b679SAndreas Boehler * @param string $name 115*a1a3b679SAndreas Boehler * @return void 116*a1a3b679SAndreas Boehler */ 117*a1a3b679SAndreas Boehler function createDirectory($name) { 118*a1a3b679SAndreas Boehler 119*a1a3b679SAndreas Boehler throw new DAV\Exception\MethodNotAllowed('Creating collections in addressbooks is not allowed'); 120*a1a3b679SAndreas Boehler 121*a1a3b679SAndreas Boehler } 122*a1a3b679SAndreas Boehler 123*a1a3b679SAndreas Boehler /** 124*a1a3b679SAndreas Boehler * Creates a new file 125*a1a3b679SAndreas Boehler * 126*a1a3b679SAndreas Boehler * The contents of the new file must be a valid VCARD. 127*a1a3b679SAndreas Boehler * 128*a1a3b679SAndreas Boehler * This method may return an ETag. 129*a1a3b679SAndreas Boehler * 130*a1a3b679SAndreas Boehler * @param string $name 131*a1a3b679SAndreas Boehler * @param resource $vcardData 132*a1a3b679SAndreas Boehler * @return string|null 133*a1a3b679SAndreas Boehler */ 134*a1a3b679SAndreas Boehler function createFile($name, $vcardData = null) { 135*a1a3b679SAndreas Boehler 136*a1a3b679SAndreas Boehler if (is_resource($vcardData)) { 137*a1a3b679SAndreas Boehler $vcardData = stream_get_contents($vcardData); 138*a1a3b679SAndreas Boehler } 139*a1a3b679SAndreas Boehler // Converting to UTF-8, if needed 140*a1a3b679SAndreas Boehler $vcardData = DAV\StringUtil::ensureUTF8($vcardData); 141*a1a3b679SAndreas Boehler 142*a1a3b679SAndreas Boehler return $this->carddavBackend->createCard($this->addressBookInfo['id'], $name, $vcardData); 143*a1a3b679SAndreas Boehler 144*a1a3b679SAndreas Boehler } 145*a1a3b679SAndreas Boehler 146*a1a3b679SAndreas Boehler /** 147*a1a3b679SAndreas Boehler * Deletes the entire addressbook. 148*a1a3b679SAndreas Boehler * 149*a1a3b679SAndreas Boehler * @return void 150*a1a3b679SAndreas Boehler */ 151*a1a3b679SAndreas Boehler function delete() { 152*a1a3b679SAndreas Boehler 153*a1a3b679SAndreas Boehler $this->carddavBackend->deleteAddressBook($this->addressBookInfo['id']); 154*a1a3b679SAndreas Boehler 155*a1a3b679SAndreas Boehler } 156*a1a3b679SAndreas Boehler 157*a1a3b679SAndreas Boehler /** 158*a1a3b679SAndreas Boehler * Renames the addressbook 159*a1a3b679SAndreas Boehler * 160*a1a3b679SAndreas Boehler * @param string $newName 161*a1a3b679SAndreas Boehler * @return void 162*a1a3b679SAndreas Boehler */ 163*a1a3b679SAndreas Boehler function setName($newName) { 164*a1a3b679SAndreas Boehler 165*a1a3b679SAndreas Boehler throw new DAV\Exception\MethodNotAllowed('Renaming addressbooks is not yet supported'); 166*a1a3b679SAndreas Boehler 167*a1a3b679SAndreas Boehler } 168*a1a3b679SAndreas Boehler 169*a1a3b679SAndreas Boehler /** 170*a1a3b679SAndreas Boehler * Returns the last modification date as a unix timestamp. 171*a1a3b679SAndreas Boehler * 172*a1a3b679SAndreas Boehler * @return void 173*a1a3b679SAndreas Boehler */ 174*a1a3b679SAndreas Boehler function getLastModified() { 175*a1a3b679SAndreas Boehler 176*a1a3b679SAndreas Boehler return null; 177*a1a3b679SAndreas Boehler 178*a1a3b679SAndreas Boehler } 179*a1a3b679SAndreas Boehler 180*a1a3b679SAndreas Boehler /** 181*a1a3b679SAndreas Boehler * Updates properties on this node. 182*a1a3b679SAndreas Boehler * 183*a1a3b679SAndreas Boehler * This method received a PropPatch object, which contains all the 184*a1a3b679SAndreas Boehler * information about the update. 185*a1a3b679SAndreas Boehler * 186*a1a3b679SAndreas Boehler * To update specific properties, call the 'handle' method on this object. 187*a1a3b679SAndreas Boehler * Read the PropPatch documentation for more information. 188*a1a3b679SAndreas Boehler * 189*a1a3b679SAndreas Boehler * @param DAV\PropPatch $propPatch 190*a1a3b679SAndreas Boehler * @return void 191*a1a3b679SAndreas Boehler */ 192*a1a3b679SAndreas Boehler function propPatch(DAV\PropPatch $propPatch) { 193*a1a3b679SAndreas Boehler 194*a1a3b679SAndreas Boehler return $this->carddavBackend->updateAddressBook($this->addressBookInfo['id'], $propPatch); 195*a1a3b679SAndreas Boehler 196*a1a3b679SAndreas Boehler } 197*a1a3b679SAndreas Boehler 198*a1a3b679SAndreas Boehler /** 199*a1a3b679SAndreas Boehler * Returns a list of properties for this nodes. 200*a1a3b679SAndreas Boehler * 201*a1a3b679SAndreas Boehler * The properties list is a list of propertynames the client requested, 202*a1a3b679SAndreas Boehler * encoded in clark-notation {xmlnamespace}tagname 203*a1a3b679SAndreas Boehler * 204*a1a3b679SAndreas Boehler * If the array is empty, it means 'all properties' were requested. 205*a1a3b679SAndreas Boehler * 206*a1a3b679SAndreas Boehler * @param array $properties 207*a1a3b679SAndreas Boehler * @return array 208*a1a3b679SAndreas Boehler */ 209*a1a3b679SAndreas Boehler function getProperties($properties) { 210*a1a3b679SAndreas Boehler 211*a1a3b679SAndreas Boehler $response = []; 212*a1a3b679SAndreas Boehler foreach ($properties as $propertyName) { 213*a1a3b679SAndreas Boehler 214*a1a3b679SAndreas Boehler if (isset($this->addressBookInfo[$propertyName])) { 215*a1a3b679SAndreas Boehler 216*a1a3b679SAndreas Boehler $response[$propertyName] = $this->addressBookInfo[$propertyName]; 217*a1a3b679SAndreas Boehler 218*a1a3b679SAndreas Boehler } 219*a1a3b679SAndreas Boehler 220*a1a3b679SAndreas Boehler } 221*a1a3b679SAndreas Boehler 222*a1a3b679SAndreas Boehler return $response; 223*a1a3b679SAndreas Boehler 224*a1a3b679SAndreas Boehler } 225*a1a3b679SAndreas Boehler 226*a1a3b679SAndreas Boehler /** 227*a1a3b679SAndreas Boehler * Returns the owner principal 228*a1a3b679SAndreas Boehler * 229*a1a3b679SAndreas Boehler * This must be a url to a principal, or null if there's no owner 230*a1a3b679SAndreas Boehler * 231*a1a3b679SAndreas Boehler * @return string|null 232*a1a3b679SAndreas Boehler */ 233*a1a3b679SAndreas Boehler function getOwner() { 234*a1a3b679SAndreas Boehler 235*a1a3b679SAndreas Boehler return $this->addressBookInfo['principaluri']; 236*a1a3b679SAndreas Boehler 237*a1a3b679SAndreas Boehler } 238*a1a3b679SAndreas Boehler 239*a1a3b679SAndreas Boehler /** 240*a1a3b679SAndreas Boehler * Returns a group principal 241*a1a3b679SAndreas Boehler * 242*a1a3b679SAndreas Boehler * This must be a url to a principal, or null if there's no owner 243*a1a3b679SAndreas Boehler * 244*a1a3b679SAndreas Boehler * @return string|null 245*a1a3b679SAndreas Boehler */ 246*a1a3b679SAndreas Boehler function getGroup() { 247*a1a3b679SAndreas Boehler 248*a1a3b679SAndreas Boehler return null; 249*a1a3b679SAndreas Boehler 250*a1a3b679SAndreas Boehler } 251*a1a3b679SAndreas Boehler 252*a1a3b679SAndreas Boehler /** 253*a1a3b679SAndreas Boehler * Returns a list of ACE's for this node. 254*a1a3b679SAndreas Boehler * 255*a1a3b679SAndreas Boehler * Each ACE has the following properties: 256*a1a3b679SAndreas Boehler * * 'privilege', a string such as {DAV:}read or {DAV:}write. These are 257*a1a3b679SAndreas Boehler * currently the only supported privileges 258*a1a3b679SAndreas Boehler * * 'principal', a url to the principal who owns the node 259*a1a3b679SAndreas Boehler * * 'protected' (optional), indicating that this ACE is not allowed to 260*a1a3b679SAndreas Boehler * be updated. 261*a1a3b679SAndreas Boehler * 262*a1a3b679SAndreas Boehler * @return array 263*a1a3b679SAndreas Boehler */ 264*a1a3b679SAndreas Boehler function getACL() { 265*a1a3b679SAndreas Boehler 266*a1a3b679SAndreas Boehler return [ 267*a1a3b679SAndreas Boehler [ 268*a1a3b679SAndreas Boehler 'privilege' => '{DAV:}read', 269*a1a3b679SAndreas Boehler 'principal' => $this->getOwner(), 270*a1a3b679SAndreas Boehler 'protected' => true, 271*a1a3b679SAndreas Boehler ], 272*a1a3b679SAndreas Boehler [ 273*a1a3b679SAndreas Boehler 'privilege' => '{DAV:}write', 274*a1a3b679SAndreas Boehler 'principal' => $this->getOwner(), 275*a1a3b679SAndreas Boehler 'protected' => true, 276*a1a3b679SAndreas Boehler ], 277*a1a3b679SAndreas Boehler 278*a1a3b679SAndreas Boehler ]; 279*a1a3b679SAndreas Boehler 280*a1a3b679SAndreas Boehler } 281*a1a3b679SAndreas Boehler 282*a1a3b679SAndreas Boehler /** 283*a1a3b679SAndreas Boehler * This method returns the ACL's for card nodes in this address book. 284*a1a3b679SAndreas Boehler * The result of this method automatically gets passed to the 285*a1a3b679SAndreas Boehler * card nodes in this address book. 286*a1a3b679SAndreas Boehler * 287*a1a3b679SAndreas Boehler * @return array 288*a1a3b679SAndreas Boehler */ 289*a1a3b679SAndreas Boehler function getChildACL() { 290*a1a3b679SAndreas Boehler 291*a1a3b679SAndreas Boehler return [ 292*a1a3b679SAndreas Boehler [ 293*a1a3b679SAndreas Boehler 'privilege' => '{DAV:}read', 294*a1a3b679SAndreas Boehler 'principal' => $this->getOwner(), 295*a1a3b679SAndreas Boehler 'protected' => true, 296*a1a3b679SAndreas Boehler ], 297*a1a3b679SAndreas Boehler [ 298*a1a3b679SAndreas Boehler 'privilege' => '{DAV:}write', 299*a1a3b679SAndreas Boehler 'principal' => $this->getOwner(), 300*a1a3b679SAndreas Boehler 'protected' => true, 301*a1a3b679SAndreas Boehler ], 302*a1a3b679SAndreas Boehler ]; 303*a1a3b679SAndreas Boehler 304*a1a3b679SAndreas Boehler } 305*a1a3b679SAndreas Boehler 306*a1a3b679SAndreas Boehler /** 307*a1a3b679SAndreas Boehler * Updates the ACL 308*a1a3b679SAndreas Boehler * 309*a1a3b679SAndreas Boehler * This method will receive a list of new ACE's. 310*a1a3b679SAndreas Boehler * 311*a1a3b679SAndreas Boehler * @param array $acl 312*a1a3b679SAndreas Boehler * @return void 313*a1a3b679SAndreas Boehler */ 314*a1a3b679SAndreas Boehler function setACL(array $acl) { 315*a1a3b679SAndreas Boehler 316*a1a3b679SAndreas Boehler throw new DAV\Exception\MethodNotAllowed('Changing ACL is not yet supported'); 317*a1a3b679SAndreas Boehler 318*a1a3b679SAndreas Boehler } 319*a1a3b679SAndreas Boehler 320*a1a3b679SAndreas Boehler /** 321*a1a3b679SAndreas Boehler * Returns the list of supported privileges for this node. 322*a1a3b679SAndreas Boehler * 323*a1a3b679SAndreas Boehler * The returned data structure is a list of nested privileges. 324*a1a3b679SAndreas Boehler * See Sabre\DAVACL\Plugin::getDefaultSupportedPrivilegeSet for a simple 325*a1a3b679SAndreas Boehler * standard structure. 326*a1a3b679SAndreas Boehler * 327*a1a3b679SAndreas Boehler * If null is returned from this method, the default privilege set is used, 328*a1a3b679SAndreas Boehler * which is fine for most common usecases. 329*a1a3b679SAndreas Boehler * 330*a1a3b679SAndreas Boehler * @return array|null 331*a1a3b679SAndreas Boehler */ 332*a1a3b679SAndreas Boehler function getSupportedPrivilegeSet() { 333*a1a3b679SAndreas Boehler 334*a1a3b679SAndreas Boehler return null; 335*a1a3b679SAndreas Boehler 336*a1a3b679SAndreas Boehler } 337*a1a3b679SAndreas Boehler 338*a1a3b679SAndreas Boehler /** 339*a1a3b679SAndreas Boehler * This method returns the current sync-token for this collection. 340*a1a3b679SAndreas Boehler * This can be any string. 341*a1a3b679SAndreas Boehler * 342*a1a3b679SAndreas Boehler * If null is returned from this function, the plugin assumes there's no 343*a1a3b679SAndreas Boehler * sync information available. 344*a1a3b679SAndreas Boehler * 345*a1a3b679SAndreas Boehler * @return string|null 346*a1a3b679SAndreas Boehler */ 347*a1a3b679SAndreas Boehler function getSyncToken() { 348*a1a3b679SAndreas Boehler 349*a1a3b679SAndreas Boehler if ( 350*a1a3b679SAndreas Boehler $this->carddavBackend instanceof Backend\SyncSupport && 351*a1a3b679SAndreas Boehler isset($this->addressBookInfo['{DAV:}sync-token']) 352*a1a3b679SAndreas Boehler ) { 353*a1a3b679SAndreas Boehler return $this->addressBookInfo['{DAV:}sync-token']; 354*a1a3b679SAndreas Boehler } 355*a1a3b679SAndreas Boehler if ( 356*a1a3b679SAndreas Boehler $this->carddavBackend instanceof Backend\SyncSupport && 357*a1a3b679SAndreas Boehler isset($this->addressBookInfo['{http://sabredav.org/ns}sync-token']) 358*a1a3b679SAndreas Boehler ) { 359*a1a3b679SAndreas Boehler return $this->addressBookInfo['{http://sabredav.org/ns}sync-token']; 360*a1a3b679SAndreas Boehler } 361*a1a3b679SAndreas Boehler 362*a1a3b679SAndreas Boehler } 363*a1a3b679SAndreas Boehler 364*a1a3b679SAndreas Boehler /** 365*a1a3b679SAndreas Boehler * The getChanges method returns all the changes that have happened, since 366*a1a3b679SAndreas Boehler * the specified syncToken and the current collection. 367*a1a3b679SAndreas Boehler * 368*a1a3b679SAndreas Boehler * This function should return an array, such as the following: 369*a1a3b679SAndreas Boehler * 370*a1a3b679SAndreas Boehler * [ 371*a1a3b679SAndreas Boehler * 'syncToken' => 'The current synctoken', 372*a1a3b679SAndreas Boehler * 'added' => [ 373*a1a3b679SAndreas Boehler * 'new.txt', 374*a1a3b679SAndreas Boehler * ], 375*a1a3b679SAndreas Boehler * 'modified' => [ 376*a1a3b679SAndreas Boehler * 'modified.txt', 377*a1a3b679SAndreas Boehler * ], 378*a1a3b679SAndreas Boehler * 'deleted' => [ 379*a1a3b679SAndreas Boehler * 'foo.php.bak', 380*a1a3b679SAndreas Boehler * 'old.txt' 381*a1a3b679SAndreas Boehler * ] 382*a1a3b679SAndreas Boehler * ]; 383*a1a3b679SAndreas Boehler * 384*a1a3b679SAndreas Boehler * The syncToken property should reflect the *current* syncToken of the 385*a1a3b679SAndreas Boehler * collection, as reported getSyncToken(). This is needed here too, to 386*a1a3b679SAndreas Boehler * ensure the operation is atomic. 387*a1a3b679SAndreas Boehler * 388*a1a3b679SAndreas Boehler * If the syncToken is specified as null, this is an initial sync, and all 389*a1a3b679SAndreas Boehler * members should be reported. 390*a1a3b679SAndreas Boehler * 391*a1a3b679SAndreas Boehler * The modified property is an array of nodenames that have changed since 392*a1a3b679SAndreas Boehler * the last token. 393*a1a3b679SAndreas Boehler * 394*a1a3b679SAndreas Boehler * The deleted property is an array with nodenames, that have been deleted 395*a1a3b679SAndreas Boehler * from collection. 396*a1a3b679SAndreas Boehler * 397*a1a3b679SAndreas Boehler * The second argument is basically the 'depth' of the report. If it's 1, 398*a1a3b679SAndreas Boehler * you only have to report changes that happened only directly in immediate 399*a1a3b679SAndreas Boehler * descendants. If it's 2, it should also include changes from the nodes 400*a1a3b679SAndreas Boehler * below the child collections. (grandchildren) 401*a1a3b679SAndreas Boehler * 402*a1a3b679SAndreas Boehler * The third (optional) argument allows a client to specify how many 403*a1a3b679SAndreas Boehler * results should be returned at most. If the limit is not specified, it 404*a1a3b679SAndreas Boehler * should be treated as infinite. 405*a1a3b679SAndreas Boehler * 406*a1a3b679SAndreas Boehler * If the limit (infinite or not) is higher than you're willing to return, 407*a1a3b679SAndreas Boehler * you should throw a Sabre\DAV\Exception\TooMuchMatches() exception. 408*a1a3b679SAndreas Boehler * 409*a1a3b679SAndreas Boehler * If the syncToken is expired (due to data cleanup) or unknown, you must 410*a1a3b679SAndreas Boehler * return null. 411*a1a3b679SAndreas Boehler * 412*a1a3b679SAndreas Boehler * The limit is 'suggestive'. You are free to ignore it. 413*a1a3b679SAndreas Boehler * 414*a1a3b679SAndreas Boehler * @param string $syncToken 415*a1a3b679SAndreas Boehler * @param int $syncLevel 416*a1a3b679SAndreas Boehler * @param int $limit 417*a1a3b679SAndreas Boehler * @return array 418*a1a3b679SAndreas Boehler */ 419*a1a3b679SAndreas Boehler function getChanges($syncToken, $syncLevel, $limit = null) { 420*a1a3b679SAndreas Boehler 421*a1a3b679SAndreas Boehler if (!$this->carddavBackend instanceof Backend\SyncSupport) { 422*a1a3b679SAndreas Boehler return null; 423*a1a3b679SAndreas Boehler } 424*a1a3b679SAndreas Boehler 425*a1a3b679SAndreas Boehler return $this->carddavBackend->getChangesForAddressBook( 426*a1a3b679SAndreas Boehler $this->addressBookInfo['id'], 427*a1a3b679SAndreas Boehler $syncToken, 428*a1a3b679SAndreas Boehler $syncLevel, 429*a1a3b679SAndreas Boehler $limit 430*a1a3b679SAndreas Boehler ); 431*a1a3b679SAndreas Boehler 432*a1a3b679SAndreas Boehler } 433*a1a3b679SAndreas Boehler} 434