Docs for new versioned get param behaviour

See https://github.com/silverstripe/silverstripe-cms/issues/1578
This commit is contained in:
Ingo Schommer 2018-03-20 16:48:36 +13:00
parent 0fe56732af
commit e6ff8bc681
3 changed files with 134 additions and 11 deletions

View File

@ -554,10 +554,93 @@ public function init()
### Controllers
The current stage for each request is determined by `VersionedRequestFilter` before any controllers initialize, through
`Versioned::choose_site_stage()`. It checks for a `Stage` GET parameter, so you can force a draft stage by appending
`?stage=Stage` to your request. The setting is "sticky" in the PHP session, so any subsequent requests will also be in
draft stage.
The current stage for each request is determined by `VersionedHTTPMiddleware` before any controllers initialize, through
`Versioned::choose_site_stage()`. It checks for a `stage` GET parameter, so you can force a draft stage by appending
`?stage=Stage` to your request.
Since SilverStripe 4.2, the current stage setting is no longer "sticky" in the session.
Any links presented on the view produced with `?stage=Stage` need to have the same GET parameters in order
to retain the stage. If you are using the `SiteTree->Link()` and `Controller->Link()` methods,
this is automatically the case for page links, controller links and form actions.
You can opt for a session base stage setting through the `Versioned.use_session` setting.
Warning: This can lead to leaking of unpublished information, if a live URL is viewed in draft mode,
and the result is cached due to agressive cache settings (not varying on cookie values).
*mysite/src/MyObject.php*
```php
use SilverStripe\Core\Injector\Injector;
use SilverStripe\ORM\DataObject;
use SilverStripe\Versioned\Versioned;
use SilverStripe\Control\Controller;
class MyObject extends DataObject {
private static $extensions = [
Versioned::class
];
public function Link($action = null)
{
return Injector::inst()->get(MyObjectController::class)->Link($this->ID);
}
public function CustomLink($action = null)
{
$link = Controller::join_links('custom-route', $this->ID, '?rand=' . rand());
$this->extend('updateLink', $link, $action); // updates $link by reference
return $link;
}
}
```
*mysite/src/MyObjectController.php*
```php
use SilverStripe\Control\Controller;
use SilverStripe\Control\HTTPRequest;
use SilverStripe\Versioned\VersionedRequestHandlerExtension;
class MyObjectController extends Controller
{
private static $extensions = [
VersionedRequestHandlerExtension::class
];
public function index(HTTPRequest $request)
{
$obj = MyObject::get()->byID($request->param('ID'));
if (!$obj) {
return $this->httpError(404);
}
// Construct view
$html = sprintf('<a href="%s">%s</a>', $obj->Link(), $obj->ID);
return $html;
}
public function Link($action = null)
{
// Construct link with graceful handling of GET parameters
$link = Controller::join_links('my-objects', $action, '?rand=' . rand());
// Allow Versioned and other extension to update $link by reference
$this->extend('updateLink', $link, $action);
return $link;
}
}
```
*mysite/_config/routes.yml*
```yml
SilverStripe\Control\Director:
rules:
'my-objects/$ID': 'MyObjectController'
```
<div class="alert" markdown="1">
The `choose_site_stage()` call only deals with setting the default stage, and doesn't check if the user is

View File

@ -159,20 +159,23 @@ For more information about templates, inheritance and how to render into views,
## Link
Each controller should define a `Link()` method. This should be used to avoid hard coding your routing in views etc.
Each controller should define a `Link()` method. This should be used to avoid hard coding your routing in views,
as well as give other features in SilverStripe the ability to influence link behaviour.
**mysite/code/controllers/TeamController.php**
```php
public function Link($action = null)
{
return Controller::join_links('teams', $action);
// Construct link with graceful handling of GET parameters
$link = Controller::join_links('teams', $ction);
// Allow Versioned and other extension to update $link by reference.
$this->extend('updateLink', $link, $action);
return $link;
}
```
<div class="info" markdown="1">
The [Controller::join_links()](api:SilverStripe\Control\Controller::join_links()) is optional, but makes `Link()` more flexible by allowing an `$action` argument, and concatenates the path segments with slashes. The action should map to a method on your controller.
</div>
```
## Related Lessons
* [Controller actions/DataObjects as pages](https://www.silverstripe.org/learn/lessons/v4/controller-actions-dataobjects-as-pages-1)

View File

@ -0,0 +1,37 @@
# 4.2.0
## Overview {#overview}
* Disable session-based stage setting in `Versioned` (see [#1578](https://github.com/silverstripe/silverstripe-cms/issues/1578))
## Upgrading {#upgrading}
### Disable session-based stage setting
When viewing a versioned record (usually pages) in "draft" mode,
SilverStripe used to record this mode in the session for further requests.
This has the advantage of transparently working on XHR and API requests,
as well as authenticated users navigating through other views.
These subsequent requests no longer carried an explicit `stage` query parameter,
which meant the same URL might show draft or live content depending on your session state.
While most HTTP caching layers deal gracefully with this variation by disabling
any caching when a session cookie is present, there is a small chance
that draft content is exposed to unauthenticated users for the lifetime of the cache.
Due to this potential risk for information leakage,
we have decided to only rely on the `stage` query parameter.
If you are consistently using the built-in `SiteTree->Link()`
and `Controller->Link()` methods to get URLs, this change likely won't affect you.
If you are manually concatenating URLs to SilverStripe controllers
rather than through their `Link()` methods (in custom PHP or JavaScript),
or have implemented your own `Link()` methods on controllers exposing
versioned objects, you'll need to check your business logic.
Alternatively, you can opt-out of this security feature via YAML configuration:
```yml
SilverStripe\Versioned\Versioned:
use_session: true
```