[Pkg-owncloud-commits] [php-sabredav] 36/163: Refactoring the property-updating system. Work in progress.

David Prévot taffit at moszumanska.debian.org
Tue May 20 18:54:51 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 7a1a7fdb755096f0b7445f8a41ead1fbfa7cc716
Author: Evert Pot <evert at rooftopsolutions.nl>
Date:   Fri Apr 4 23:24:47 2014 -0400

    Refactoring the property-updating system. Work in progress.
---
 .gitignore                                       |  35 ++-
 lib/Sabre/DAV/CorePlugin.php                     |  64 ++++-
 lib/Sabre/DAV/FSExt/Node.php                     |  41 +--
 lib/Sabre/DAV/IProperties.php                    |  37 +--
 lib/Sabre/DAV/PropPatch.php                      | 342 +++++++++++++++++++++++
 lib/Sabre/DAV/Server.php                         |  41 ++-
 lib/Sabre/DAV/Tree.php                           |   6 +-
 tests/Sabre/DAV/FSExt/NodeTest.php               |  35 ++-
 tests/Sabre/DAV/HTTPPreferParsingTest.php        |   9 +-
 tests/Sabre/DAV/Mock/PropertiesNode.php          |  56 ++++
 tests/Sabre/DAV/PropPatchTest.php                | 127 +++++++++
 tests/Sabre/DAV/ServerPropsInfiniteDepthTest.php |  45 +--
 tests/Sabre/DAV/ServerPropsTest.php              |  32 ---
 tests/Sabre/DAV/TreeTest.php                     |  20 +-
 14 files changed, 730 insertions(+), 160 deletions(-)

diff --git a/.gitignore b/.gitignore
index 5514165..a0b83ed 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,23 +1,34 @@
-docs/api
-docs/wikidocs
-build.properties
-build
-public
-data
-fileserver.php
-fileserver2.php
-calendarserver.php
-groupwareserver.php
-package.xml
-tmpdata
+# Unit tests
 tests/temp
 tests/.sabredav
+tests/cov
+
+# ViM
 *.swp
+
+# Composer
 composer.lock
 vendor
 
+# Composer binaries
 bin/phing
 bin/phpunit
 bin/vobject
 bin/phpdocmd
 bin/phpunit
+
+# Various debugging/testing stuff
+fileserver.php
+fileserver2.php
+calendarserver.php
+groupwareserver.php
+tmpdata
+public
+
+# Build
+build
+build.properties
+
+# Docs
+docs/api
+docs/wikidocs
diff --git a/lib/Sabre/DAV/CorePlugin.php b/lib/Sabre/DAV/CorePlugin.php
index 4bef056..1d47c3b 100644
--- a/lib/Sabre/DAV/CorePlugin.php
+++ b/lib/Sabre/DAV/CorePlugin.php
@@ -43,6 +43,9 @@ class CorePlugin extends ServerPlugin {
         $server->on('method:COPY',      [$this, 'httpCopy']);
         $server->on('method:REPORT',    [$this, 'httpReport']);
 
+        $server->on('propPatch', [$this, 'propPatchProtectedPropertyCheck'], 100);
+        $server->on('propPatch', [$this, 'propPatchNodeUpdate'], 200);
+
     }
 
     /**
@@ -377,7 +380,7 @@ class CorePlugin extends ServerPlugin {
             // request was succesful, and don't need to return the
             // multi-status.
             $ok = true;
-            foreach($result as $code=>$prop) {
+            foreach($result as $prop=>$code) {
                 if ((int)$code > 299) {
                     $ok = false;
                 }
@@ -395,8 +398,20 @@ class CorePlugin extends ServerPlugin {
         $response->setStatus(207);
         $response->setHeader('Content-Type','application/xml; charset=utf-8');
 
+
+        // Reorganizing the result for generateMultiStatus
+        $multiStatus = [];
+        foreach($result as $propertyName => $code) {
+            if (isset($multiStatus[$code])) {
+                $multiStatus[$code][$propertyName] = null;
+            } else {
+                $multiStatus[$code] = [$propertyName => null];
+            }
+        }
+        $multiStatus['href'] = $path;
+
         $response->setBody(
-            $this->server->generateMultiStatus([$result])
+            $this->server->generateMultiStatus([$multiStatus])
         );
 
         // Sending back false will interupt the event chain and tell the server
@@ -713,4 +728,49 @@ class CorePlugin extends ServerPlugin {
 
     }
 
+    /**
+     * This method is called during property updates.
+     *
+     * Here we check if a user attempted to update a protected property and
+     * ensure that the process fails if this is the case.
+     *
+     * @param PropPatch $propPatch
+     * @return void
+     */
+    public function propPatchProtectedPropertyCheck($path, PropPatch $propPatch) {
+
+        // Comparing the mutation list to the list of propetected properties.
+        $mutations = $propPatch->getMutations();
+
+        $protected = array_intersect(
+            $this->server->protectedProperties,
+            array_keys($mutations)
+        );
+
+        if ($protected) {
+            $propPatch->setRemainingResultCode($protected, 403);
+        }
+
+    }
+
+    /**
+     * This method is called during property updates.
+     *
+     * Here we check if a node implements IProperties and let the node handle
+     * updating of (some) properties.
+     *
+     * @param PropPatch $propPatch
+     * @return void
+     */
+    public function propPatchNodeUpdate($path, PropPatch $propPatch) {
+
+        // This should trigger a 404 if the node doesn't exist.
+        $node = $this->server->tree->getNodeForPath($path);
+
+        if ($node instanceof IProperties) {
+            $node->propPatch($propPatch);
+        }
+
+    }
+
 }
diff --git a/lib/Sabre/DAV/FSExt/Node.php b/lib/Sabre/DAV/FSExt/Node.php
index 906eda6..e736ae0 100644
--- a/lib/Sabre/DAV/FSExt/Node.php
+++ b/lib/Sabre/DAV/FSExt/Node.php
@@ -4,7 +4,8 @@ namespace Sabre\DAV\FSExt;
 
 use
     Sabre\DAV,
-    Sabre\HTTP\URLUtil;
+    Sabre\HTTP\URLUtil,
+    Sabre\DAV\PropPatch;
 
 /**
  * Base node-class
@@ -18,31 +19,39 @@ use
 abstract class Node extends DAV\FS\Node implements DAV\IProperties {
 
     /**
-     * Updates properties on this node,
+     * Updates properties on this node.
      *
-     * @param array $properties
-     * @see Sabre\DAV\IProperties::updateProperties
+     * 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 array $mutations
      * @return bool|array
      */
-    public function updateProperties($properties) {
+    public function propPatch(PropPatch $proppatch) {
 
-        $resourceData = $this->getResourceData();
+        $proppatch->handleRemaining(function(array $properties) {
 
-        foreach($properties as $propertyName=>$propertyValue) {
+            $resourceData = $this->getResourceData();
+            foreach($properties as $propertyName=>$propertyValue) {
 
-            // If it was null, we need to delete the property
-            if (is_null($propertyValue)) {
-                if (isset($resourceData['properties'][$propertyName])) {
-                    unset($resourceData['properties'][$propertyName]);
+                // If it was null, we need to delete the property
+                if (is_null($propertyValue)) {
+                    if (isset($resourceData['properties'][$propertyName])) {
+                        unset($resourceData['properties'][$propertyName]);
+                    }
+                } else {
+                    $resourceData['properties'][$propertyName] = $propertyValue;
                 }
-            } else {
-                $resourceData['properties'][$propertyName] = $propertyValue;
+
             }
+            $this->putResourceData($resourceData);
 
-        }
+            return true;
+        });
 
-        $this->putResourceData($resourceData);
-        return true;
     }
 
     /**
diff --git a/lib/Sabre/DAV/IProperties.php b/lib/Sabre/DAV/IProperties.php
index fc10cfc..5a35cf8 100644
--- a/lib/Sabre/DAV/IProperties.php
+++ b/lib/Sabre/DAV/IProperties.php
@@ -14,41 +14,18 @@ namespace Sabre\DAV;
 interface IProperties extends INode {
 
     /**
-     * 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.
-     *
-     * 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.
+     * To update specific properties, call the 'handle' method on this object.
+     * Read the PropPatch documentation for more information.
      *
      * @param array $mutations
      * @return bool|array
      */
-    function updateProperties($mutations);
+    public function propPatch(PropPatch $proppatch);
 
     /**
      * Returns a list of properties for this nodes.
@@ -65,7 +42,7 @@ interface IProperties extends INode {
      * @param array $properties
      * @return array
      */
-    function getProperties($properties);
+    public function getProperties($properties);
 
 }
 
diff --git a/lib/Sabre/DAV/PropPatch.php b/lib/Sabre/DAV/PropPatch.php
new file mode 100644
index 0000000..6379b0c
--- /dev/null
+++ b/lib/Sabre/DAV/PropPatch.php
@@ -0,0 +1,342 @@
+<?php
+
+namespace Sabre\DAV;
+
+/**
+ * This class represents a set of properties that are going to be updated.
+ *
+ * Usually this is simply a PROPPATCH request, but it can also be used for
+ * internal updates.
+ *
+ * Property updates must always be atomic. This means that a property update
+ * must either completely succeed, or completely fail.
+ *
+ * @copyright Copyright (C) 2007-2014 fruux GmbH. All rights reserved.
+ * @author Evert Pot (http://evertpot.com/)
+ * @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
+ */
+class PropPatch {
+
+    /**
+     * Properties that are being updated.
+     *
+     * This is a key-value list. If the value is null, the property is supposed
+     * to be deleted.
+     *
+     * @var array
+     */
+    protected $mutations;
+
+    /**
+     * A list of properties and the result of the update. The result is in the
+     * form of a HTTP status code.
+     *
+     * @var array
+     */
+    protected $result = [];
+
+    /**
+     * This is the list of callbacks when we're performing the actual update.
+     *
+     * @var array
+     */
+    protected $propertyUpdateCallbacks = [];
+
+    /**
+     * This property will be set to true if the operation failed.
+     *
+     * @var bool
+     */
+    protected $failed = false;
+
+    /**
+     * Constructor
+     *
+     * @param array $mutations A list of updates
+     */
+    public function __construct(array $mutations) {
+
+        $this->mutations = $mutations;
+
+    }
+
+    /**
+     * Call this function if you wish to handle updating certain properties.
+     * For instance, your class may be responsible for handling updates for the
+     * {DAV:}displayname property.
+     *
+     * In that case, call this method with the first argument
+     * "{DAV:}displayname" and a second argument that's a method that does the
+     * actual updating.
+     *
+     * It's possible to specify more than one property.
+     *
+     * @param string|array $properties
+     * @param callable $callback
+     * @return void
+     */
+    public function handle($properties, callable $callback) {
+
+        $usedProperties = [];
+        foreach((array)$properties as $propertyName) {
+
+            if (isset($this->mutations[$propertyName]) && !isset($this->result[$propertyName])) {
+
+                $usedProperties[] = $propertyName;
+                // HTTP Accepted
+                $this->result[$propertyName] = 202;
+            }
+
+        }
+
+        // Only registering if there's any unhandled properties.
+        if (!$usedProperties) {
+            return;
+        }
+        $this->propertyUpdateCallbacks[] = [
+            // We need to set this as a string, so the commit function knows
+            // how to format the arguments to the callback.
+            is_string($properties)?$properties:$usedProperties,
+            $callback
+        ];
+
+    }
+
+    /**
+     * Call this function if you wish to handle _all_ properties that haven't
+     * been handled by anything else yet. Note that you effectively claim with
+     * this that you promise to process _all_ properties that are coming in.
+     *
+     * @param string|array $properties
+     * @param callable $callback
+     * @return void
+     */
+    public function handleRemaining(callable $callback) {
+
+        $properties = $this->getRemainingMutations();
+        if (!$properties) {
+            // Nothing to do, don't register callback
+            return;
+        }
+
+        foreach($properties as $propertyName) {
+            // HTTP Accepted
+            $this->result[$propertyName] = 202;
+
+            $this->propertyUpdateCallbacks[] = [
+                $properties,
+                $callback
+            ];
+        }
+
+    }
+
+    /**
+     * Sets the result code for one or more properties.
+     *
+     * Properties can either be specified as a single string, or an array of
+     * strings.
+     *
+     * @param string|array $properties
+     * @param int $resultCode
+     * @return void
+     */
+    public function setResultCode($properties, $resultCode) {
+
+        foreach((array)$properties as $propertyName) {
+            $this->result[$propertyName] = $resultCode;
+        }
+
+        if ($resultCode>=400) {
+            $this->failed = true;
+        }
+
+    }
+
+    /**
+     * Sets the result code for all properties that did not have a result yet.
+     *
+     * @param int $resultCode
+     * @return void
+     */
+    public function setRemainingResultCode($resultCode) {
+
+        $this->setResultCode(
+            $this->getRemainingMutations(),
+            $resultCode
+        );
+
+    }
+
+    /**
+     * Returns the list of properties that don't have a result code yet.
+     *
+     * @return array
+     */
+    public function getRemainingMutations() {
+
+        $remaining = [];
+        foreach($this->mutations as $propertyName => $propValue) {
+            if (!isset($this->result[$propertyName])) {
+                $remaining[] = $propertyName;
+            }
+        }
+
+        return $remaining;
+
+    }
+
+    /**
+     * Performs the actual update, and calls all callbacks.
+     *
+     * This method returns true or false depending on if the operation was
+     * successful.
+     *
+     * @return void
+     */
+    public function commit() {
+
+        // First we validate if every property has a handler
+        foreach($this->mutations as $propertyName => $value) {
+
+            if (!isset($this->result[$propertyName])) {
+                $this->failed = true;
+                $this->result[$propertyName] = 403;
+            }
+
+        }
+
+        foreach($this->propertyUpdateCallbacks as $callbackInfo) {
+
+            if (is_string($callbackInfo[0])) {
+                $this->doCallbackSingleProp($callbackInfo[0], $callbackInfo[1]);
+            } else {
+                $this->doCallbackMultiProp($callbackInfo[0], $callbackInfo[1]);
+            }
+            if ($this->failed) {
+                break;
+            }
+
+        }
+
+        /**
+         * If anywhere in this operation updating a property failed, we must
+         * update all other properties accordingly.
+         */
+        if ($this->failed) {
+
+            foreach($this->result as $propertyName=>$status) {
+                if ($status === 202) {
+                    // Failed dependency
+                    $this->result[$propertyName][$status] = 424;
+                }
+            }
+
+        }
+
+        return !$this->failed;
+
+    }
+
+    /**
+     * Executes a property callback with the single-property syntax.
+     * 
+     * @param string $propertyName
+     * @param callable $callback
+     * @return void
+     */
+    private function doCallBackSingleProp($propertyName, callable $callback) {
+
+        $result = $callback($this->mutations[$propertyName]);
+        if (is_bool($result)) {
+            if ($result) { 
+                if (is_null($this->mutations[$propertyName])) {
+                    // Delete
+                    $result = 204;
+                } else {
+                    // Update
+                    $result = 200;
+                }
+            } else {
+                // Fail
+                $result = 403;
+            } 
+        }
+        if (!is_int($result)) {
+            throw new UnexpectedValueException('A callback sent to handle() did not return an int or a bool');
+        }
+        $this->mutations[$propertyName] = $result;
+        if ($result>=400) {
+            $this->failed = true;
+        }
+
+    }
+
+    /**
+     * Executes a property callback with the multi-property syntax.
+     * 
+     * @param array $propertyName
+     * @param callable $callback
+     * @return void
+     */
+    private function doCallBackMultiProp(array $propertyList, callable $callback) {
+
+        $argument = [];
+        foreach($propertyList as $propertyName) {
+            $argument[$propertyName] = $this->mutations[$propertyName];
+        }
+
+        $result = $callback($propertyName);
+
+        if (is_array($result)) {
+            foreach($propertyList as $propertyName) {
+                if (!isset($result[$propertyName])) {
+                    $resultCode = 500;
+                }
+                $resultCode = $result[$propertyName];
+                if ($resultCode >= 400) {
+                    $this->failed = true;
+                }
+                $this->result[$propertyName] = $resultCode;
+
+            }
+        } elseif ($result === true) {
+
+            // Success
+            foreach($argument as $propertyName=>$propertyValue) {
+                $this->result[$propertyName] = is_null($propertyValue)?204:200;
+            }
+
+        } elseif ($result === false) {
+            // Fail :(
+            $this->failed = true;
+            foreach($propertyList as $propertyName) {
+                $this->result[$propertyName] = 403;
+            }
+        } 
+
+    }
+
+    /**
+     * Returns the result of the operation.
+     *
+     * @return array
+     */
+    public function getResult() {
+
+        return $this->result;
+
+    }
+
+    /**
+     * Returns the full list of mutations
+     *
+     * @return array
+     */
+    public function getMutations() {
+
+        return $this->mutations;
+
+    }
+
+}
diff --git a/lib/Sabre/DAV/Server.php b/lib/Sabre/DAV/Server.php
index 588feca..2a2ace5 100644
--- a/lib/Sabre/DAV/Server.php
+++ b/lib/Sabre/DAV/Server.php
@@ -1281,7 +1281,19 @@ class Server extends EventEmitter {
                 // Re-throwing exception
                 if ($exception) throw $exception;
 
-                return $errorResult;
+                // Re-arranging the result so it makes sense for
+                // generateMultiStatus.
+                $newResult = [
+                    'href' => $uri,
+                ];
+                foreach($errorResult as $property=>$code) {
+                    if (!isset($newResult[$code])) {
+                        $newResult[$code] = [$property => null];
+                    } else {
+                        $newResult[$code][$property] = null;
+                    }
+                }
+                return $newResult;
             }
 
         }
@@ -1300,15 +1312,31 @@ class Server extends EventEmitter {
      * Note that this request should either completely succeed, or
      * completely fail.
      *
-     * The response is an array with statuscodes for keys, which in turn
-     * contain arrays with propertynames. This response can be used
-     * to generate a multistatus body.
+     * The response is an array with properties for keys, and http status codes
+     * as their values.
      *
-     * @param string $uri
+     * @param string $path
      * @param array $properties
      * @return array
      */
-    public function updateProperties($uri, array $properties) {
+    public function updateProperties($path, array $properties) {
+
+        $propPatch = new PropPatch($properties);
+        $this->emit('propPatch', [$path, $propPatch]);
+        $propPatch->commit();
+
+        return $propPatch->getResult();
+
+        /*
+        $restructuredResult = [];
+        foreach($result as $key=>$value) {
+            if (isset($restructedResult[$value])) {
+                $restructedResult[$value] = [
+                    $key => null,
+                ];
+            }
+        }
+
 
         // we'll start by grabbing the node, this will throw the appropriate
         // exceptions if it doesn't.
@@ -1405,6 +1433,7 @@ class Server extends EventEmitter {
         }
         $result['href'] = $uri;
         return $result;
+         */
 
     }
 
diff --git a/lib/Sabre/DAV/Tree.php b/lib/Sabre/DAV/Tree.php
index c15c4ea..2ce8fff 100644
--- a/lib/Sabre/DAV/Tree.php
+++ b/lib/Sabre/DAV/Tree.php
@@ -177,7 +177,7 @@ abstract class Tree {
      * @param string $destinationName
      * @return void
      */
-    protected function copyNode(INode $source,ICollection $destinationParent,$destinationName = null) {
+    protected function copyNode(INode $source, ICollection $destinationParent, $destinationName = null) {
 
         if (!$destinationName) $destinationName = $source->getName();
 
@@ -210,7 +210,9 @@ abstract class Tree {
         if ($source instanceof IProperties && $destination instanceof IProperties) {
 
             $props = $source->getProperties(array());
-            $destination->updateProperties($props);
+            $propPatch = new PropPatch($props);
+            $destination->propPatch($propPatch);
+            $propPatch->commit();
 
         }
 
diff --git a/tests/Sabre/DAV/FSExt/NodeTest.php b/tests/Sabre/DAV/FSExt/NodeTest.php
index 275075b..3b20a58 100644
--- a/tests/Sabre/DAV/FSExt/NodeTest.php
+++ b/tests/Sabre/DAV/FSExt/NodeTest.php
@@ -1,7 +1,9 @@
 <?php
 
 namespace Sabre\DAV\FSExt;
+
 use Sabre\DAV;
+use Sabre\DAV\PropPatch;
 
 require_once 'Sabre/TestUtil.php';
 
@@ -29,13 +31,11 @@ class NodeTest extends \PHPUnit_Framework_TestCase {
             '{http://sabredav.org/NS/2010}test2' => 'bar',
         );
 
-        $result = $file->updateProperties($properties);
-        $expected = true;
-
-        $this->assertEquals($expected, $result);
+        $propPatch = new PropPatch($properties);
+        $file->propPatch($propPatch);
+        $propPatch->commit();
 
         $getProperties = $file->getProperties(array_keys($properties));
-
         $this->assertEquals($properties, $getProperties);
 
     }
@@ -51,7 +51,9 @@ class NodeTest extends \PHPUnit_Framework_TestCase {
             '{http://sabredav.org/NS/2010}test2' => 'bar',
         );
 
-        $result = $file->updateProperties($mutations);
+        $propPatch = new PropPatch($mutations);
+        $file->propPatch($propPatch);
+        $result = $propPatch->commit();
 
         $this->assertEquals(true, $result);
 
@@ -60,7 +62,9 @@ class NodeTest extends \PHPUnit_Framework_TestCase {
             '{http://sabredav.org/NS/2010}test3' => 'baz',
         );
 
-        $result = $file->updateProperties($mutations);
+        $propPatch = new PropPatch($mutations);
+        $file->propPatch($propPatch);
+        $result = $propPatch->commit();
 
         $this->assertEquals(true, $result);
     }
@@ -77,7 +81,9 @@ class NodeTest extends \PHPUnit_Framework_TestCase {
             '{http://sabredav.org/NS/2010}test2' => 'bar',
         );
 
-        $result = $file->updateProperties($mutations);
+        $propPatch = new PropPatch($mutations);
+        $file->propPatch($propPatch);
+        $result = $propPatch->commit();
 
         $this->assertEquals(true, $result);
 
@@ -86,7 +92,10 @@ class NodeTest extends \PHPUnit_Framework_TestCase {
             '{http://sabredav.org/NS/2010}test3' => null
         );
 
-        $result = $file->updateProperties($mutations);
+
+        $propPatch = new PropPatch($mutations);
+        $file->propPatch($propPatch);
+        $result = $propPatch->commit();
 
         $this->assertEquals(true, $result);
 
@@ -109,7 +118,9 @@ class NodeTest extends \PHPUnit_Framework_TestCase {
             '{http://sabredav.org/NS/2010}test2' => 'bar',
         );
 
-        $result = $file->updateProperties($mutations);
+        $propPatch = new PropPatch($mutations);
+        $file->propPatch($propPatch);
+        $result = $propPatch->commit();
 
         $this->assertEquals(true, $result);
 
@@ -149,7 +160,9 @@ class NodeTest extends \PHPUnit_Framework_TestCase {
             '{http://sabredav.org/NS/2010}test2' => 'bar',
         );
 
-        $result = $file->updateProperties($mutations);
+        $propPatch = new PropPatch($mutations);
+        $file->propPatch($propPatch);
+        $result = $propPatch->commit();
 
         $this->assertEquals(true, $result);
 
diff --git a/tests/Sabre/DAV/HTTPPreferParsingTest.php b/tests/Sabre/DAV/HTTPPreferParsingTest.php
index 73c7926..9eaed82 100644
--- a/tests/Sabre/DAV/HTTPPreferParsingTest.php
+++ b/tests/Sabre/DAV/HTTPPreferParsingTest.php
@@ -155,12 +155,11 @@ BLA
 BLA
         );
 
-        $this->server->on('updateProperties', function(&$props, &$result) {
+        $this->server->on('propPatch', function($path, PropPatch $propPatch) {
 
-            if (isset($props['{DAV:}something'])) {
-                unset($props['{DAV:}something']);
-                $result[200]['{DAV:}something'] = null;
-            }
+            $propPatch->handle('{DAV:}something', function($props) {
+                return true; 
+            });
 
         });
 
diff --git a/tests/Sabre/DAV/Mock/PropertiesNode.php b/tests/Sabre/DAV/Mock/PropertiesNode.php
new file mode 100644
index 0000000..ef1d285
--- /dev/null
+++ b/tests/Sabre/DAV/Mock/PropertiesNode.php
@@ -0,0 +1,56 @@
+<?php
+
+namespace Sabre\DAV\Mock;
+
+use
+    Sabre\DAV\IProperties;
+
+/**
+ * A node specifically for testing property-related operations
+ * 
+ * @copyright Copyright (C) 2007-2014 fruux GmbH. All rights reserved.
+ * @author Evert Pot (http://evertpot.com/) 
+ * @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
+ */
+class PropertiesCollection extends Collection implements IProperties {
+
+    public $failMode = false;
+
+    /**
+     * Updates properties on this node.
+     *
+     * 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 array $mutations
+     * @return bool|array
+     */
+    public function propPatch(PropPatch $proppatch) {
+
+        $proppatch->on('commit', function() {
+
+            switch($this->failMode) {
+                case 'updatepropsfalse' : return false;
+                case 'updatepropsarray' :
+                    $r = array(402 => array());
+                    foreach($updateProperties as $k=>$v) $r[402][$k] = null;
+                    return $r;
+                case 'updatepropsobj' :
+                    return new \STDClass();
+            }
+
+        });
+
+    }
+
+    function getProperties($requestedPropeties) {
+
+        return array();
+
+    }
+
+
+}
diff --git a/tests/Sabre/DAV/PropPatchTest.php b/tests/Sabre/DAV/PropPatchTest.php
new file mode 100644
index 0000000..87233a1
--- /dev/null
+++ b/tests/Sabre/DAV/PropPatchTest.php
@@ -0,0 +1,127 @@
+<?php
+
+namespace Sabre\DAV;
+
+class PropPatchTest extends \PHPUnit_Framework_TestCase {
+
+    protected $propPatch;
+
+    public function setUp() {
+
+        $this->propPatch = new PropPatch([
+            '{DAV:}displayname' => 'foo',
+        ]);
+
+    }
+
+    public function testHandleSuccess() {
+
+        $hasRan = false;
+
+        $this->propPatch->handle('{DAV:}displayname', function($value) use (&$hasRan) {
+            $hasRan = true;
+            $this->assertEquals('foo', $value);
+            return true;
+        });
+
+        $this->assertTrue($this->propPatch->commit());
+        $result = $this->propPatch->getResult();
+        $this->assertEquals(['{DAV:}displayname' => 200], $result);
+
+        $this->assertTrue($hasRan);
+
+    }
+    public function testHandleNothing() {
+
+        $hasRan = false;
+
+        $this->propPatch->handle('{DAV:}foobar', function($value) use (&$hasRan) {
+            $hasRan = true;
+        });
+
+        $this->assertFalse($hasRan);
+
+    }
+
+    public function testHandleRemaining() {
+
+        $hasRan = false;
+
+        $this->propPatch->handleRemaining(function($mutations) use (&$hasRan) {
+            $hasRan = true;
+            $this->assertEquals(['{DAV:}displayname' => 'foo'], $mutations);
+            return true;
+        });
+
+        $this->assertTrue($this->propPatch->commit());
+        $result = $this->propPatch->getResult();
+        $this->assertEquals(['{DAV:}displayname' => 200], $result);
+
+        $this->assertTrue($hasRan);
+
+    }
+    public function testHandleRemainingNothingToDo() {
+
+        $hasRan = false;
+
+        $this->propPatch->handle('{DAV:}displayname', function() {} );
+        $this->propPatch->handleRemaining(function($mutations) use (&$hasRan) {
+            $hasRan = true;
+        });
+
+        $this->assertFalse($hasRan);
+
+    }
+
+    public function testSetResultCode() {
+
+        $this->propPatch->setResultCode('{DAV:}displayname', 201);
+        $this->assertTrue($this->propPatch->commit());
+        $result = $this->propPatch->getResult();
+        $this->assertEquals(['{DAV:}displayname' => 201], $result);
+
+    }
+
+    public function testSetResultCodeFail() {
+
+        $this->propPatch->setResultCode('{DAV:}displayname', 402);
+        $this->assertFalse($this->propPatch->commit());
+        $result = $this->propPatch->getResult();
+        $this->assertEquals(['{DAV:}displayname' => 402], $result);
+
+    }
+
+    public function testSetRemainingResultCode() {
+
+        $this->propPatch->setRemainingResultCode(204);
+        $this->assertTrue($this->propPatch->commit());
+        $result = $this->propPatch->getResult();
+        $this->assertEquals(['{DAV:}displayname' => 204], $result);
+
+    }
+
+    public function testCommitNoHandler() {
+
+        $this->assertFalse($this->propPatch->commit());
+        $result = $this->propPatch->getResult();
+        $this->assertEquals(['{DAV:}displayname' => 403], $result);
+
+    }
+
+    public function testHandlerNotCalled() {
+
+        $hasRan = false;
+
+        $this->propPatch->setResultCode('{DAV:}displayname', 402);
+        $this->propPatch->handle('{DAV:}displayname', function($value) use (&$hasRan) {
+            $hasRan = true;
+        });
+
+        $this->propPatch->commit();
+
+        // The handler is not supposed to have ran
+        $this->assertFalse($hasRan); 
+
+    }
+
+}
diff --git a/tests/Sabre/DAV/ServerPropsInfiniteDepthTest.php b/tests/Sabre/DAV/ServerPropsInfiniteDepthTest.php
index 605714c..4b7a00b 100644
--- a/tests/Sabre/DAV/ServerPropsInfiniteDepthTest.php
+++ b/tests/Sabre/DAV/ServerPropsInfiniteDepthTest.php
@@ -209,10 +209,9 @@ class ServerPropsInfiniteDepthTest extends AbstractServer {
 
         $result = $this->server->updateProperties('/test2.txt',$props);
 
-        $this->assertEquals(array(
-            '200' => array('{http://sabredav.org/NS/test}someprop' => null),
-            'href' => '/test2.txt',
-        ), $result);
+        $this->assertEquals([
+            '{http://sabredav.org/NS/test}someprop' => 200,
+        ], $result);
 
     }
 
@@ -230,9 +229,8 @@ class ServerPropsInfiniteDepthTest extends AbstractServer {
         $result = $this->server->updateProperties('/test2.txt',$props);
 
         $this->assertEquals(array(
-            '424' => array('{http://sabredav.org/NS/test}someprop' => null),
-            '403' => array('{DAV:}getcontentlength' => null),
-            'href' => '/test2.txt',
+            '{http://sabredav.org/NS/test}someprop' => array(),
+            '{DAV:}getcontentlength' => array(),
         ), $result);
 
     }
@@ -379,36 +377,3 @@ class ServerPropsInfiniteDepthTest extends AbstractServer {
     }
 
 }
-
-class PropInfiniteDepthTestDirMock extends SimpleCollection implements IProperties {
-
-    public $type;
-
-    function __construct($type) {
-
-        $this->type =$type;
-        parent::__construct('root');
-
-    }
-
-    function updateProperties($updateProperties) {
-
-        switch($this->type) {
-            case 'updatepropsfalse' : return false;
-            case 'updatepropsarray' :
-                $r = array(402 => array());
-                foreach($updateProperties as $k=>$v) $r[402][$k] = null;
-                return $r;
-            case 'updatepropsobj' :
-                return new \STDClass();
-        }
-
-    }
-
-    function getProperties($requestedPropeties) {
-
-        return array();
-
-    }
-
-}
diff --git a/tests/Sabre/DAV/ServerPropsTest.php b/tests/Sabre/DAV/ServerPropsTest.php
index ff373b0..d3d07d0 100644
--- a/tests/Sabre/DAV/ServerPropsTest.php
+++ b/tests/Sabre/DAV/ServerPropsTest.php
@@ -378,35 +378,3 @@ class ServerPropsTest extends AbstractServer {
 
 }
 
-class PropTestDirMock extends SimpleCollection implements IProperties {
-
-    public $type;
-
-    function __construct($type) {
-
-        $this->type =$type;
-        parent::__construct('root');
-
-    }
-
-    function updateProperties($updateProperties) {
-
-        switch($this->type) {
-            case 'updatepropsfalse' : return false;
-            case 'updatepropsarray' :
-                $r = array(402 => array());
-                foreach($updateProperties as $k=>$v) $r[402][$k] = null;
-                return $r;
-            case 'updatepropsobj' :
-                return new \STDClass();
-        }
-
-    }
-
-    function getProperties($requestedPropeties) {
-
-        return array();
-
-    }
-
-}
diff --git a/tests/Sabre/DAV/TreeTest.php b/tests/Sabre/DAV/TreeTest.php
index 90df642..49470e1 100644
--- a/tests/Sabre/DAV/TreeTest.php
+++ b/tests/Sabre/DAV/TreeTest.php
@@ -164,10 +164,22 @@ class TreeFileTester extends File implements IProperties {
 
     }
 
-    function updateProperties($properties) {
-
-        $this->properties = $properties;
-        return true;
+    /**
+     * Updates properties on this node.
+     *
+     * 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 array $mutations
+     * @return bool|array
+     */
+    public function propPatch(PropPatch $propPatch) {
+
+        $this->properties = $propPatch->getMutations();
+        $propPatch->setRemainingResultCode(200);
 
     }
 

-- 
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