Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP : docs #1

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 45 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,51 @@ This library aims to provide storage agnostic mechanics to add versioning capabi
Documentation
-------------

todo documentation
Start reading the library documentation.

* [Installation](docs/1-install.md)
* [Concepts](docs/2-concepts.md) (**highly recommended**)
* [Usage](docs/3-usage.md)
* [Initialize](docs/4-initialize.md)
* [Purge](docs/5-purge.md)


Learn more about model classes to implement.

* [Version](docs/components/version.md)
* [Versionable Resource](docs/components/versionable-resource.md)
* [Versionable Author](docs/components/versionable-author.md)


Learn more about core components.

* [Author Storage](docs/components/author-storage.md)
* [Object finder](docs/components/object-finder.md)
* [Purger](docs/components/purger.md)
* [Snapshot Taker](docs/components/snapshot-taker.md)
* [Update Guesser](docs/components/update-guesser.md)
* [Version Factory](docs/components/version-factory.md)
* [Version Storage](docs/components/version-storage.md)


Or jump to integrations.

| Require | Purpose | Documentation |
| -------------------------- | ---------------------------------------------------- | ---------------------------------------------------- |
| `symfony/framework-bundle` | Framework integration | [here](docs/integration/symfony-framework.md) |
| `symfony/event-dispatcher` | Initialize context using events | [here](docs/integration/symfony-event-dispatcher.md) |
| `symfony/serializer` | Take snapshots using normalization | [here](docs/integration/symfony-serializer.md) |
| `doctrine/orm` | Store versions using ORM, track versionable entities | [here](docs/integration/doctrine-orm.md) |
| `symfony/security` | Initialize context authors using authenticated user | [here](docs/integration/symfony-security.md) |
| `symfony/console` | Add command to purge/initialize versionable models | [here](docs/integration/symfony-console.md) |


If you did not find what you was looking for ? Have a look to the recipes.

* [Custom Author storage](docs/recipes/custom-author-storage.md)
* [Custom Object Finder](docs/recipes/custom-object-finder.md)
* [Custom Resource storage](docs/recipes/custom-resource-storage.md)
* [Custom Version storage](docs/recipes/custom-version-storage.md)


MIT License
Expand Down
13 changes: 13 additions & 0 deletions docs/1-install.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
Installation
------------

Require the library as composer dependency

```bash
$ composer require yokai/versionable
```


---

« [README](../README.md) • [Concepts](2-concepts.md) »
95 changes: 95 additions & 0 deletions docs/2-concepts.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
Concepts
--------


### Analyze models to analyze

Whenever you are about to create/update/delete something, you should trigger an analyze ot these objects,
so the library can decide whether or not there something to do with each of these.

> **note** deciding whether or not an object is under versioning is the job of the
[update guesser components](components/update-guesser.md)

When to ask this library is up to you. You must call explicitly the library to analyze your objects.
Then, for each objects that you considered as created/updated/deleted,
you must call the [VersionBuilder](../src/VersionBuilder.php).

> **integration** when using `doctrine/orm` [integration](integration/doctrine-orm.md)
you do not need to trigger the analyze explicitly : a listener is doing it for you.


### Find current version of model

The first to do is to find whether or not there was a previous version for your object.
The [verson storage](components/version-storage.md) will be called to fetch it.


### Take a snapshot

Then, the [snapshot taker](components/snapshot-taker.md) will be called to take a snapshot of your object.

A snapshot is nothing more than a normalized representation of your object, ie : an array.

> **integration** did you noticed that we talked about normalization here ?
You may use the `symfony/serializer` [integration](integration/symfony-serializer.md) to take a these snapshots.


### Determine changeset

With these information, the [ChangesetBuilder](../src/ChangesetBuilder.php) will be called with 2 snapshots to compare :
the previous that was fetched (or an empty array), the new one that was just fetched.

The snapshot will be an array, that look like to something like :

```json
{
"name": {"old": "Spoon", "new": "Very interesting spoon"},
"price": {"old": 0.29, "new": 0.30}
}
```


### Gather contextual information

Before creating the version object, the [VersionBuilder](../src/VersionBuilder.php)
will ask some contextual information (stored in [Context](../src/Context.php)).

There is three things we can extract from it :

* An entry point.
It is a `string` that represent the place on which the changes was performed.
* Some parameters.
It is an `array` that represent the parameters of the endpoint.
* An author.
It is an `object`, instance of [VersionableAuthorInterface](../src/VersionableAuthorInterface.php)
that represent the one that introduced these changes.


> **integration** when using `symfony/event-dispatcher` [integration](integration/symfony-event-dispatcher.md),
the entry point and parameters may be filled using `route` and `route params` in http context,
or with `command name` and `command arguments` plus `command options` in console context.
The author may be filled using authenticated user if available (and if it implements the interface).


### Create a version object

At this point, we have all required information to create a new version for our object.
The [version factory](components/version-factory.md) will be asked to create it.

Then, the [VersionBuilder](../src/VersionBuilder.php) will return the object version.

> **note** the version changeset may be empty, it is up to decide what to do with it.


### Store new version of model

The [VersionBuilder](../src/VersionBuilder.php) just built a version for your object(s), but it is not stored yet.
The [verson storage](components/version-storage.md) should be called to store the built version(s).

> **integration** when using `doctrine/orm` [integration](integration/doctrine-orm.md)
you do not need to store the version by yourself : a listener is doing it for you.


---

« [Install](1-install.md) • [Usage](3-usage.md) »
104 changes: 104 additions & 0 deletions docs/3-usage.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
Usage
-----

The following example assume that you (as a developer) provided an implementation for each of the following :

* `MyVersionFactory` : a [version factory](components/version-factory.md)
* `MyVersionStorage` : a [version storage](components/version-storage.md)
* `MySnapshotTaker` : a [snapshot taker](components/snapshot-taker.md)

> **note** keep in mind that the library already provide at least one implementation for each.

Additionally, the example assume that the following models exists and are :

* `Acme\Model\BlogPost` : a valid [versionable resource](components/versionable-resource.md)
* `Acme\Model\User` : a valid [versionable author](components/versionable-author.md)


```php
<?php

use Yokai\Versioning\ChangesetBuilder;
use Yokai\Versioning\TypesConfig;
use Yokai\Versioning\Context;
use Yokai\Versioning\VersionBuilder;
use Yokai\Versioning\UpdateGuesser\ChainUpdateGuesser;
use Yokai\Versioning\UpdateGuesser\UpdateGuesserInterface;
use Yokai\Versioning\UpdateGuesser\VersionableChildUpdateGuesser;
use Yokai\Versioning\UpdateGuesser\VersionableUpdateGuesser;

/** @var \Yokai\Versioning\VersionFactoryInterface $versionFactory */
$versionFactory = new MyVersionFactory();
/** @var \Yokai\Versioning\Storage\VersionStorageInterface $versionStorage */
$versionStorage = new MyVersionStorage();
/** @var \Yokai\Versioning\SnapshotTakerInterface $snapshotTaker */
$snapshotTaker = new MySnapshotTaker();

$typesConfig = new TypesConfig(
['user' => 'Acme\Model\BlogPost'],
['blog-post' => 'Acme\Model\User']
);

$context = new Context();
$context->setEntryPoint($theAction);
$context->setParameters($theActionParameters);
$context->setAuthor($theUserThatTriggeredTheChanges);

$updateGuesser = new ChainUpdateGuesser([new VersionableUpdateGuesser(), new VersionableChildUpdateGuesser()]);

$versionBuilder = new VersionBuilder(
$typesConfig,
$versionStorage,
$snapshotTaker,
new ChangesetBuilder(),
$context,
$versionFactory
);

$versions = [];

$analyzeHash = [
UpdateGuesserInterface::ACTION_INSERT => $createdObjects,
UpdateGuesserInterface::ACTION_UPDATE => $updatedObjects,
UpdateGuesserInterface::ACTION_DELETE => $deletedObjects,
];

foreach ($analyzeHash as $action => $objects) {
foreach ($objects as $object) {
foreach ($updateGuesser->guessUpdates($object, $action) as $versionable) {
$version = $versionBuilder->build($object);

if (count($version->getChangeSet()) === 0) {
continue;
}

$versions[] = $version;
}
}
}

$versionStorage->store($versions);
```

What is happening here ?

* First, an instance of each of your components are created.
* An instance of [TypesConfig](../src/TypesConfig.php) is created.
It will store mapping of storage identifier for each versionable resource / author.
* An instance of [Context](../src/Context.php) is created.
It will store the context of the triggered changes.
* The [Context](../src/Context.php) is filled using some information (optional).
* An [update guesser](components/update-guesser.md) is created.
It will find what versionable resources are tracked for an object.
* An instance of [VersionBuilder](../src/VersionBuilder.php), with all its dependencies is created.
It will build a version for a each versionable objects.
* An analyze will be triggered for each inserted/updated/deleted objects, 3 steps :
* Find versionables resources associated, using the update guesser.
* Build a version for each of the versionable resources.
* Add the version object to an array if the changeset is not empty.
* The version storage is called with the list of built version to store through persistence.


---

« [Concepts](2-concepts.md) • [Initialize](4-initialize.md) »
17 changes: 17 additions & 0 deletions docs/4-initialize.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
Initialize
----------

If you installed this library in a project that already has some versionable resource models.
You may want to initialize the first version of these objects in the version storage.

This is the responsibility of the [Initializer](../src/Initialize/Initializer.php).

The initializer will trigger the version analyze process for each objects
fetched by the [version finder](components/object-finder.md).

> **note** the [Symfony Console component](integration/symfony-console.md) integration has a command to trigger it.


---

« [Usage](3-usage.md) • [Purge](5-purge.md) »
18 changes: 18 additions & 0 deletions docs/5-purge.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
Purge
-----

Sometime, you may want to remove some versions from the storage.

There is different strategies you may want to implement :
* keep a fixed number of version for each versionable resource
* remove versions of versionable resources that was removed
* etc...

This feature is covered by the [purger](components/purger.md).

> **note** the [Symfony Console component](integration/symfony-console.md) integration has a command to trigger it.


---

« [Initialize](4-initialize.md) • [README](../README.md) »
8 changes: 8 additions & 0 deletions docs/components/author-storage.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
Author storage
--------------



---

« [README](../../README.md)
8 changes: 8 additions & 0 deletions docs/components/object-finder.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
Object Finder
-------------



---

« [README](../../README.md)
8 changes: 8 additions & 0 deletions docs/components/purger.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
Purger
------



---

« [README](../../README.md)
8 changes: 8 additions & 0 deletions docs/components/snapshot-taker.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
Snapshot taker
--------------



---

« [README](../../README.md)
8 changes: 8 additions & 0 deletions docs/components/update-guesser.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
Update guesser
--------------



---

« [README](../../README.md)
48 changes: 48 additions & 0 deletions docs/components/version-factory.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
Version Factory
---------------

The [VersionFactoryInterface](../../src/VersionFactoryInterface.php)
is the interface for version factories.

The purpose of a version factory is to return a concrete [version](version.md) instance.

```php
<?php

use Yokai\Versioning\VersionFactoryInterface;
use Yokai\Versioning\VersionInterface;

class VersionFactory implements VersionFactoryInterface
{
public function create(
array $resource,
int $version,
array $snapshot,
array $changeSet,
array $author,
array $context,
DateTimeInterface $loggedAt
): VersionInterface {
list($resourceType, $resourceId) = $resource;
list($authorType, $authorId) = $author;
list($contextEndpoint, $contextParameters) = $context;

return new Acme\My\Version(
$resourceType,
$resourceId,
$version,
$snapshot,
$changeSet,
$authorType,
$authorId,
$contextEndpoint,
$contextParameters,
$loggedAt
);
}
}
```

---

« [README](../../README.md)
Loading