2017 © Pedro Peláez
 

library athene2-versioning

Zend Framework 2 Module that provides versioning components for Athene2

image

serlo-org/athene2-versioning

Zend Framework 2 Module that provides versioning components for Athene2

  • Sunday, August 10, 2014
  • by arekkas
  • Repository
  • 2 Watchers
  • 4 Stars
  • 1 Installations
  • PHP
  • 0 Dependents
  • 0 Suggesters
  • 1 Forks
  • 0 Open issues
  • 3 Versions
  • 0 % Grown

The README.md

athene2-versioning

Build Status Scrutinizer Code Quality Code Coverage Latest Stable Version Latest Unstable Version License Total Downloads, (*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

The Versions