PHPCR-ODM natively supports versioning documents, using the power of the PHPCR Version feature. This is an optional feature of the PHPCR specification, so make sure your PHPCR implementation supports it.
PHPCR-ODM does not replicate the complete PHPCR Version API (
PHPCR\Version). For the full flexibility, you would have
access the PHPCR session and interact with the VersionManager directly.
But PHPCR-ODM provides simple methods for the common operations, covering the most common use cases.
PHPCR has 2 levels: simpleVersionable and (full) versionable. Simple versioning consists of a linear version history and the checkin/checkout methods to create new versions. Checking in a node creates a new version and makes the node readonly. You need to check it out again to write to it (or just do a checkpoint to do both in one call).
Full versioning additionally offers branches for non-linear versioning (which the PHPCR-ODM does not provide any helper methods for) and version labels (which we plan to support once Jackalope supports them). For each node, you can add labels to a version, but one specific label may only occur once per version history of a node (meaning if you want to label another version, you need to remove the label from the first version before you add the label).
The full versioning corresponds to the PHPCR
that allows to branch versions. If you need some of the full versionable features,
you will have to :doc:`access PHPCR directly <phpcr-access>` for those operations.
Version names are generated by PHPCR and can not be controlled by the client application. There is no concept of commit messages for PHPCR. We decided to not build something like that into the core of the ODM versioning system to avoid unnecessary overhead if the user does not need it. It is however doable with having a field on your document that you set to your commit message and flush the document manager before calling checkin().
Versioning is not supported by Jackalope Doctrine DBAL PHPCR provider, while
with Jackalope Jackrabbit provider currently you can use only
because simple versioning is not yet implemented in Jackrabbit server
(see JCR-2112 issue).
For the PHPCR-ODM layer, the following applies: Contrary to translations, getting an old version does not change the document representing the current version. An old version can't be modified and can't be persisted. (Except with the special restoreVersion and removeVersion methods.)
What you get is a detached instance of the document which is ignored by flush and can not be persisted.
To version documents, you need to set the versionable attribute on the document mapping. You can choose between "full" and "simple" versionable. For PHPCR-ODM, both are equivalent.
Due to implementation limitations, the Locale field is required on all translatable documents.
Be aware that these two are different things:
documentthat is versionable. This is the document and you can take snapshots of this document with the
detached documentthat represents an old version of your document (a PHPCR frozen node). You get this document with the findVersionByName method. It is read-only. The document class you use needs not be the same. You can define a version document that is the same as your base document, but all fields are read only and you use the VersionName and VersionCreated annotations on it. It also does not need the versionable document attribute. (You do not create versions of old versions, you only create versions of the main document.)
You can track some information about old versions in PHPCR-ODM. Both are only
populated when you load an old version of a document, and both are read only.
VersionName tracks the version identifier that PHPCR assigned the
version you created,
VersionCreated the DateTime when the version was
Note that all fields of a document are automatically versioned, you can not exclude anything from being versioned. Referenced documents are not versioned at the same time, but it is stored to which document the reference pointed at this time. Children and parents are not versioned by default. Children can be versioned by defining a PHCPR node type that specifies to cascade versioning. This feature however is untested with PHPCR-ODM, if you have feedback please tell us.
Referencial integrity with hard references is only ensured for live
documents, not for versions. It is thus possible that a reference that
is declared "hard" can be null nontheless. Make sure to always check for
null values in version documents.
Interacting with versions
See the Phpdoc for full details on those methods.
DocumentManager::find()works as normal, always gives you the current latest version.
DocumentManager::getAllLinearVersions($document)returns an array with all version names for this document, ordered from most recent to oldest version. You can specify an optional limit to only get that many most recent versions.
DocumentManager::findVersionByName($id, $versionName)get a detached read-only document for a specific version.
Modify the version history:
DocumentManager::checkincreate new version of a flushed document and make it readonly
DocumentManager::checkoutmake a document that was checked in writable again
DocumentManager::checkpointcreate a new version without making the document read-only, aka checkin followed by checkout
DocumentManager::restoreVersionrestore the document to an old version
DocumentManager::removeVersioncompletely remove an old version from the history
<?php $article = new Article(); $article->id = '/test'; $article->topic = 'Test'; $dm->persist($article); $dm->flush(); // generate a version snapshot of the document as currently stored $dm->checkpoint($article); $article->topic = 'Newvalue'; $dm->flush(); // get the version information $versioninfos = $dm->getAllLinearVersions($article); $firstVersion = reset($versioninfos); // and use it to find the snapshot of an old version $oldVersion = $dm->findVersionByName(null, $article->id, $firstVersion['name']); echo $oldVersion->topic; // "Test" // find the head version $article = $dm->find('/test'); echo $article->topic; // "Newvalue" // restore the head to the old version $dm->restoreVersion($oldVersion); // the article document is refreshed echo $article->topic; // "Test" // create a second version to demo removing a version $article->topic = 'Newvalue'; $dm->flush(); $dm->checkpoint($article); // remove the old version from the history (not allowed for the last version) $dm->removeVersion($oldVersion);