[Pkg-owncloud-commits] [php-sabredav] 46/275: Propertystorage must transfer properties after MOVE requests.

David Prévot taffit at moszumanska.debian.org
Thu Sep 25 14:55:50 UTC 2014


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

taffit pushed a commit to branch master
in repository php-sabredav.

commit 4470aef7706803bbb86476d26cb9b23b5f27a8b3
Author: Evert Pot <me at evertpot.com>
Date:   Tue May 27 01:43:36 2014 -0400

    Propertystorage must transfer properties after MOVE requests.
---
 ChangeLog.md                                       |  4 +++
 lib/DAV/CorePlugin.php                             |  7 ++++
 .../PropertyStorage/Backend/BackendInterface.php   | 13 ++++++++
 lib/DAV/PropertyStorage/Backend/PDO.php            | 38 ++++++++++++++++++++++
 lib/DAV/PropertyStorage/Plugin.php                 | 23 +++++++++++--
 .../PropertyStorage/Backend/AbstractPDOTest.php    | 34 +++++++++++++++++++
 tests/Sabre/DAV/PropertyStorage/Backend/Mock.php   | 30 +++++++++++++++++
 7 files changed, 147 insertions(+), 2 deletions(-)

diff --git a/ChangeLog.md b/ChangeLog.md
index 51ab79f..974476e 100644
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -3,11 +3,15 @@ ChangeLog
 
 2.1.0-alpha1 (2014-??-??)
 -------------------------
+* Changed: PropertyStorage backends now have a `move` method.
+* Added: `beforeMove`, and `afterMove` events.
+* #460: PropertyStorage must move properties during MOVE requests
 
 2.0.1 (2014-??-??)
 * #459: PROPFIND requests on Files with no Depth header would return a fatal
   error.
 
+
 2.0.0 (2014-05-22)
 ------------------
 
diff --git a/lib/DAV/CorePlugin.php b/lib/DAV/CorePlugin.php
index 09b8ff0..5a7bb9e 100644
--- a/lib/DAV/CorePlugin.php
+++ b/lib/DAV/CorePlugin.php
@@ -639,7 +639,14 @@ class CorePlugin extends ServerPlugin {
 
         if (!$this->server->emit('beforeUnbind',[$path])) return false;
         if (!$this->server->emit('beforeBind',[$moveInfo['destination']])) return false;
+        if (!$this->server->emit('beforeMove', [$path, $moveInfo['destination']])) return false;
         $this->server->tree->move($path, $moveInfo['destination']);
+
+        // Its important afterMove is called before afterUnbind, because it
+        // allows systems to transfer data from one path to another.
+        // PropertyStorage uses this. If afterUnbind was first, it would clean
+        // up all the properties before it has a chance.
+        !$this->server->emit('afterMove', [$path, $moveInfo['destination']]);
         $this->server->emit('afterUnbind',[$path]);
         $this->server->emit('afterBind',[$moveInfo['destination']]);
 
diff --git a/lib/DAV/PropertyStorage/Backend/BackendInterface.php b/lib/DAV/PropertyStorage/Backend/BackendInterface.php
index c2e03d5..e4f9e58 100644
--- a/lib/DAV/PropertyStorage/Backend/BackendInterface.php
+++ b/lib/DAV/PropertyStorage/Backend/BackendInterface.php
@@ -45,4 +45,17 @@ interface BackendInterface {
      */
     public function delete($path);
 
+    /**
+     * This method is called after a successful MOVE
+     *
+     * This should be used to migrate all properties from one path to another.
+     * Note that entire collections may be moved, so ensure that all properties
+     * for children are also moved along.
+     *
+     * @param string $source
+     * @param string $destination
+     * @return void
+     */
+    public function move($source, $destination);
+
 }
diff --git a/lib/DAV/PropertyStorage/Backend/PDO.php b/lib/DAV/PropertyStorage/Backend/PDO.php
index 08ab0d6..3b2d23d 100644
--- a/lib/DAV/PropertyStorage/Backend/PDO.php
+++ b/lib/DAV/PropertyStorage/Backend/PDO.php
@@ -104,4 +104,42 @@ class PDO implements BackendInterface {
 
     }
 
+    /**
+     * This method is called after a successful MOVE
+     *
+     * This should be used to migrate all properties from one path to another.
+     * Note that entire collections may be moved, so ensure that all properties
+     * for children are also moved along.
+     *
+     * @param string $source
+     * @param string $destination
+     * @return void
+     */
+    public function move($source, $destination) {
+
+        // I don't know a way to write this all in a single sql query that's
+        // also compatible across db engines, so we're letting PHP do all the
+        // updates. Much slower, but it should still be pretty fast in most
+        // cases.
+        $select = $this->pdo->prepare('SELECT id, path FROM propertystorage WHERE path = ? OR path LIKE ?');
+        $select->execute([$source, $source . '/%']);
+
+        $update = $this->pdo->prepare('UPDATE propertystorage SET path = ? WHERE id = ?');
+        while($row = $select->fetch(\PDO::FETCH_ASSOC)) {
+
+            // Sanity check. SQL may select too many records, such as records
+            // with different cases.
+            if ($row['path'] !== $source && strpos($row['path'], $source . '/')!==0) continue;
+
+            $trailingPart = substr($row['path'], strlen($source)+1);
+            $newPath = $destination;
+            if ($trailingPart) {
+                $newPath.='/' . $trailingPart;
+            }
+            $update->execute([$newPath, $row['id']]);
+
+        }
+
+    }
+
 }
diff --git a/lib/DAV/PropertyStorage/Plugin.php b/lib/DAV/PropertyStorage/Plugin.php
index f3dbc59..9d2872a 100644
--- a/lib/DAV/PropertyStorage/Plugin.php
+++ b/lib/DAV/PropertyStorage/Plugin.php
@@ -46,8 +46,9 @@ class Plugin extends ServerPlugin {
      */
     public function initialize(Server $server) {
 
-        $server->on('propFind', [$this, 'propFind'], 130);
-        $server->on('propPatch', [$this, 'propPatch'], 300);
+        $server->on('propFind',    [$this, 'propFind'], 130);
+        $server->on('propPatch',   [$this, 'propPatch'], 300);
+        $server->on('afterMove',   [$this, 'afterMove']);
         $server->on('afterUnbind', [$this, 'afterUnbind']);
 
     }
@@ -103,4 +104,22 @@ class Plugin extends ServerPlugin {
 
     }
 
+    /**
+     * Called after a node is moved.
+     *
+     * This allows the backend to move all the associated properties.
+     *
+     * @param string $path
+     * @return void
+     */
+    public function afterMove($source, $destination) {
+
+        if ($this->pathFilter && !$this->pathFilter($source)) return;
+        // If the destination is filtered, afterUnbind will handle cleaning up
+        // the properties.
+        if ($this->pathFilter && !$this->pathFilter($destination)) return;
+
+        $this->backend->move($source, $destination);
+
+    }
 }
diff --git a/tests/Sabre/DAV/PropertyStorage/Backend/AbstractPDOTest.php b/tests/Sabre/DAV/PropertyStorage/Backend/AbstractPDOTest.php
index cb96100..31f56f2 100644
--- a/tests/Sabre/DAV/PropertyStorage/Backend/AbstractPDOTest.php
+++ b/tests/Sabre/DAV/PropertyStorage/Backend/AbstractPDOTest.php
@@ -93,4 +93,38 @@ abstract class AbstractPDOTest extends \PHPUnit_Framework_TestCase {
 
     }
 
+    /**
+     * @depends testPropFind
+     */
+    function testMove() {
+
+        $backend = $this->getBackend();
+        // Creating a new child property.
+        $propPatch = new PropPatch(['{DAV:}displayname' => 'child']);
+        $backend->propPatch('dir/child', $propPatch);
+        $propPatch->commit();
+
+        $backend->move('dir','dir2');
+
+        // Old 'dir'
+        $propFind = new PropFind('dir', ['{DAV:}displayname']);
+        $backend->propFind('dir', $propFind);
+        $this->assertEquals(null, $propFind->get('{DAV:}displayname'));
+
+        // Old 'dir/child'
+        $propFind = new PropFind('dir/child', ['{DAV:}displayname']);
+        $backend->propFind('dir/child', $propFind);
+        $this->assertEquals(null, $propFind->get('{DAV:}displayname'));
+
+        // New 'dir2'
+        $propFind = new PropFind('dir2', ['{DAV:}displayname']);
+        $backend->propFind('dir2', $propFind);
+        $this->assertEquals('Directory', $propFind->get('{DAV:}displayname'));
+
+        // New 'dir2/child'
+        $propFind = new PropFind('dir2/child', ['{DAV:}displayname']);
+        $backend->propFind('dir2/child', $propFind);
+        $this->assertEquals('child', $propFind->get('{DAV:}displayname'));
+    }
+
 }
diff --git a/tests/Sabre/DAV/PropertyStorage/Backend/Mock.php b/tests/Sabre/DAV/PropertyStorage/Backend/Mock.php
index d5769aa..87e7280 100644
--- a/tests/Sabre/DAV/PropertyStorage/Backend/Mock.php
+++ b/tests/Sabre/DAV/PropertyStorage/Backend/Mock.php
@@ -81,4 +81,34 @@ class Mock implements BackendInterface {
 
     }
 
+    /**
+     * This method is called after a successful MOVE
+     *
+     * This should be used to migrate all properties from one path to another.
+     * Note that entire collections may be moved, so ensure that all properties
+     * for children are also moved along.
+     *
+     * @param string $source
+     * @param string $destination
+     * @return void
+     */
+    public function move($source, $destination) {
+
+        foreach($this->data as $path => $props) {
+
+            if ($path === $source) {
+                $this->data[$destination] = $props;
+                unset($this->data[$path]);
+                continue;
+            }
+
+            if (strpos($path, $source . '/')===0) {
+                $this->data[$destination . substr($path, strlen($source)+1)] = $props;
+                unset($this->data[$path]);
+            }
+
+        }
+
+    }
+
 }

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