mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-10-22 14:05:37 +02:00
Complete version doc rewrite.
This commit is contained in:
parent
d0a16bacd2
commit
e0762d5a95
@ -13,7 +13,7 @@ Versioning in SilverStripe is handled through the [Versioned](api:SilverStripe\V
|
||||
|
||||
## Understanding versioning concepts
|
||||
|
||||
This section discuss how SilverStripe implements versioning and related high level concepts.
|
||||
This section discuss how SilverStripe implements versioning and related high level concepts without digging into technical details.
|
||||
|
||||
### Stages
|
||||
|
||||
@ -86,6 +86,8 @@ It is possible for an item to be included both implicitly and explicitly in a ch
|
||||
|
||||
## Implementing a versioned DataObject
|
||||
|
||||
This section explains how to take a regular DataObject and add versioning to it.
|
||||
|
||||
### Applying the `Versioned` extension to your DataObject
|
||||
|
||||
```php
|
||||
@ -106,6 +108,7 @@ can be specified by using the `.versioned` service variant that provides only ve
|
||||
staging.
|
||||
|
||||
```php
|
||||
<?php
|
||||
use SilverStripe\ORM\DataObject;
|
||||
use SilverStripe\Versioned\Versioned;
|
||||
|
||||
@ -284,6 +287,8 @@ class Page extends SiteTree
|
||||
|
||||
## Interacting with versioned DataObjects
|
||||
|
||||
This section deals with specialised oeprations that can be perform on versioned DataObjects.
|
||||
|
||||
### Reading latest versions by stage
|
||||
|
||||
By default, all records are retrieved from the "Draft" stage (so the `MyRecord` table in our example). You can
|
||||
@ -309,6 +314,7 @@ in the `<class>_versions` tables.
|
||||
|
||||
```php
|
||||
<?php
|
||||
use SilverStripe\Versioned\Versioned;
|
||||
$historicalRecord = Versioned::get_version('MyRecord', <record-id>, <version-id>);
|
||||
```
|
||||
|
||||
@ -354,7 +360,7 @@ Similarly, an "unpublish" operation does the reverse, and removes a record from
|
||||
### Publishing a versioned DataObject
|
||||
|
||||
There's two main methods used to publish a versioned DataObject:
|
||||
* `publishSingle()` publishes this record to live from the draft.
|
||||
* `publishSingle()` publishes this record to live from the draft
|
||||
* `publishRecursive()` publishes this record, and any dependant objects this record may refer to.
|
||||
|
||||
In most regular cases, you'll want to use `publishRecursive`.
|
||||
@ -366,7 +372,7 @@ In most regular cases, you'll want to use `publishRecursive`.
|
||||
$record = MyRecord::get()->byID(99);
|
||||
$record->MyField = 'changed';
|
||||
|
||||
// Will create a new revision in Stage. Editors will be able to see this revision, but visitors to the website.
|
||||
// Will create a new revision in Stage. Editors will be able to see this revision, but not visitors to the website.
|
||||
$record->write();
|
||||
|
||||
// This will publish the changes so they are visible publicly.
|
||||
@ -377,7 +383,7 @@ $record->publishRecursive();
|
||||
|
||||
Archiving and unpublishing are similar operations, both will prevent a versioned DataObject from being publicly accessible. Archiving will also remove the record from the _Stage_ stage ; other ORMs may refer to this concept as _soft-deletion_.
|
||||
|
||||
Use `doUnpublish()` to unpublish an item. Simply call `delete()` to archive an item. The SilverStripe ORM doesn't _hard_ deletion of versioned DataObjects.
|
||||
Use `doUnpublish()` to unpublish an item. Simply call `delete()` to archive an item. The SilverStripe ORM doesn't allow you to _hard-delete_ versioned DataObjects.
|
||||
|
||||
```php
|
||||
<?php
|
||||
@ -394,7 +400,29 @@ $record->delete();
|
||||
Note that `doUnpublish()` and `doArchive()` do not work recursively. If you wish to unpublish or archive dependants records, you have to it manually.
|
||||
|
||||
### Rolling back to an older version
|
||||
Rolling back allows you to return a DataObject to a previous state. You can rollback a single DataObject using the `rollbackSingle` method. You can also rollback all dependant records using the `rollbackRecursive()` method.
|
||||
Rolling back allows you to return a DataObject to a previous state. You can rollback a single DataObject using the `rollbackSingle()` method. You can also rollback all dependant records using the `rollbackRecursive()` method.
|
||||
|
||||
Both `rollbackSingle()` and `rollbackRecursive()` expect a single argument, which may be a specific version ID or a stage name.
|
||||
|
||||
```php
|
||||
<?php
|
||||
use SilverStripe\Versioned\Versioned;
|
||||
|
||||
$record = MyRecord::get()->byID(99);
|
||||
|
||||
// This will take the current live version of record ID 99 - and all it's associated DataObjects - and copy it to the
|
||||
// "Stage" stage. This is equivalent to dismissing any draft work and reverting to what was last published.
|
||||
$record->rollbackRecursive(Versioned::LIVE);
|
||||
|
||||
// This will restore version 10 of record ID 99 to "Stage" without affecting any owned DataObjects.
|
||||
$record->rollbackSingle(10);
|
||||
|
||||
// The live version of the record won't be affected unless you publish you're rolled back record.
|
||||
$record->publishRecursive();
|
||||
```
|
||||
|
||||
Note that internally, rolling back a DataObject creates a new version identical of the restored version ID. For example,
|
||||
if the live version of `$record` is 10 and the staged version is 13, rolling back to live will create a version 14 in _Stage_ that is identical to version 10.
|
||||
|
||||
### Restoring an archived version
|
||||
|
||||
@ -417,6 +445,8 @@ foreach ($allMyRecords as $myRecord)
|
||||
|
||||
## Interacting with ChangeSet
|
||||
|
||||
This section explains how you can interact with ChangeSets.
|
||||
|
||||
### Adding and removing DataObjects to a change set
|
||||
|
||||
* `$myChangeSet->addObject(DataObject $record)`: Add a record and all of its owned records to the changeset (`canEdit()` dependent).
|
||||
@ -430,23 +460,25 @@ foreach ($allMyRecords as $myRecord)
|
||||
|
||||
### Getting information about the state of the ChangeSet
|
||||
|
||||
Changesets can exists in three different states:
|
||||
ChangeSets can exists in three different states:
|
||||
|
||||
* `open` No action has been taked on the changeset. Resolves to `publishing` or `reverting`.
|
||||
* `published`: The changeset has published changes to all of its items and its now closed.
|
||||
* `reverted`: The changeset has reverted changes to all of its items and its now closed. (Future API, not supported yet)
|
||||
* `open` No action has been taken on the ChangeSet. Resolves to `publishing` or `reverting`.
|
||||
* `published`: The ChangeSet has published changes to all of its items and its now closed.
|
||||
* `reverted`: The ChangeSet has reverted changes to all of its items and its now closed. (Future API, not supported yet)
|
||||
|
||||
### Getting information about items in a ChangeSet
|
||||
|
||||
Each item in the changeset stores `VersionBefore` and `VersionAfter` fields. As such, they can compute the type of change they are adding to their parent changeset. Change types include:
|
||||
Each item in the ChangeSet stores `VersionBefore` and `VersionAfter` fields. As such, they can compute the type of change they are adding to their parent ChangeSet. Change types include:
|
||||
|
||||
* `created`: This changeset item is for a record that does not yet exist
|
||||
* `modified`: This changeset item is for a record that differs from what is on the live stage
|
||||
* `deleted`: This changeset item will no longer exist when the changeset is published
|
||||
* `none`: This changeset item is exactly as it is on the live stage
|
||||
* `created`: This ChangeSet item is for a record that does not yet exist
|
||||
* `modified`: This ChangeSet item is for a record that differs from what is on the live stage
|
||||
* `deleted`: This ChangeSet item will no longer exist when the ChangeSet is published
|
||||
* `none`: This ChangeSet item is exactly as it is on the live stage
|
||||
|
||||
## Advanced versioning topics
|
||||
|
||||
These topics are targeted towards more advanced use cases that might require developers to extend the behavior of versioning.
|
||||
|
||||
### How versioned DataObjects are tracked in the database
|
||||
|
||||
Depending on whether staging is enabled, one or more new tables will be created for your records. `<class>_versions`
|
||||
@ -472,6 +504,7 @@ automatically joined as required:
|
||||
Because `many_many` relationships create their own sets of records on their own tables, representing content changes to a DataObject, they can therefore be versioned. This is done using the ["through" setting](https://docs.silverstripe.org/en/4/developer_guides/model/relations/#many-many-through-relationship-joined-on-a-separate-dataobject) on a `many_many` definition. This setting allows you to specify a custom DataObject through which to map the `many_many` relation. As such, it is possible to version your `many_many` data by versioning a "through" dataobject. For example:
|
||||
|
||||
```php
|
||||
<?php
|
||||
use SilverStripe\ORM\DataObject;
|
||||
|
||||
class Product extends DataObject
|
||||
@ -492,6 +525,7 @@ class Product extends DataObject
|
||||
```
|
||||
|
||||
```php
|
||||
<?php
|
||||
use SilverStripe\ORM\DataObject;
|
||||
use SilverStripe\Versioned\Versioned;
|
||||
|
||||
@ -515,12 +549,13 @@ class ProductCategory extends DataObject
|
||||
### Writing custom queries to retrieve versioned DataObject
|
||||
|
||||
We generally discourage writing `Versioned` queries from scratch, due to the complexities involved through joining
|
||||
multiple tables across an inherited table scheme (see [Versioned::augmentSQL()](api:SilverStripe\Versioned\Versioned::augmentSQL())). If possible, try to stick to
|
||||
smaller modifications of the generated `DataList` objects.
|
||||
multiple tables across an inherited table scheme (see [Versioned::augmentSQL()](api:SilverStripe\Versioned\Versioned::augmentSQL())). If possible, try to stick to smaller modifications of the generated `DataList` objects.
|
||||
|
||||
Example: Get the first 10 live records, filtered by creation date:
|
||||
|
||||
```php
|
||||
<?php
|
||||
use SilverStripe\Versioned\Versioned;
|
||||
$records = Versioned::get_by_stage('MyRecord', Versioned::LIVE)->limit(10)->sort('Created', 'ASC');
|
||||
```
|
||||
|
||||
@ -544,6 +579,7 @@ and the result is cached due to agressive cache settings (not varying on cookie
|
||||
*app/src/MyObject.php*
|
||||
|
||||
```php
|
||||
<?php
|
||||
use SilverStripe\Core\Injector\Injector;
|
||||
use SilverStripe\ORM\DataObject;
|
||||
use SilverStripe\Versioned\Versioned;
|
||||
@ -578,6 +614,7 @@ class MyObject extends DataObject {
|
||||
*app/src/MyObjectController.php*
|
||||
|
||||
```php
|
||||
<?php
|
||||
use SilverStripe\Control\Controller;
|
||||
use SilverStripe\Control\HTTPRequest;
|
||||
|
||||
@ -612,7 +649,7 @@ class MyObjectController extends Controller
|
||||
|
||||
*app/_config/routes.yml*
|
||||
|
||||
```yml
|
||||
```yaml
|
||||
SilverStripe\Control\Director:
|
||||
rules:
|
||||
'my-objects/$ID': 'MyObjectController'
|
||||
@ -626,8 +663,7 @@ permissions, and avoid exposing unpublished content to your users.
|
||||
|
||||
### Controlling permissions to versioned DataObjects
|
||||
|
||||
By default, `Versioned` will come out of the box with security extensions which restrict
|
||||
the visibility of objects in Draft (stage) or Archive viewing mode.
|
||||
By default, `Versioned` will come out of the box with security extensions which restrict the visibility of objects in Draft (stage) or Archive viewing mode.
|
||||
|
||||
<div class="alert" markdown="1">
|
||||
As is standard practice, user code should always invoke `canView()` on any object before
|
||||
@ -636,6 +672,47 @@ done via user code. This be be achieved either by wrapping `<% if $canView %>` i
|
||||
your template, or by implementing your visibility check in PHP.
|
||||
</div>
|
||||
|
||||
#### Version specific _can_ methods
|
||||
|
||||
Versioned DataObjects get additional permission check methods to verify what oepration a Member is allowed to perform:
|
||||
* `canPublish()`
|
||||
* `canUnpublish()`
|
||||
* `canArchive()`
|
||||
* `canViewVersioned()`.
|
||||
|
||||
These methods accept an optional Member argument. If not provided, they will assume you want to check the permission against the current Member. When performing version operation on behalf of a Member, you'll probably want to use these method to confirm they are authorised,
|
||||
|
||||
```php
|
||||
<?php
|
||||
use SilverStripe\Security\Security;
|
||||
|
||||
$record = MyRecord::get()->byID(99);
|
||||
$member = Security::getCurrentUser();
|
||||
if ($record->canPublish($member)) {
|
||||
$record->publishRecursive();
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
There's also a `canViewStage()` method which can be use to check if a Member can access a specific stage.
|
||||
|
||||
```php
|
||||
<?php
|
||||
use SilverStripe\Versioned\Versioned;
|
||||
|
||||
// Check if `$member` can view the Live version of $record.
|
||||
$record->canViewStage(Versioned::LIVE, $member);
|
||||
|
||||
// Check if `$member` can view the Stage version of $record.
|
||||
$record->canViewStage(Versioned::DRAFT, $member);
|
||||
|
||||
// Both parameters are optional. This is equivalent to calling the method with Versioned::LIVE and
|
||||
// Security::getCurrentUser();
|
||||
$record->canViewStage();
|
||||
```
|
||||
|
||||
#### Customising permissions for a versioned DataObject
|
||||
|
||||
Versioned object visibility can be customised in one of the following ways by editing your user code:
|
||||
|
||||
* Override the `canViewVersioned` method in your code. Make sure that this returns true or
|
||||
@ -645,6 +722,7 @@ Versioned object visibility can be customised in one of the following ways by ed
|
||||
E.g.
|
||||
|
||||
```php
|
||||
<?php
|
||||
use SilverStripe\Versioned\Versioned;
|
||||
use SilverStripe\Security\Permission;
|
||||
use SilverStripe\ORM\DataObject;
|
||||
@ -682,6 +760,7 @@ only be invoked if the object is in a non-published state.
|
||||
E.g.
|
||||
|
||||
```php
|
||||
<?php
|
||||
use SilverStripe\Security\Permission;
|
||||
use SilverStripe\ORM\DataExtension;
|
||||
|
||||
@ -700,6 +779,7 @@ permissions in the `TargetObject.non_live_permissions` config.
|
||||
E.g.
|
||||
|
||||
```php
|
||||
<?php
|
||||
use SilverStripe\Versioned\Versioned;
|
||||
use SilverStripe\ORM\DataObject;
|
||||
|
||||
@ -736,17 +816,13 @@ public function init()
|
||||
|
||||
### Low level write and publication methods
|
||||
|
||||
To move a saved version from one stage to another, call [writeToStage(<stage>)](api:SilverStripe\Versioned\Versioned::writeToStage()) on the
|
||||
object. The process of moving a version to a different stage is also called "publishing". This can be
|
||||
done via one of several ways:
|
||||
SilverStripe will usually call these low level methods for you when you. However if you have specialised needs, you may call them directly.
|
||||
|
||||
To move a saved version from one stage to another, call [writeToStage(<stage>)](api:SilverStripe\Versioned\Versioned::writeToStage()) on the object. This is used internally to publish DataObjects.
|
||||
|
||||
* `copyVersionToStage` which will allow you to specify a source (which could be either a version
|
||||
number, or a stage), as well as a destination stage.
|
||||
`copyVersionToStage($versionID, $stage)` allow you to restore a previous version to a specific stage. This is used internally when performing a rollback.
|
||||
|
||||
|
||||
The current stage is stored as global state on the object. It is usually modified by controllers, e.g. when a preview
|
||||
is initialized. But it can also be set and reset temporarily to force a specific operation to run on a certain stage.
|
||||
The current stage is stored as global state on the `Versioned` object. It is usually modified by controllers, e.g. when a preview is initialized. But it can also be set and reset temporarily to force a specific operation to run on a certain stage.
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
Loading…
Reference in New Issue
Block a user