athene2-versioning
, (*1)
Installation
athene2-versioning only officially supports installation through Composer. For Composer documentation, please refer to
getcomposer.org., (*2)
Install the module:, (*3)
$ php composer.phar require serlo-org/athene2-versioning:~2.0
Using the versioning module
The versioning module enables you to manage repositories which contain revisions. Each repository has n revisions and one or zero HEAD revision. The HEAD revision is the current revision of that repository. The default implementation of the VersioningManager is Doctrine friendly!, (*4)
Features
- Doctrine implementation (using the ObjectManager)
- Bundled with zfc-rbac for authorization
- Events
Understanding how it works
The versioning module consists of one Versioning\Manager\VersioningManager
, who implements the Versioning\Manager\VersioningManagerInterface
. He manages models or entities which implement the Versioning\Entity\RepositoryInterface
and the Versioning\Entity\RevisionInterface
., (*5)
Let's implement those entity interfaces!
You can find example implementations here!, (*6)
RevisionInterface
<?php
use Athene2\Versioning\Entity\RepositoryInterface;
use Athene2\Versioning\Entity\RevisionInterface;
use ZfcRbac\Identity\IdentityInterface;
/**
* Class Revision
*
* @author Aeneas Rekkas
*/
class Revision implements RevisionInterface
{
/**
* @var mixed
*/
protected $id;
/**
* @var RepositoryInterface
*/
protected $repository;
/**
* @var
*/
protected $author;
/**
* @var bool
*/
protected $trashed = false;
/**
* @var array
*/
protected $data = [];
/**
* @param mixed $id
* @return void
*/
public function setId($id)
{
$this->id = $id;
}
/**
* {@inheritDoc}
*/
public function getId()
{
return $this->id;
}
/**
* {@inheritDoc}
*/
public function getRepository()
{
return $this->repository;
}
/**
* {@inheritDoc}
*/
public function setRepository(RepositoryInterface $repository)
{
$this->repository = $repository;
}
/**
* {@inheritDoc}
*/
public function setAuthor(IdentityInterface $author)
{
$this->author = $author;
}
/**
* {@inheritDoc}
*/
public function getAuthor()
{
return $this->author;
}
/**
* {@inheritDoc}
*/
public function setTrashed($trash)
{
$this->trashed = (bool)$trash;
}
/**
* {@inheritDoc}
*/
public function isTrashed()
{
return $this->trashed;
}
/**
* {@inheritDoc}
*/
public function set($key, $value)
{
$this->data[$key] = $value;
}
/**
* {@inheritDoc}
*/
public function get($key)
{
return isset($this->data[$key]) ? $this->data[$key] : null;
}
}
RepositoryInterface
<?php
use Athene2\Versioning\Entity\RepositoryInterface;
use Athene2\Versioning\Entity\RevisionInterface;
class Repository implements RepositoryInterface
{
/**
* @var array|RevisionInterface[]
*/
protected $revisions = [];
/**
* @var null|RevisionInterface
*/
protected $head = null;
/**
* @var mixed
*/
protected $id;
/**
* {@inheritDoc}
*/
public function addRevision(RevisionInterface $revision)
{
$this->revisions[$revision->getId()] = $revision;
}
/**
* {@inheritDoc}
*/
public function createRevision()
{
return new Revision();
}
/**
* {@inheritDoc}
*/
public function getCurrentRevision()
{
return $this->head;
}
/**
* {@inheritDoc}
*/
public function getId()
{
return $this->id;
}
/**
* {@inheritDoc}
*/
public function getRevisions()
{
return $this->revisions;
}
/**
* {@inheritDoc}
*/
public function hasCurrentRevision()
{
return null !== $this->head;
}
/**
* {@inheritDoc}
*/
public function removeRevision(RevisionInterface $revision)
{
unset($this->revisions[$revision->getId()]);
}
/**
* {@inheritDoc}
*/
public function setCurrentRevision(RevisionInterface $revision)
{
$this->head = $revision;
}
}
Well, that wasn't so hard, was it?, (*7)
Using the RepositoryManager
The default RepositoryManager
implementation is bundled with Doctrine, ZF2 EventManager and zfc-rbac., (*8)
Setting up permissions
Not everyone should be allowed to commit, reject and accept revisions, right? Therefore, the RepositoryManager
is able to handle permissions via zfc-rbac!, (*9)
To set up permissions, you will need to add some config data to your module.config.php:, (*10)
return [
// ...
'versioning' => [
'permissions' => [
// Use the classname of the revision class
// In the example above the namespace is missing, therefore the classname is only "Revision".
// This could be also "MyModule\Entity\Revision"
'Revision' => [
// There are three actions which need authentication:
// 'commit' gets checked when you call "commitRevision"
ModuleOptions::KEY_PERMISSION_COMMIT => 'revision.create',
// 'checkout' gets checked when you call "checkoutRevision"
ModuleOptions::KEY_PERMISSION_CHECKOUT => 'revision.checkout',
// 'reject' gets checked when you call "rejectRevision"
ModuleOptions::KEY_PERMISSION_REJECT => 'revision.trash'
// Name the permissions whatever you like. Just be aware that they are registered in zfc-rbac!
// ModuleOptions::KEY_PERMISSION_COMMIT => 'mymodule.entity.revision.commit',
]
]
]
// ...
];
Important: The revision is always passed to zfc-rbac as a context object for usage with e.g. Assertions!, (*11)
Create a new Revision and fill it with data!
// Let's create a repository first
$repository = new Repository();
// Now we need the RepositoryManager
$repositoryManager = $serviceManager->get('Athene2\Versioning\Manager\VersioningManager');
// Let's create our first revision!
$revision = $repositoryManager->commitRevision($repository, ['foo' => 'bar'], 'I added some stuff');
// And check it out (set as HEAD / current revision)
// We can also add a short message, why we checked out this revision!
$repositoryManager->checkoutRevision($repository, $revision, 'That\'s a nice reason, isn\'t it?');
// Now, let's make those changes persistent!
$repositoryManager->flush();
Trash a revision
Someone made a mistake? Just reject the revision!, (*12)
// Now we need the RepositoryManager
$repositoryManager = $serviceManager->get('Athene2\Versioning\Manager\VersioningManager');
$revision = $repositoryManager->rejectRevision($repository, 5, 'Sorry but there are too many mistakes!');
// Now, let's make those changes persistent!
$repositoryManager->flush();
Check out a revision
Do you approve of a certain revision? Go ahead and check it out!, (*13)
// Now we need the RepositoryManager
$repositoryManager = $serviceManager->get('Athene2\Versioning\Manager\VersioningManager');
$revision = $repositoryManager->checkoutRevision($repository, 5, 'Fine job!');
// Now, let's make those changes persistent!
$repositoryManager->flush();
Hooking into Events
The VersioningManager fires events for both failure and success:, (*14)
$eventManager = $repositoryManager->getEventManager();
$eventManager->attach(VersioningEvent::COMMIT, function(VersioningEvent $event) {
echo "I just committed a new revision with a cool message: " . $event->getMessage();
});
$eventManager->attach(VersioningEvent::COMMIT_UNAUTHORIZED, function(VersioningEvent $event) {
echo "I just committed a new revision but didn't have the rights to do so!";
});
$repositoryManager->commitRevision($repository, $data, $message);
There are also other events available, like:, (*15)
-
VersioningEvent::COMMIT
and VersioningEvent::COMMIT_UNAUTHORIZED
-
VersioningEvent::REJECT
and VersioningEvent::REJECT_UNAUTHORIZED
-
VersioningEvent::CHECKOUT
and VersioningEvent::CHECKOUT_UNAUTHORIZED
To be done
There are a more things to come:, (*16)
- A beautiful UI to manage your repositories
- A RESTful API
- Better docs