Upgrading from SabreDAV 1.0 to 1.2

To keep the SabreDAV simple to use and to extend, I wanted to make a few changes.

Distribution

Before SabreDAV was distributed as a single .tgz. This is now a zip file. The pear installation is separate and comes as 4 separate packages.

  1. Sabre
  2. Sabre_HTTP
  3. Sabre_DAV
  4. Sabre_CalDAV

This forces a clearer separation of concerns and allows people to ignore packages they might not need.

All of these are installable from the PEAR channel. The old package must be uninstalled for installation to succeed. This process goes as follows:

pear uninstall Sabre_DAV
# If you hadn't added the new channel:
pear channel-discover pear.sabredav.org
pear install Sabre Sabre_HTTP Sabre_DAV Sabre_CalDAV

Sabre_DAV_Auth_* Backends structure changed

If you had your own Authentication backend defined, based on Sabre_DAV_Auth_Backend_Abstract you need to change that declaration to Sabre_DAV_Auth_Backend_AbstractDigest.

The 'Abstract' backend class can be used to create any generic authentication backend, instead of just HTTP Digest.

In addition, some method signatures were changed:

Old code:

class MyAuthenticationClass extends Sabre_DAV_Auth_Backend_Abstract {

    function getDigestHash($userName) {

        // This function would normally return the digest hash
        // This method is removed in favor of getUserInfo

    }

    function getUsers() {

        // Before this method would return a 'userId' per user
        // This should now be the uri.

        // This is still optional to implement.

    }

}

New code:

class MyAuthenticationClass extends Sabre_DAV_Auth_Backend_AbstractDigest {

    function getUserInfo($realm, $username) {

        // This function returns user information
        // based on the realm and username

        // the returned data is an array. The array must contain the
        // following 2 keys:

        // 1. uri This is a path to the user. The path does not have to exist
        //    unless CalDAV or similar standards have to be implemented.
        //    It's a good idea to name it '/principals/username'
        // 2. digestHash This is the digest hash that was used to returned
        //    from the old getDigestHash function.

    }

    function getUsers() {

        // Before this method would return a 'userId' per user
        // This should now be the uri.

        // This is still optional to implement.

    }

}

Sabre_DAV comes with both a File and a PDO authentication backend, which can be used as an easy reference.

PermissionDenied exception is now called Forbidden

Old code:

throw new Sabre_DAV_Exception_PermissionDenied('Message..');

New code:

throw new Sabre_DAV_Exception_Forbidden('Message..');

Full backwards compatibility is provided, but 'PermissionDenied' will be removed at some point in the future.

IDirectory is now called ICollection

The IDirectory interface has gotten renamed to ICollection. The signature has not changed.

Old code:

class MyClass implements Sabre_DAV_IDirectory {
  /* .... */ 
}

New code:

class MyClass implements Sabre_DAV_ICollection {
  /* .... */ 
}

Property updating has changed quite a bit

If you implemented custom properties, and specifically updating custom properties in your plugins or Nodes, take note.

The old request and response was quite complicated, but this was simplified quite a bit.

Old code:

function updateProperties($mutations) {

    // mutations is an array that looked something
    // like this:
    $mutations = array(
        array(Sabre_DAV_Server::PROP_SET, '{http://www.example.org/ns}nodename', 'value'),
        array(Sabre_DAV_Server::PROP_REMOVE, '{http://www.example.org/ns}nodename2'),
    );

    // The returned value contains a list of all the properties again, along
    // with the statuscode for the change.
    return array(
        array('{http://www.example.org/ns}nodename', 201),
        array('{http://www.example.org/ns}nodename2', 200),
    );  

}

New code:

function updateProperties($mutations) {

    // Mutations is now a simple list. If a value is null
    // it should be removed.
    // It looks kind of like this:
    $mutations = array(
        '{http://www.example.org/ns}nodename'  => 'value',
        '{http://www.example.org/ns}nodename2' => null,
    );

    // The returned value should now simply be 'true' for 
    // success, or false or an exception for failure.
    return true;

    // If you do want to tell the client in detail which mutation
    // caused the request to fail, it is still allowed in this new
    // return structure:

    return array(

        // Permission denied
        403 => array(
            '{http://www.example.org/ns}nodename' => null,
        ),

        424 => array(
            '{http://www.example.org/ns}nodename2' => null,
        ),

    );

    // The values are always null in the previous array. This format
    // was chosen because it has the exact same structure as the result
    // of PROPFIND, which also generates a multi-status response.

}

Locks_File backend now requires a constructor argument

The Sabre_DAV_Locks_Backend_FS class now requires an argument. The argument specifies where lock information is stored:

$backend = Sabre_DAV_Locks_Backend_FS('/path/to/locks/directory');

Before the locks backend would use the same directory PHP uses to store session files, but this was considered a poor choice. So it seems better to make the user choose this one.

XML namespace change

All custom SabreDAV properties used to fall under the following namespace:

This has been changed to:

"Sabre.autoload.php" and "Sabre.includes.php"

The lib/Sabre.includes.php file is now deprecated and should no longer be used. Because Sabre_DAV is split up over multiple packages, this no longer makes sense.

In the future this might come back as lib/Sabre/DAV/includes.php, lib/Sabre/HTTP/includes.php, etc.

The autoload file is now moved from:

lib/Sabre.autoload.php

to:

lib/Sabre/autoload.php

This makes more sense for packaging. The old one also still works, but will be removed at one point in the future.