[Pkg-owncloud-commits] [php-sabredav] 40/163: Refactored Cal- and CardDAV

David Prévot taffit at moszumanska.debian.org
Tue May 20 18:54:52 UTC 2014


This is an automated email from the git hooks/post-receive script.

taffit pushed a commit to annotated tag upstream/2.0.0_beta1
in repository php-sabredav.

commit d0c1e83112445103a7aa684dbc73b3b4cc11ecaf
Author: Evert Pot <evert at rooftopsolutions.nl>
Date:   Sat Apr 5 02:23:35 2014 -0400

    Refactored Cal- and CardDAV
---
 lib/Sabre/CalDAV/Backend/AbstractBackend.php       |  42 +---
 lib/Sabre/CalDAV/Backend/BackendInterface.php      |  40 +---
 lib/Sabre/CalDAV/Backend/PDO.php                   | 223 ++++++---------------
 lib/Sabre/CalDAV/Backend/SubscriptionSupport.php   |  42 ++--
 lib/Sabre/CalDAV/Calendar.php                      |  19 +-
 lib/Sabre/CalDAV/SharingPlugin.php                 |  37 ++--
 lib/Sabre/CalDAV/Subscriptions/Subscription.php    |  46 ++---
 lib/Sabre/CardDAV/AddressBook.php                  |  46 +----
 lib/Sabre/CardDAV/Backend/BackendInterface.php     |  21 +-
 lib/Sabre/CardDAV/Backend/PDO.php                  |  90 +++++----
 lib/Sabre/CardDAV/Plugin.php                       |  53 ++---
 .../DAVACL/PrincipalBackend/BackendInterface.php   |   1 +
 tests/Sabre/CalDAV/Backend/AbstractPDOTest.php     |  53 ++---
 tests/Sabre/CalDAV/Backend/AbstractTest.php        |  10 +-
 tests/Sabre/CalDAV/Backend/Mock.php                |  42 ----
 .../CalDAV/Backend/MockSubscriptionSupport.php     |  51 ++---
 tests/Sabre/CalDAV/CalendarTest.php                |   9 +-
 tests/Sabre/CalDAV/SharingPluginTest.php           |  12 +-
 .../CalDAV/Subscriptions/SubscriptionTest.php      |   7 +-
 .../CalDAV/UserCalendarsSharedCalendarsTest.php    |   1 -
 tests/Sabre/CalDAV/UserCalendarsTest.php           |   1 -
 tests/Sabre/CardDAV/AddressBookTest.php            |   9 +-
 tests/Sabre/CardDAV/Backend/AbstractPDOTest.php    |  22 +-
 tests/Sabre/CardDAV/Backend/Mock.php               |  30 ++-
 tests/Sabre/CardDAV/PluginTest.php                 |  10 +-
 tests/Sabre/DAV/ServerPropsTest.php                |   6 +-
 26 files changed, 348 insertions(+), 575 deletions(-)

diff --git a/lib/Sabre/CalDAV/Backend/AbstractBackend.php b/lib/Sabre/CalDAV/Backend/AbstractBackend.php
index 6ae6c66..b35fa5a 100644
--- a/lib/Sabre/CalDAV/Backend/AbstractBackend.php
+++ b/lib/Sabre/CalDAV/Backend/AbstractBackend.php
@@ -19,42 +19,20 @@ abstract class AbstractBackend implements BackendInterface {
     /**
      * Updates properties for a calendar.
      *
-     * The mutations array uses the propertyName in clark-notation as key,
-     * and the array value for the property value. In the case a property
-     * should be deleted, the property value will be null.
+     * The list of mutations is stored in a Sabre\DAV\PropPatch object.
+     * To do the actual updates, you must tell this object which properties
+     * you're going to process with the handle() method.
      *
-     * This method must be atomic. If one property cannot be changed, the
-     * entire operation must fail.
+     * Calling the handle method is like telling the PropPatch object "I
+     * promise I can handle updating this property".
      *
-     * If the operation was successful, true can be returned.
-     * If the operation failed, false can be returned.
+     * Read the PropPatch documenation for more info and examples.
      *
-     * Deletion of a non-existent property is always successful.
-     *
-     * Lastly, it is optional to return detailed information about any
-     * failures. In this case an array should be returned with the following
-     * structure:
-     *
-     * array(
-     *   403 => array(
-     *      '{DAV:}displayname' => null,
-     *   ),
-     *   424 => array(
-     *      '{DAV:}owner' => null,
-     *   )
-     * )
-     *
-     * In this example it was forbidden to update {DAV:}displayname.
-     * (403 Forbidden), which in turn also caused {DAV:}owner to fail
-     * (424 Failed Dependency) because the request needs to be atomic.
-     *
-     * @param mixed $calendarId
-     * @param array $mutations
-     * @return bool|array
+     * @param string $path
+     * @param \Sabre\DAV\PropPatch $propPatch
+     * @return void
      */
-    public function updateCalendar($calendarId, array $mutations) {
-
-        return false;
+    public function updateCalendar($calendarId, \Sabre\DAV\PropPatch $propPatch) {
 
     }
 
diff --git a/lib/Sabre/CalDAV/Backend/BackendInterface.php b/lib/Sabre/CalDAV/Backend/BackendInterface.php
index 5bfb9e4..0337450 100644
--- a/lib/Sabre/CalDAV/Backend/BackendInterface.php
+++ b/lib/Sabre/CalDAV/Backend/BackendInterface.php
@@ -51,40 +51,20 @@ interface BackendInterface {
     /**
      * Updates properties for a calendar.
      *
-     * The mutations array uses the propertyName in clark-notation as key,
-     * and the array value for the property value. In the case a property
-     * should be deleted, the property value will be null.
+     * The list of mutations is stored in a Sabre\DAV\PropPatch object.
+     * To do the actual updates, you must tell this object which properties
+     * you're going to process with the handle() method.
      *
-     * This method must be atomic. If one property cannot be changed, the
-     * entire operation must fail.
+     * Calling the handle method is like telling the PropPatch object "I
+     * promise I can handle updating this property".
      *
-     * If the operation was successful, true can be returned.
-     * If the operation failed, false can be returned.
+     * Read the PropPatch documenation for more info and examples.
      *
-     * Deletion of a non-existent property is always successful.
-     *
-     * Lastly, it is optional to return detailed information about any
-     * failures. In this case an array should be returned with the following
-     * structure:
-     *
-     * array(
-     *   403 => array(
-     *      '{DAV:}displayname' => null,
-     *   ),
-     *   424 => array(
-     *      '{DAV:}owner' => null,
-     *   )
-     * )
-     *
-     * In this example it was forbidden to update {DAV:}displayname.
-     * (403 Forbidden), which in turn also caused {DAV:}owner to fail
-     * (424 Failed Dependency) because the request needs to be atomic.
-     *
-     * @param mixed $calendarId
-     * @param array $mutations
-     * @return bool|array
+     * @param string $path
+     * @param \Sabre\DAV\PropPatch $propPatch
+     * @return void
      */
-    public function updateCalendar($calendarId, array $mutations);
+    public function updateCalendar($calendarId, \Sabre\DAV\PropPatch $propPatch);
 
     /**
      * Delete a calendar and all it's objects
diff --git a/lib/Sabre/CalDAV/Backend/PDO.php b/lib/Sabre/CalDAV/Backend/PDO.php
index 72ff08b..8838e10 100644
--- a/lib/Sabre/CalDAV/Backend/PDO.php
+++ b/lib/Sabre/CalDAV/Backend/PDO.php
@@ -242,104 +242,54 @@ class PDO extends AbstractBackend implements SyncSupport, SubscriptionSupport {
     /**
      * Updates properties for a calendar.
      *
-     * The mutations array uses the propertyName in clark-notation as key,
-     * and the array value for the property value. In the case a property
-     * should be deleted, the property value will be null.
+     * The list of mutations is stored in a Sabre\DAV\PropPatch object.
+     * To do the actual updates, you must tell this object which properties
+     * you're going to process with the handle() method.
      *
-     * This method must be atomic. If one property cannot be changed, the
-     * entire operation must fail.
+     * Calling the handle method is like telling the PropPatch object "I
+     * promise I can handle updating this property".
      *
-     * If the operation was successful, true can be returned.
-     * If the operation failed, false can be returned.
-     *
-     * Deletion of a non-existent property is always successful.
-     *
-     * Lastly, it is optional to return detailed information about any
-     * failures. In this case an array should be returned with the following
-     * structure:
-     *
-     * [
-     *   403 => [
-     *      '{DAV:}displayname' => null,
-     *   ],
-     *   424 => [
-     *      '{DAV:}owner' => null,
-     *   ]
-     * ]
-     *
-     * In this example it was forbidden to update {DAV:}displayname.
-     * (403 Forbidden), which in turn also caused {DAV:}owner to fail
-     * (424 Failed Dependency) because the request needs to be atomic.
+     * Read the PropPatch documenation for more info and examples.
      *
      * @param string $calendarId
-     * @param array $mutations
-     * @return bool|array
+     * @param \Sabre\DAV\PropPatch $propPatch
+     * @return void
      */
-    public function updateCalendar($calendarId, array $mutations) {
-
-        $newValues = [];
-        $result = [
-            200 => [], // Ok
-            403 => [], // Forbidden
-            424 => [], // Failed Dependency
-        ];
+    public function updateCalendar($calendarId, \Sabre\DAV\PropPatch $propPatch) {
 
-        $hasError = false;
-
-        foreach($mutations as $propertyName=>$propertyValue) {
-
-            switch($propertyName) {
-                case '{' . CalDAV\Plugin::NS_CALDAV . '}schedule-calendar-transp' :
-                    $fieldName = 'transparent';
-                    $newValues[$fieldName] = $propertyValue->getValue()==='transparent';
-                    break;
-                default :
-                    // Checking the property map
-                    if (!isset($this->propertyMap[$propertyName])) {
-                        // We don't know about this property.
-                        $hasError = true;
-                        $result[403][$propertyName] = null;
-                        unset($mutations[$propertyName]);
-                        continue;
-                    }
+        $supportedProperties = array_keys($this->propertyMap);
+        $supportedProperties[] = '{' . CalDAV\Plugin::NS_CALDAV . '}schedule-calendar-transp';
 
-                    $fieldName = $this->propertyMap[$propertyName];
-                    $newValues[$fieldName] = $propertyValue;
-            }
+        $propPatch->handle($supportedProperties, function($mutations) use ($calendarId) {
+            $newValues = [];
+            foreach($mutations as $propertyName=>$propertyValue) {
 
-        }
+                switch($propertyName) {
+                    case '{' . CalDAV\Plugin::NS_CALDAV . '}schedule-calendar-transp' :
+                        $fieldName = 'transparent';
+                        $newValues[$fieldName] = $propertyValue->getValue()==='transparent';
+                        break;
+                    default :
+                        $fieldName = $this->propertyMap[$propertyName];
+                        $newValues[$fieldName] = $propertyValue;
+                        break;
+                }
 
-        // If there were any errors we need to fail the request
-        if ($hasError) {
-            // Properties has the remaining properties
-            foreach($mutations as $propertyName=>$propertyValue) {
-                $result[424][$propertyName] = null;
             }
-
-            // Removing unused statuscodes for cleanliness
-            foreach($result as $status=>$properties) {
-                if (is_array($properties) && count($properties)===0) unset($result[$status]);
+            $valuesSql = [];
+            foreach($newValues as $fieldName=>$value) {
+                $valuesSql[] = $fieldName . ' = ?';
             }
 
-            return $result;
-
-        }
-
-        // Success
+            $stmt = $this->pdo->prepare("UPDATE " . $this->calendarTableName . " SET " . implode(', ',$valuesSql) . " WHERE id = ?");
+            $newValues['id'] = $calendarId;
+            $stmt->execute(array_values($newValues));
 
-        // Now we're generating the sql query.
-        $valuesSql = [];
-        foreach($newValues as $fieldName=>$value) {
-            $valuesSql[] = $fieldName . ' = ?';
-        }
-
-        $stmt = $this->pdo->prepare("UPDATE " . $this->calendarTableName . " SET " . implode(', ',$valuesSql) . " WHERE id = ?");
-        $newValues['id'] = $calendarId;
-        $stmt->execute(array_values($newValues));
+            $this->addChange($calendarId, "", 2);
 
-        $this->addChange($calendarId, "", 2);
+            return true;
 
-        return true;
+        });
 
     }
 
@@ -1049,100 +999,53 @@ class PDO extends AbstractBackend implements SyncSupport, SubscriptionSupport {
     /**
      * Updates a subscription
      *
-     * The mutations array uses the propertyName in clark-notation as key,
-     * and the array value for the property value. In the case a property
-     * should be deleted, the property value will be null.
-     *
-     * This method must be atomic. If one property cannot be changed, the
-     * entire operation must fail.
-     *
-     * If the operation was successful, you can just return true.
-     * If the operation failed, you may just return false.
-     *
-     * Deletion of a non-existent property is always successful.
-     *
-     * Lastly, it is optional to return detailed information about any
-     * failures. In this case an array should be returned with the following
-     * structure:
+     * The list of mutations is stored in a Sabre\DAV\PropPatch object.
+     * To do the actual updates, you must tell this object which properties
+     * you're going to process with the handle() method.
      *
-     * array(
-     *   403 => array(
-     *      '{DAV:}displayname' => null,
-     *   ),
-     *   424 => array(
-     *      '{DAV:}owner' => null,
-     *   )
-     * )
+     * Calling the handle method is like telling the PropPatch object "I
+     * promise I can handle updating this property".
      *
-     * In this example it was forbidden to update {DAV:}displayname.
-     * (403 Forbidden), which in turn also caused {DAV:}owner to fail
-     * (424 Failed Dependency) because the request needs to be atomic.
+     * Read the PropPatch documenation for more info and examples.
      *
      * @param mixed $subscriptionId
-     * @param array $mutations
-     * @return bool|array
+     * @param \Sabre\DAV\PropPatch $propPatch
+     * @return void
      */
-    public function updateSubscription($subscriptionId, array $mutations) {
+    public function updateSubscription($subscriptionId, DAV\PropPatch $propPatch) {
 
-        $newValues = [];
-        $result = [
-            200 => [], // Ok
-            403 => [], // Forbidden
-            424 => [], // Failed Dependency
-        ];
+        $supportedProperties = array_keys($this->subscriptionPropertyMap);
+        $supportedProperties[] = '{http://calendarserver.org/ns/}source';
+        
+        $propPatch->handle($supportedProperties, function($mutations) use ($subscriptionId) {
 
-        $hasError = false;
+            $newValues = [];
 
-        foreach($mutations as $propertyName=>$propertyValue) {
+            foreach($mutations as $propertyName=>$propertyValue) {
 
-            if ($propertyName === '{http://calendarserver.org/ns/}source') {
-                $newValues['source'] = $propertyValue->getHref();
-            } else {
-                // Checking the property map
-                if (!isset($this->subscriptionPropertyMap[$propertyName])) {
-                    // We don't know about this property.
-                    $hasError = true;
-                    $result[403][$propertyName] = null;
-                    unset($mutations[$propertyName]);
-                    continue;
+                if ($propertyName === '{http://calendarserver.org/ns/}source') {
+                    $newValues['source'] = $propertyValue->getHref();
+                } else {
+                    $fieldName = $this->subscriptionPropertyMap[$propertyName];
+                    $newValues[$fieldName] = $propertyValue;
                 }
 
-                $fieldName = $this->subscriptionPropertyMap[$propertyName];
-                $newValues[$fieldName] = $propertyValue;
-            }
-
-        }
-
-        // If there were any errors we need to fail the request
-        if ($hasError) {
-            // Properties has the remaining properties
-            foreach($mutations as $propertyName=>$propertyValue) {
-                $result[424][$propertyName] = null;
             }
 
-            // Removing unused statuscodes for cleanliness
-            foreach($result as $status=>$properties) {
-                if (is_array($properties) && count($properties)===0) unset($result[$status]);
+            // Now we're generating the sql query.
+            $valuesSql = [];
+            foreach($newValues as $fieldName=>$value) {
+                $valuesSql[] = $fieldName . ' = ?';
             }
 
-            return $result;
-
-        }
-
-        // Success
-
-        // Now we're generating the sql query.
-        $valuesSql = [];
-        foreach($newValues as $fieldName=>$value) {
-            $valuesSql[] = $fieldName . ' = ?';
-        }
+            $stmt = $this->pdo->prepare("UPDATE " . $this->calendarSubscriptionsTableName . " SET " . implode(', ',$valuesSql) . ", lastmodified = ? WHERE id = ?");
+            $newValues['lastmodified'] = time();
+            $newValues['id'] = $subscriptionId;
+            $stmt->execute(array_values($newValues));
 
-        $stmt = $this->pdo->prepare("UPDATE " . $this->calendarSubscriptionsTableName . " SET " . implode(', ',$valuesSql) . ", lastmodified = ? WHERE id = ?");
-        $newValues['lastmodified'] = time();
-        $newValues['id'] = $subscriptionId;
-        $stmt->execute(array_values($newValues));
+            return true;
 
-        return true;
+        });
 
     }
 
diff --git a/lib/Sabre/CalDAV/Backend/SubscriptionSupport.php b/lib/Sabre/CalDAV/Backend/SubscriptionSupport.php
index 0d24487..c458ab4 100644
--- a/lib/Sabre/CalDAV/Backend/SubscriptionSupport.php
+++ b/lib/Sabre/CalDAV/Backend/SubscriptionSupport.php
@@ -2,6 +2,8 @@
 
 namespace Sabre\CalDAV\Backend;
 
+use Sabre\DAV;
+
 /**
  * Every CalDAV backend must at least implement this interface.
  *
@@ -59,42 +61,22 @@ interface SubscriptionSupport extends BackendInterface {
     public function createSubscription($principalUri, $uri, array $properties);
 
     /**
-     * Updates a subscription.
-     *
-     * The mutations array uses the propertyName in clark-notation as key,
-     * and the array value for the property value. In the case a property
-     * should be deleted, the property value will be null.
-     *
-     * This method must be atomic. If one property cannot be changed, the
-     * entire operation must fail.
+     * Updates a subscription
      *
-     * If the operation was successful, true can be returned.
-     * If the operation failed, false can be returned.
+     * The list of mutations is stored in a Sabre\DAV\PropPatch object.
+     * To do the actual updates, you must tell this object which properties
+     * you're going to process with the handle() method.
      *
-     * Deletion of a non-existent property is always successful.
+     * Calling the handle method is like telling the PropPatch object "I
+     * promise I can handle updating this property".
      *
-     * Lastly, it is optional to return detailed information about any
-     * failures. In this case an array should be returned with the following
-     * structure:
-     *
-     * array(
-     *   403 => array(
-     *      '{DAV:}displayname' => null,
-     *   ),
-     *   424 => array(
-     *      '{DAV:}owner' => null,
-     *   )
-     * )
-     *
-     * In this example it was forbidden to update {DAV:}displayname.
-     * (403 Forbidden), which in turn also caused {DAV:}owner to fail
-     * (424 Failed Dependency) because the request needs to be atomic.
+     * Read the PropPatch documenation for more info and examples.
      *
      * @param mixed $subscriptionId
-     * @param array $mutations
-     * @return bool|array
+     * @param \Sabre\DAV\PropPatch $propPatch
+     * @return void
      */
-    public function updateSubscription($subscriptionId, array $mutations);
+    public function updateSubscription($subscriptionId, DAV\PropPatch $propPatch);
 
     /**
      * Deletes a subscription.
diff --git a/lib/Sabre/CalDAV/Calendar.php b/lib/Sabre/CalDAV/Calendar.php
index 1fae32b..db8a635 100644
--- a/lib/Sabre/CalDAV/Calendar.php
+++ b/lib/Sabre/CalDAV/Calendar.php
@@ -4,7 +4,8 @@ namespace Sabre\CalDAV;
 
 use
     Sabre\DAV,
-    Sabre\DAVACL;
+    Sabre\DAVACL,
+    Sabre\DAV\PropPatch;
 
 /**
  * This object represents a CalDAV calendar.
@@ -57,14 +58,20 @@ class Calendar implements ICalendar, DAV\IProperties, DAVACL\IACL, DAV\Sync\ISyn
     }
 
     /**
-     * Updates properties such as the display name and description
+     * Updates properties on this node.
      *
-     * @param array $mutations
-     * @return array
+     * This method received a PropPatch object, which contains all the
+     * information about the update.
+     *
+     * To update specific properties, call the 'handle' method on this object.
+     * Read the PropPatch documentation for more information.
+     *
+     * @param PropPatch $propPatch
+     * @return void
      */
-    public function updateProperties($mutations) {
+    public function propPatch(PropPatch $propPatch) {
 
-        return $this->caldavBackend->updateCalendar($this->calendarInfo['id'],$mutations);
+        return $this->caldavBackend->updateCalendar($this->calendarInfo['id'], $propPatch);
 
     }
 
diff --git a/lib/Sabre/CalDAV/SharingPlugin.php b/lib/Sabre/CalDAV/SharingPlugin.php
index cb8c89a..42d494a 100644
--- a/lib/Sabre/CalDAV/SharingPlugin.php
+++ b/lib/Sabre/CalDAV/SharingPlugin.php
@@ -94,7 +94,7 @@ class SharingPlugin extends DAV\ServerPlugin {
 
         $this->server->on('beforeGetProperties', [$this, 'beforeGetProperties']);
         $this->server->on('afterGetProperties',  [$this, 'afterGetProperties']);
-        $this->server->on('updateProperties',    [$this, 'updateProperties']);
+        $this->server->on('propPatch',           [$this, 'propPatch'], 40);
         $this->server->on('method:POST',         [$this, 'httpPost']);
 
     }
@@ -221,35 +221,28 @@ class SharingPlugin extends DAV\ServerPlugin {
      * Even though this is no longer in the current spec, we keep this around
      * because OS X 10.7 may still make use of this feature.
      *
-     * @param array $mutations
-     * @param array $result
-     * @param DAV\INode $node
+     * @param string $path
+     * @param DAV\PropPatch $propPatch
      * @return void
      */
-    public function updateProperties(array &$mutations, array &$result, DAV\INode $node) {
+    public function propPatch($path, DAV\PropPatch $propPatch) {
 
+        $node = $this->server->tree->getNodeForPath($path);
         if (!$node instanceof IShareableCalendar)
             return;
 
-        if (!isset($mutations['{DAV:}resourcetype'])) {
-            return;
-        }
-
-        // Only doing something if shared-owner is indeed not in the list.
-        if($mutations['{DAV:}resourcetype']->is('{' . Plugin::NS_CALENDARSERVER . '}shared-owner')) return;
-
-        $shares = $node->getShares();
-        $remove = array();
-        foreach($shares as $share) {
-            $remove[] = $share['href'];
-        }
-        $node->updateShares(array(), $remove);
+        $propPatch->handle('{DAV:}resourcetype', function($value) use ($node) {
+            if($value->is('{' . Plugin::NS_CALENDARSERVER . '}shared-owner')) return false;
+            $shares = $node->getShares();
+            $remove = array();
+            foreach($shares as $share) {
+                $remove[] = $share['href'];
+            }
+            $node->updateShares(array(), $remove);
 
-        // We're marking this update as 200 OK
-        $result[200]['{DAV:}resourcetype'] = null;
+            return true;
 
-        // Removing it from the mutations list
-        unset($mutations['{DAV:}resourcetype']);
+        });
 
     }
 
diff --git a/lib/Sabre/CalDAV/Subscriptions/Subscription.php b/lib/Sabre/CalDAV/Subscriptions/Subscription.php
index dd3cb0c..aa8a1a4 100644
--- a/lib/Sabre/CalDAV/Subscriptions/Subscription.php
+++ b/lib/Sabre/CalDAV/Subscriptions/Subscription.php
@@ -4,10 +4,13 @@ namespace Sabre\CalDAV\Subscriptions;
 
 use
     Sabre\DAV\Collection,
-    Sabre\CalDAV\Backend\SubscriptionSupport,
     Sabre\DAV\Property\Href,
+    Sabre\DAV\PropPatch,
+    Sabre\DAV\Exception\MethodNotAllowed,
     Sabre\DAVACL\IACL,
-    Sabre\DAV\Exception\MethodNotAllowed;
+    Sabre\CalDAV\Backend\SubscriptionSupport;
+
+
 
 /**
  * Subscription Node
@@ -113,43 +116,20 @@ class Subscription extends Collection implements ISubscription, IACL {
     /**
      * Updates properties on this node.
      *
-     * The properties array uses the propertyName in clark-notation as key,
-     * and the array value for the property value. In the case a property
-     * should be deleted, the property value will be null.
-     *
-     * This method must be atomic. If one property cannot be changed, the
-     * entire operation must fail.
-     *
-     * If the operation was successful, true can be returned.
-     * If the operation failed, false can be returned.
+     * This method received a PropPatch object, which contains all the
+     * information about the update.
      *
-     * Deletion of a non-existent property is always successful.
+     * To update specific properties, call the 'handle' method on this object.
+     * Read the PropPatch documentation for more information.
      *
-     * Lastly, it is optional to return detailed information about any
-     * failures. In this case an array should be returned with the following
-     * structure:
-     *
-     * array(
-     *   403 => array(
-     *      '{DAV:}displayname' => null,
-     *   ),
-     *   424 => array(
-     *      '{DAV:}owner' => null,
-     *   )
-     * )
-     *
-     * In this example it was forbidden to update {DAV:}displayname.
-     * (403 Forbidden), which in turn also caused {DAV:}owner to fail
-     * (424 Failed Dependency) because the request needs to be atomic.
-     *
-     * @param array $mutations
-     * @return bool|array
+     * @param PropPatch $propPatch
+     * @return void
      */
-    public function updateProperties($mutations) {
+    public function propPatch(PropPatch $propPatch) {
 
         return $this->caldavBackend->updateSubscription(
             $this->subscriptionInfo['id'],
-            $mutations
+            $propPatch
         );
 
     }
diff --git a/lib/Sabre/CardDAV/AddressBook.php b/lib/Sabre/CardDAV/AddressBook.php
index ce7f32e..2b97300 100644
--- a/lib/Sabre/CardDAV/AddressBook.php
+++ b/lib/Sabre/CardDAV/AddressBook.php
@@ -2,9 +2,8 @@
 
 namespace Sabre\CardDAV;
 
-use
-    Sabre\DAV,
-    Sabre\DAVACL;
+use Sabre\DAV;
+use Sabre\DAVACL;
 
 /**
  * The AddressBook class represents a CardDAV addressbook, owned by a specific user
@@ -178,43 +177,20 @@ class AddressBook extends DAV\Collection implements IAddressBook, DAV\IPropertie
     }
 
     /**
-     * Updates properties on this node,
+     * Updates properties on this node.
      *
-     * The properties array uses the propertyName in clark-notation as key,
-     * and the array value for the property value. In the case a property
-     * should be deleted, the property value will be null.
+     * This method received a PropPatch object, which contains all the
+     * information about the update.
      *
-     * This method must be atomic. If one property cannot be changed, the
-     * entire operation must fail.
+     * To update specific properties, call the 'handle' method on this object.
+     * Read the PropPatch documentation for more information.
      *
-     * If the operation was successful, true can be returned.
-     * If the operation failed, false can be returned.
-     *
-     * Deletion of a non-existent property is always successful.
-     *
-     * Lastly, it is optional to return detailed information about any
-     * failures. In this case an array should be returned with the following
-     * structure:
-     *
-     * [
-     *   403 => [
-     *      '{DAV:}displayname' => null,
-     *   ],
-     *   424 => [
-     *      '{DAV:}owner' => null,
-     *   ]
-     * ]
-     *
-     * In this example it was forbidden to update {DAV:}displayname.
-     * (403 Forbidden), which in turn also caused {DAV:}owner to fail
-     * (424 Failed Dependency) because the request needs to be atomic.
-     *
-     * @param array $mutations
-     * @return bool|array
+     * @param DAV\PropPatch $propPatch
+     * @return void
      */
-    public function updateProperties($mutations) {
+    public function propPatch(DAV\PropPatch $propPatch) {
 
-        return $this->carddavBackend->updateAddressBook($this->addressBookInfo['id'], $mutations);
+        return $this->carddavBackend->updateAddressBook($this->addressBookInfo['id'], $propPatch);
 
     }
 
diff --git a/lib/Sabre/CardDAV/Backend/BackendInterface.php b/lib/Sabre/CardDAV/Backend/BackendInterface.php
index a1b55ce..a0998e5 100644
--- a/lib/Sabre/CardDAV/Backend/BackendInterface.php
+++ b/lib/Sabre/CardDAV/Backend/BackendInterface.php
@@ -37,17 +37,22 @@ interface BackendInterface {
     public function getAddressBooksForUser($principalUri);
 
     /**
-     * Updates an addressbook's properties
+     * Updates properties for an address book.
      *
-     * See Sabre\DAV\IProperties for a description of the mutations array, as
-     * well as the return value.
+     * The list of mutations is stored in a Sabre\DAV\PropPatch object.
+     * To do the actual updates, you must tell this object which properties
+     * you're going to process with the handle() method.
      *
-     * @param mixed $addressBookId
-     * @param array $mutations
-     * @see Sabre\DAV\IProperties::updateProperties
-     * @return bool|array
+     * Calling the handle method is like telling the PropPatch object "I
+     * promise I can handle updating this property".
+     *
+     * Read the PropPatch documenation for more info and examples.
+     *
+     * @param string $addressBookId
+     * @param \Sabre\DAV\PropPatch $propPatch
+     * @return void
      */
-    public function updateAddressBook($addressBookId, array $mutations);
+    public function updateAddressBook($addressBookId, \Sabre\DAV\PropPatch $propPatch);
 
     /**
      * Creates a new address book
diff --git a/lib/Sabre/CardDAV/Backend/PDO.php b/lib/Sabre/CardDAV/Backend/PDO.php
index b3531a4..b3ad22f 100644
--- a/lib/Sabre/CardDAV/Backend/PDO.php
+++ b/lib/Sabre/CardDAV/Backend/PDO.php
@@ -91,62 +91,64 @@ class PDO extends AbstractBackend implements SyncSupport {
 
 
     /**
-     * Updates an addressbook's properties
+     * Updates properties for an address book.
      *
-     * See Sabre\DAV\IProperties for a description of the mutations array, as
-     * well as the return value.
+     * The list of mutations is stored in a Sabre\DAV\PropPatch object.
+     * To do the actual updates, you must tell this object which properties
+     * you're going to process with the handle() method.
      *
-     * @param mixed $addressBookId
-     * @param array $mutations
-     * @see Sabre\DAV\IProperties::updateProperties
-     * @return bool|array
+     * Calling the handle method is like telling the PropPatch object "I
+     * promise I can handle updating this property".
+     *
+     * Read the PropPatch documenation for more info and examples.
+     *
+     * @param string $addressBookId
+     * @param \Sabre\DAV\PropPatch $propPatch
+     * @return void
      */
-    public function updateAddressBook($addressBookId, array $mutations) {
-
-        $updates = array();
-
-        foreach($mutations as $property=>$newValue) {
+    public function updateAddressBook($addressBookId, \Sabre\DAV\PropPatch $propPatch) {
 
-            switch($property) {
-                case '{DAV:}displayname' :
-                    $updates['displayname'] = $newValue;
-                    break;
-                case '{' . CardDAV\Plugin::NS_CARDDAV . '}addressbook-description' :
-                    $updates['description'] = $newValue;
-                    break;
-                default :
-                    // If any unsupported values were being updated, we must
-                    // let the entire request fail.
-                    return false;
-            }
+        $supportedProperties = [
+            '{DAV:}displayname',
+            '{' . CardDAV\Plugin::NS_CARDDAV . '}addressbook-description',
+        ];
 
-        }
+        $propPatch->handle($supportedProperties, function($mutations) use ($addressBookId) {
 
-        // No values are being updated?
-        if (!$updates) {
-            return false;
-        }
+            $updates = [];
+            foreach($mutations as $property=>$newValue) {
 
-        $query = 'UPDATE ' . $this->addressBooksTableName . ' SET ';
-        $first = true;
-        foreach($updates as $key=>$value) {
-            if ($first) {
-                $first = false;
-            } else {
-                $query.=', ';
+                switch($property) {
+                    case '{DAV:}displayname' :
+                        $updates['displayname'] = $newValue;
+                        break;
+                    case '{' . CardDAV\Plugin::NS_CARDDAV . '}addressbook-description' :
+                        $updates['description'] = $newValue;
+                        break;
+                }
             }
-            $query.=' `' . $key . '` = :' . $key . ' ';
-        }
-        $query.=' WHERE id = :addressbookid';
+            $query = 'UPDATE ' . $this->addressBooksTableName . ' SET ';
+            $first = true;
+            foreach($updates as $key=>$value) {
+                if ($first) {
+                    $first = false;
+                } else {
+                    $query.=', ';
+                }
+                $query.=' `' . $key . '` = :' . $key . ' ';
+            }
+            $query.=' WHERE id = :addressbookid';
 
-        $stmt = $this->pdo->prepare($query);
-        $updates['addressbookid'] = $addressBookId;
+            $stmt = $this->pdo->prepare($query);
+            $updates['addressbookid'] = $addressBookId;
+
+            $stmt->execute($updates);
 
-        $stmt->execute($updates);
+            $this->addChange($addressBookId, "", 2);
 
-        $this->addChange($addressBookId, "", 2);
+            return true;
 
-        return true;
+        });
 
     }
 
diff --git a/lib/Sabre/CardDAV/Plugin.php b/lib/Sabre/CardDAV/Plugin.php
index 54761d9..e935a2b 100644
--- a/lib/Sabre/CardDAV/Plugin.php
+++ b/lib/Sabre/CardDAV/Plugin.php
@@ -53,7 +53,7 @@ class Plugin extends DAV\ServerPlugin {
         /* Events */
         $server->on('beforeGetProperties', [$this, 'beforeGetProperties']);
         $server->on('afterGetProperties',  [$this, 'afterGetProperties']);
-        $server->on('updateProperties',    [$this, 'updateProperties']);
+        $server->on('propPatch',           [$this, 'propPatch']);
         $server->on('report',              [$this, 'report']);
         $server->on('onHTMLActionsPanel',  [$this, 'htmlActionsPanel']);
         $server->on('onBrowserPostAction', [$this, 'browserPostAction']);
@@ -187,51 +187,38 @@ class Plugin extends DAV\ServerPlugin {
     /**
      * This event is triggered when a PROPPATCH method is executed
      *
-     * @param array $mutations
-     * @param array $result
-     * @param DAV\INode $node
+     * @param string $path
+     * @param DAV\PropPatch $propPatch
      * @return bool
      */
-    public function updateProperties(&$mutations, &$result, DAV\INode $node) {
+    public function propPatch($path, DAV\PropPatch $propPatch) {
 
+        $node = $this->server->tree->getNodeForPath($path);
         if (!$node instanceof UserAddressBooks) {
             return true;
         }
 
         $meCard = '{http://calendarserver.org/ns/}me-card';
 
-        // The only property we care about
-        if (!isset($mutations[$meCard]))
-            return true;
-
-        $value = $mutations[$meCard];
-        unset($mutations[$meCard]);
-
-        if ($value instanceof DAV\Property\IHref) {
-            $value = $value->getHref();
-            $value = $this->server->calculateUri($value);
-        } elseif (!is_null($value)) {
-            $result[400][$meCard] = null;
-            return false;
-        }
+        $propPatch->handle($meCard, function($value) use ($node) {
 
-        $innerResult = $this->server->updateProperties(
-            $node->getOwner(),
-            array(
-                '{http://sabredav.org/ns}vcard-url' => $value,
-            )
-        );
-
-        $closureResult = false;
-        foreach($innerResult as $status => $props) {
-            if (is_array($props) && array_key_exists('{http://sabredav.org/ns}vcard-url', $props)) {
-                $result[$status][$meCard] = null;
-                $closureResult = ($status>=200 && $status<300);
+            if ($value instanceof DAV\Property\IHref) {
+                $value = $value->getHref();
+                $value = $this->server->calculateUri($value);
+            } elseif (!is_null($value)) {
+                return 400;
             }
 
-        }
+            $innerResult = $this->server->updateProperties(
+                $node->getOwner(),
+                array(
+                    '{http://sabredav.org/ns}vcard-url' => $value,
+                )
+            );
+
+            return $innerResult['{http://sabredav.org/ns}vcard-url'];
 
-        return $result;
+        });
 
     }
 
diff --git a/lib/Sabre/DAVACL/PrincipalBackend/BackendInterface.php b/lib/Sabre/DAVACL/PrincipalBackend/BackendInterface.php
index c62b425..c410e1f 100644
--- a/lib/Sabre/DAVACL/PrincipalBackend/BackendInterface.php
+++ b/lib/Sabre/DAVACL/PrincipalBackend/BackendInterface.php
@@ -57,6 +57,7 @@ interface BackendInterface {
      *
      * @param string $path
      * @param \Sabre\DAV\PropPatch $propPatch
+     * @return void
      */
     function updatePrincipal($path, \Sabre\DAV\PropPatch $propPatch);
 
diff --git a/tests/Sabre/CalDAV/Backend/AbstractPDOTest.php b/tests/Sabre/CalDAV/Backend/AbstractPDOTest.php
index 8484840..ac1016a 100644
--- a/tests/Sabre/CalDAV/Backend/AbstractPDOTest.php
+++ b/tests/Sabre/CalDAV/Backend/AbstractPDOTest.php
@@ -1,8 +1,10 @@
 <?php
 
 namespace Sabre\CalDAV\Backend;
+
 use Sabre\CalDAV;
 use Sabre\DAV;
+use Sabre\DAV\PropPatch;
 
 abstract class AbstractPDOTest extends \PHPUnit_Framework_TestCase {
 
@@ -69,14 +71,17 @@ abstract class AbstractPDOTest extends \PHPUnit_Framework_TestCase {
         //Creating a new calendar
         $newId = $backend->createCalendar('principals/user2','somerandomid',array());
 
-        // Updating the calendar
-        $result = $backend->updateCalendar($newId,array(
+        $propPatch = new PropPatch([
             '{DAV:}displayname' => 'myCalendar',
             '{urn:ietf:params:xml:ns:caldav}schedule-calendar-transp' => new CalDAV\Property\ScheduleCalendarTransp('transparent'),
-        ));
+        ]);
+
+        // Updating the calendar
+        $backend->updateCalendar($newId, $propPatch);
+        $result = $propPatch->commit();
 
         // Verifying the result of the update
-        $this->assertEquals(true, $result);
+        $this->assertTrue($result);
 
         // Fetching all calendars from this user
         $calendars = $backend->getCalendarsForUser('principals/user2');
@@ -114,17 +119,20 @@ abstract class AbstractPDOTest extends \PHPUnit_Framework_TestCase {
         //Creating a new calendar
         $newId = $backend->createCalendar('principals/user2','somerandomid',array());
 
-        // Updating the calendar
-        $result = $backend->updateCalendar($newId,array(
+        $propPatch = new PropPatch([
             '{DAV:}displayname' => 'myCalendar',
             '{DAV:}yourmom'     => 'wittycomment',
-        ));
+        ]);
+
+        // Updating the calendar
+        $backend->updateCalendar($newId, $propPatch);
+        $propPatch->commit();
 
         // Verifying the result of the update
-        $this->assertEquals(array(
-            '403' => array('{DAV:}yourmom' => null),
-            '424' => array('{DAV:}displayname' => null),
-        ), $result);
+        $this->assertEquals([
+            '{DAV:}yourmom' => 403,
+            '{DAV:}displayname' => 424,
+        ], $propPatch->getResult());
 
     }
 
@@ -723,7 +731,9 @@ abstract class AbstractPDOTest extends \PHPUnit_Framework_TestCase {
             '{http://calendarserver.org/ns/}source' => new \Sabre\DAV\Property\Href('http://example.org/cal2.ics', false),
         ];
 
-        $result = $backend->updateSubscription(1, $newProps);
+        $propPatch = new DAV\PropPatch($newProps);
+        $backend->updateSubscription(1, $propPatch);
+        $result = $propPatch->commit();
 
         $this->assertTrue($result);
 
@@ -759,23 +769,20 @@ abstract class AbstractPDOTest extends \PHPUnit_Framework_TestCase {
         $backend = new PDO($this->pdo);
         $backend->createSubscription('principals/user1', 'sub1', $props);
 
-        $newProps = [
+        $propPatch = new DAV\PropPatch([
             '{DAV:}displayname' => 'new displayname',
             '{http://calendarserver.org/ns/}source' => new \Sabre\DAV\Property\Href('http://example.org/cal2.ics', false),
             '{DAV:}unknown' => 'foo',
-        ];
+        ]);
 
-        $result = $backend->updateSubscription(1, $newProps);
+        $backend->updateSubscription(1, $propPatch);
+        $propPatch->commit();
 
         $this->assertEquals([
-            403 => [
-                '{DAV:}unknown' => null,
-            ],
-            424 => [
-                '{DAV:}displayname' => null,
-                '{http://calendarserver.org/ns/}source' => null,
-            ],
-        ], $result);
+            '{DAV:}unknown' => 403,
+            '{DAV:}displayname' => 424,
+            '{http://calendarserver.org/ns/}source' => 424,
+        ], $propPatch->getResult());
 
     }
 
diff --git a/tests/Sabre/CalDAV/Backend/AbstractTest.php b/tests/Sabre/CalDAV/Backend/AbstractTest.php
index 04fb16d..a2959f5 100644
--- a/tests/Sabre/CalDAV/Backend/AbstractTest.php
+++ b/tests/Sabre/CalDAV/Backend/AbstractTest.php
@@ -2,12 +2,20 @@
 
 namespace Sabre\CalDAV\Backend;
 
+use
+    Sabre\DAV\PropPatch;
+
 class AbstractTest extends \PHPUnit_Framework_TestCase {
 
     function testUpdateCalendar() {
 
         $abstract = new AbstractMock();
-        $this->assertEquals(false, $abstract->updateCalendar('randomid', array('{DAV:}displayname' => 'anything')));
+        $propPatch = new PropPatch( ['{DAV:}displayname' => 'anything'] );
+
+        $abstract->updateCalendar('randomid', $propPatch);
+        $result = $propPatch->commit();
+
+        $this->assertFalse($result);
 
     }
 
diff --git a/tests/Sabre/CalDAV/Backend/Mock.php b/tests/Sabre/CalDAV/Backend/Mock.php
index b4737b0..4c64c96 100644
--- a/tests/Sabre/CalDAV/Backend/Mock.php
+++ b/tests/Sabre/CalDAV/Backend/Mock.php
@@ -78,48 +78,6 @@ class Mock extends AbstractBackend implements NotificationSupport, SharingSuppor
     }
 
     /**
-     * Updates properties on this node,
-     *
-     * The properties array uses the propertyName in clark-notation as key,
-     * and the array value for the property value. In the case a property
-     * should be deleted, the property value will be null.
-     *
-     * This method must be atomic. If one property cannot be changed, the
-     * entire operation must fail.
-     *
-     * If the operation was successful, true can be returned.
-     * If the operation failed, false can be returned.
-     *
-     * Deletion of a non-existent property is always successful.
-     *
-     * Lastly, it is optional to return detailed information about any
-     * failures. In this case an array should be returned with the following
-     * structure:
-     *
-     * array(
-     *   403 => array(
-     *      '{DAV:}displayname' => null,
-     *   ),
-     *   424 => array(
-     *      '{DAV:}owner' => null,
-     *   )
-     * )
-     *
-     * In this example it was forbidden to update {DAV:}displayname.
-     * (403 Forbidden), which in turn also caused {DAV:}owner to fail
-     * (424 Failed Dependency) because the request needs to be atomic.
-     *
-     * @param string $calendarId
-     * @param array $properties
-     * @return bool|array
-     */
-    public function updateCalendar($calendarId, array $properties) {
-
-        return false;
-
-    }
-
-    /**
      * Delete a calendar and all it's objects
      *
      * @param string $calendarId
diff --git a/tests/Sabre/CalDAV/Backend/MockSubscriptionSupport.php b/tests/Sabre/CalDAV/Backend/MockSubscriptionSupport.php
index a85e52a..b8b508d 100644
--- a/tests/Sabre/CalDAV/Backend/MockSubscriptionSupport.php
+++ b/tests/Sabre/CalDAV/Backend/MockSubscriptionSupport.php
@@ -95,40 +95,20 @@ class MockSubscriptionSupport extends Mock implements SubscriptionSupport {
     /**
      * Updates a subscription
      *
-     * The mutations array uses the propertyName in clark-notation as key,
-     * and the array value for the property value. In the case a property
-     * should be deleted, the property value will be null.
+     * The list of mutations is stored in a Sabre\DAV\PropPatch object.
+     * To do the actual updates, you must tell this object which properties
+     * you're going to process with the handle() method.
      *
-     * This method must be atomic. If one property cannot be changed, the
-     * entire operation must fail.
+     * Calling the handle method is like telling the PropPatch object "I
+     * promise I can handle updating this property".
      *
-     * If the operation was successful, true can be returned.
-     * If the operation failed, false can be returned.
-     *
-     * Deletion of a non-existent property is always successful.
-     *
-     * Lastly, it is optional to return detailed information about any
-     * failures. In this case an array should be returned with the following
-     * structure:
-     *
-     * array(
-     *   403 => array(
-     *      '{DAV:}displayname' => null,
-     *   ),
-     *   424 => array(
-     *      '{DAV:}owner' => null,
-     *   )
-     * )
-     *
-     * In this example it was forbidden to update {DAV:}displayname.
-     * (403 Forbidden), which in turn also caused {DAV:}owner to fail
-     * (424 Failed Dependency) because the request needs to be atomic.
+     * Read the PropPatch documenation for more info and examples.
      *
      * @param mixed $subscriptionId
-     * @param array $mutations
-     * @return bool|array
+     * @param \Sabre\DAV\PropPatch $propPatch
+     * @return void
      */
-    public function updateSubscription($subscriptionId, array $mutations) {
+    public function updateSubscription($subscriptionId, DAV\PropPatch $propPatch) {
 
         $found = null;
         foreach($this->subs[$subscriptionId[0]] as &$sub) {
@@ -140,13 +120,14 @@ class MockSubscriptionSupport extends Mock implements SubscriptionSupport {
 
         }
 
-        if (!$found) return false;
-
-        foreach($mutations as $k=>$v) {
-            $found[$k] = $v;
-        }
+        if (!$found) return;
 
-        return true;
+        $propPatch->handleRemaining(function($mutations) use (&$found) {
+            foreach($mutations as $k=>$v) {
+                $found[$k] = $v;
+            }
+            return true;
+        });
 
     }
 
diff --git a/tests/Sabre/CalDAV/CalendarTest.php b/tests/Sabre/CalDAV/CalendarTest.php
index 5cb6ea1..a5f3e3d 100644
--- a/tests/Sabre/CalDAV/CalendarTest.php
+++ b/tests/Sabre/CalDAV/CalendarTest.php
@@ -1,6 +1,8 @@
 <?php
 
 namespace Sabre\CalDAV;
+
+use Sabre\DAV\PropPatch;
 use Sabre\DAVACL;
 
 require_once 'Sabre/CalDAV/TestUtil.php';
@@ -51,9 +53,12 @@ class CalendarTest extends \PHPUnit_Framework_TestCase {
      */
     function testUpdateProperties() {
 
-        $result = $this->calendar->updateProperties(array(
+        $propPatch = new PropPatch([
             '{DAV:}displayname' => 'NewName',
-        ));
+        ]);
+
+        $result = $this->calendar->propPatch($propPatch);
+        $result = $propPatch->commit();
 
         $this->assertEquals(true, $result);
 
diff --git a/tests/Sabre/CalDAV/SharingPluginTest.php b/tests/Sabre/CalDAV/SharingPluginTest.php
index 5d59759..b6f2f8e 100644
--- a/tests/Sabre/CalDAV/SharingPluginTest.php
+++ b/tests/Sabre/CalDAV/SharingPluginTest.php
@@ -33,7 +33,7 @@ class SharingPluginTest extends \Sabre\DAVServerTest {
                 'id' => 3,
                 'uri' => 'cal3',
             ),
-        ); 
+        );
 
         parent::setUp();
 
@@ -96,10 +96,7 @@ class SharingPluginTest extends \Sabre\DAVServerTest {
         ));
 
         $this->assertEquals(array(
-            200 => array(
-                '{DAV:}resourcetype' => null,
-            ),
-            'href' => 'calendars/user1/cal1',
+            '{DAV:}resourcetype' => 200
         ), $result);
 
         $this->assertEquals(0, count($this->caldavBackend->getShares(1)));
@@ -113,10 +110,7 @@ class SharingPluginTest extends \Sabre\DAVServerTest {
         ));
 
         $this->assertEquals(array(
-            403 => array(
-                '{DAV:}foo' => null,
-            ),
-            'href' => 'calendars/user1/cal3',
+            '{DAV:}foo' => 403,
         ), $result);
 
     }
diff --git a/tests/Sabre/CalDAV/Subscriptions/SubscriptionTest.php b/tests/Sabre/CalDAV/Subscriptions/SubscriptionTest.php
index 18b8b69..2cbd912 100644
--- a/tests/Sabre/CalDAV/Subscriptions/SubscriptionTest.php
+++ b/tests/Sabre/CalDAV/Subscriptions/SubscriptionTest.php
@@ -3,6 +3,7 @@
 namespace Sabre\CalDAV\Subscriptions;
 
 use Sabre\DAV\Property\Href;
+use Sabre\DAV\PropPatch;
 
 class SubscriptionTest extends \PHPUnit_Framework_TestCase {
 
@@ -114,9 +115,11 @@ class SubscriptionTest extends \PHPUnit_Framework_TestCase {
     function testUpdateProperties() {
 
         $sub = $this->getSub();
-        $this->assertTrue($sub->updateProperties([
+        $propPatch = new PropPatch([
             '{DAV:}displayname' => 'foo',
-        ]));
+        ]);
+        $sub->propPatch($propPatch);
+        $this->assertTrue($propPatch->commit());
 
         $this->assertEquals(
             'foo',
diff --git a/tests/Sabre/CalDAV/UserCalendarsSharedCalendarsTest.php b/tests/Sabre/CalDAV/UserCalendarsSharedCalendarsTest.php
index 1f20be4..69e3a88 100644
--- a/tests/Sabre/CalDAV/UserCalendarsSharedCalendarsTest.php
+++ b/tests/Sabre/CalDAV/UserCalendarsSharedCalendarsTest.php
@@ -7,7 +7,6 @@ use Sabre\DAVACL;
 require_once 'Sabre/CalDAV/TestUtil.php';
 
 /**
- * @covers Sabre\CalDAV\UserCalendars
  */
 class UserCalendarsSharedCalendarsTest extends \PHPUnit_Framework_TestCase {
 
diff --git a/tests/Sabre/CalDAV/UserCalendarsTest.php b/tests/Sabre/CalDAV/UserCalendarsTest.php
index 453c872..4e16566 100644
--- a/tests/Sabre/CalDAV/UserCalendarsTest.php
+++ b/tests/Sabre/CalDAV/UserCalendarsTest.php
@@ -7,7 +7,6 @@ use Sabre\DAV;
 require_once 'Sabre/CalDAV/TestUtil.php';
 
 /**
- * @covers Sabre\CalDAV\UserCalendars
  */
 class UserCalendarsTest extends \PHPUnit_Framework_TestCase {
 
diff --git a/tests/Sabre/CardDAV/AddressBookTest.php b/tests/Sabre/CardDAV/AddressBookTest.php
index 0cb291c..eb6808a 100644
--- a/tests/Sabre/CardDAV/AddressBookTest.php
+++ b/tests/Sabre/CardDAV/AddressBookTest.php
@@ -2,6 +2,7 @@
 
 namespace Sabre\CardDAV;
 
+use Sabre\DAV\PropPatch;
 
 require_once 'Sabre/CardDAV/Backend/Mock.php';
 
@@ -105,9 +106,11 @@ class AddressBookTest extends \PHPUnit_Framework_TestCase {
 
     function testUpdateProperties() {
 
-        $this->assertTrue(
-            $this->ab->updateProperties(array('{DAV:}displayname' => 'barrr'))
-        );
+        $propPatch = new PropPatch([
+            '{DAV:}displayname' => 'barrr',
+        ]);
+        $this->ab->propPatch($propPatch);
+        $this->assertTrue($propPatch->commit());
 
         $this->assertEquals('barrr', $this->backend->addressBooks[0]['{DAV:}displayname']);
 
diff --git a/tests/Sabre/CardDAV/Backend/AbstractPDOTest.php b/tests/Sabre/CardDAV/Backend/AbstractPDOTest.php
index 3dcb12e..afd9e04 100644
--- a/tests/Sabre/CardDAV/Backend/AbstractPDOTest.php
+++ b/tests/Sabre/CardDAV/Backend/AbstractPDOTest.php
@@ -3,6 +3,7 @@
 namespace Sabre\CardDAV\Backend;
 
 use Sabre\CardDAV;
+use Sabre\DAV\PropPatch;
 
 abstract class AbstractPDOTest extends \PHPUnit_Framework_TestCase {
 
@@ -49,11 +50,14 @@ abstract class AbstractPDOTest extends \PHPUnit_Framework_TestCase {
 
     public function testUpdateAddressBookInvalidProp() {
 
-        $result = $this->backend->updateAddressBook(1, array(
+        $propPatch = new PropPatch([
             '{DAV:}displayname' => 'updated',
             '{' . CardDAV\Plugin::NS_CARDDAV . '}addressbook-description' => 'updated',
             '{DAV:}foo' => 'bar',
-        ));
+        ]);
+
+        $this->backend->updateAddressBook(1, $propPatch);
+        $result = $propPatch->commit();
 
         $this->assertFalse($result);
 
@@ -78,9 +82,12 @@ abstract class AbstractPDOTest extends \PHPUnit_Framework_TestCase {
 
     public function testUpdateAddressBookNoProps() {
 
-        $result = $this->backend->updateAddressBook(1, array());
+        $propPatch = new PropPatch([
+        ]);
 
-        $this->assertFalse($result);
+        $this->backend->updateAddressBook(1, $propPatch);
+        $result = $propPatch->commit();
+        $this->assertTrue($result);
 
         $result = $this->backend->getAddressBooksForUser('principals/user1');
 
@@ -104,10 +111,13 @@ abstract class AbstractPDOTest extends \PHPUnit_Framework_TestCase {
 
     public function testUpdateAddressBookSuccess() {
 
-        $result = $this->backend->updateAddressBook(1, array(
+        $propPatch = new PropPatch([
             '{DAV:}displayname' => 'updated',
             '{' . CardDAV\Plugin::NS_CARDDAV . '}addressbook-description' => 'updated',
-        ));
+        ]);
+
+        $this->backend->updateAddressBook(1, $propPatch);
+        $result = $propPatch->commit();
 
         $this->assertTrue($result);
 
diff --git a/tests/Sabre/CardDAV/Backend/Mock.php b/tests/Sabre/CardDAV/Backend/Mock.php
index ab7ac4e..3f96d3c 100644
--- a/tests/Sabre/CardDAV/Backend/Mock.php
+++ b/tests/Sabre/CardDAV/Backend/Mock.php
@@ -48,18 +48,36 @@ class Mock extends AbstractBackend {
 
     }
 
-    function updateAddressBook($addressBookId, array $mutations) {
+    /**
+     * Updates properties for an address book.
+     *
+     * The list of mutations is stored in a Sabre\DAV\PropPatch object.
+     * To do the actual updates, you must tell this object which properties
+     * you're going to process with the handle() method.
+     *
+     * Calling the handle method is like telling the PropPatch object "I
+     * promise I can handle updating this property".
+     *
+     * Read the PropPatch documenation for more info and examples.
+     *
+     * @param string $addressBookId
+     * @param \Sabre\DAV\PropPatch $propPatch
+     * @return void
+     */
+    public function updateAddressBook($addressBookId, \Sabre\DAV\PropPatch $propPatch) {
 
         foreach($this->addressBooks as &$book) {
             if ($book['id'] !== $addressBookId)
                 continue;
 
-            foreach($mutations as $key=>$value) {
-                $book[$key] = $value;
-            }
-            return true;
+            $propPatch->handleRemaining(function($mutations) use (&$book) {
+                foreach($mutations as $key=>$value) {
+                    $book[$key] = $value;
+                }
+                return true;
+            });
+
         }
-        return false;
 
     }
 
diff --git a/tests/Sabre/CardDAV/PluginTest.php b/tests/Sabre/CardDAV/PluginTest.php
index aa5b41a..e7f61af 100644
--- a/tests/Sabre/CardDAV/PluginTest.php
+++ b/tests/Sabre/CardDAV/PluginTest.php
@@ -119,10 +119,7 @@ class PluginTest extends AbstractPluginTest {
 
         $this->assertEquals(
             array(
-                'href' => 'addressbooks/user1',
-                200 => array(
-                    '{http://calendarserver.org/ns/}me-card' => null,
-                ),
+                '{http://calendarserver.org/ns/}me-card' => 200,
             ),
             $result
         );
@@ -137,10 +134,7 @@ class PluginTest extends AbstractPluginTest {
 
         $this->assertEquals(
             array(
-                'href' => 'addressbooks/user1',
-                400 => array(
-                    '{http://calendarserver.org/ns/}me-card' => null,
-                ),
+                '{http://calendarserver.org/ns/}me-card' => 400,
             ),
             $result
         );
diff --git a/tests/Sabre/DAV/ServerPropsTest.php b/tests/Sabre/DAV/ServerPropsTest.php
index 06ff724..a09dc57 100644
--- a/tests/Sabre/DAV/ServerPropsTest.php
+++ b/tests/Sabre/DAV/ServerPropsTest.php
@@ -225,7 +225,7 @@ class ServerPropsTest extends AbstractServer {
 
     public function testUpdatePropertiesFail1() {
 
-        $dir = new Mock\PropertiesCollection([]);
+        $dir = new Mock\PropertiesCollection('root', []);
         $dir->failMode = 'updatepropsfalse';
 
         $objectTree = new ObjectTree($dir);
@@ -248,7 +248,7 @@ class ServerPropsTest extends AbstractServer {
      */
     public function testUpdatePropertiesFail2() {
 
-        $dir = new Mock\PropertiesCollection([]);
+        $dir = new Mock\PropertiesCollection('root', []);
         $dir->failMode = 'updatepropsarray';
 
         $objectTree = new ObjectTree($dir);
@@ -272,7 +272,7 @@ class ServerPropsTest extends AbstractServer {
      */
     public function testUpdatePropertiesFail3() {
 
-        $dir = new Mock\PropertiesCollection([]);
+        $dir = new Mock\PropertiesCollection('root', []);
         $dir->failMode = 'updatepropsobj';
 
         $objectTree = new ObjectTree($dir);

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-owncloud/php-sabredav.git



More information about the Pkg-owncloud-commits mailing list