PHPackages                             silverstripe/controllerpolicy - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Caching](/categories/caching)
4. /
5. silverstripe/controllerpolicy

AbandonedArchivedSilverstripe-vendormodule[Caching](/categories/caching)

silverstripe/controllerpolicy
=============================

SilverStripe module providing a framework for per-controller policies. Includes a caching policy implementation that's more flexible than the Framework's default.

2.2.0(5y ago)1156.8k10[4 issues](https://github.com/silverstripe/silverstripe-controllerpolicy/issues)[1 PRs](https://github.com/silverstripe/silverstripe-controllerpolicy/pulls)1BSD-3-ClausePHP

Since Nov 29Pushed 4y ago4 watchersCompare

[ Source](https://github.com/silverstripe/silverstripe-controllerpolicy)[ Packagist](https://packagist.org/packages/silverstripe/controllerpolicy)[ RSS](/packages/silverstripe-controllerpolicy/feed)WikiDiscussions 2 Synced 1w ago

READMEChangelog (4)Dependencies (3)Versions (17)Used By (1)

Archived
========

[](#archived)

This module has been archived because it has been superseded by functionality within Silverstripe framework.

Please set HTTP cache control headers via [HTTPCacheControlMiddleware](https://docs.silverstripe.org/en/4/developer_guides/performance/http_cache_headers/).

Controller Policy
=================

[](#controller-policy)

Summary
-------

[](#summary)

**This module is deprecated for usage with SilverStripe 3.7+**. The [HTTPCacheControl API](https://docs.silverstripe.org/en/4/developer_guides/performance/http_cache_headers/)in SilverStripe Framework provides a more high-level abstraction of caching behaviour.

Overview
--------

[](#overview)

This module has been designed to provide the ability to configure response policies that apply per specific Controller.

It comes with a small selection of policies for implementing caching:

- `CachingPolicy`: rewrite of SilverStripe default `HTTP::add_cache_headers()`.
- `CustomHeaderPolicy`: allow adding any headers via config system.

An example Page extension PageControlledPolicy is also provided utilising CachingPolicy's ability to customise max-age based on CMS configuration on specific objects.

Installation
------------

[](#installation)

Install using Composer:

```
composer require silverstripe/controllerpolicy ^2

```

**Note:** This version supported SilverStripe 4. For a SilverStripe 3 compatible version please see the [1.x release line](https://github.com/silverstripe/silverstripe-controllerpolicy/tree/1).

Policies
--------

[](#policies)

### Simple policy

[](#simple-policy)

Let's say we want to apply a caching header of max-age 300 to the HomePage only. This module comes with a `CachingPolicy` which by implementing the `ControllerPolicy` interface can be applied to anything derived from `Controller`. This class can also be configured to specify the custom max-age via (injected) properties.

Using this policy is done via your project-specific **config.yml**. We configure the pseudo-singleton via Dependency Injection and apply it directly to `HomePage_Controller`:

```
SilverStripe\Core\Injector\Injector:
  StandardCachingPolicy:
    class: SilverStripe\ControllerPolicy\Policies\CachingPolicy
    properties:
      CacheAge: 300
HomePageController:
  dependencies:
    Policies: '%$StandardCachingPolicy'
```

Every policy will set headers on top of the default framework's `HTTP::add_cache_headers`, which is exactly what we want. This allows us to for example customise the `Vary` headers per policy, which were previously hardcoded. It also allows us to configure these settings on a per-controller basis, rather than a global default.

### Ignoring domains

[](#ignoring-domains)

If you wish to exclude some domains from the policies completely, you can do the following:

```
SilverStripe\ControllerPolicy\ControllerPolicyMiddleware:
  ignore_regex_domains:
    - '/.*\.uat.server.com$/'
```

This could be useful for example if you wish to disable caching on test servers, or if you are doing aggressive caching and want your editors to see changed resources immediately.

### Vary headers

[](#vary-headers)

`CachingPolicy` also allows customisation of `Vary` headers through the config system:

```
SilverStripe\Core\Injector\Injector:
  StandardCachingPolicy:
    class: SilverStripe\ControllerPolicy\Policies\CachingPolicy
    properties:
      CacheAge: 300
      Vary: 'Cookie, X-Forwarded-Protocol, Accept-Language'
```

Any URL which content depends on an impulse from the visitor should use Vary header to encode this dependency, otherwise caches might serve wrong content to the wrong user (possibly even confidential data!).

Here is a table of some more obvious `Vary` headers. `CachingPolicy` uses a relatively safe combination of `Cookie, X-Forwarded-Protocol`. Keep in mind the more of these you specify, the more partitioned the cache, which will nullify potential gains. Use as few as you are confident with.

Vary onDescriptionCache partitioning impactAccept-EncodingVary on content deflate method - Apache will deliver different content depending on accepted encoding. Automatically added by Apache mod\_header.lowCookieVary on user session. Pretty much partitions the responses into generic and personalised. Note that for this to work well, the cache needs to purge frontend-only cookies such as \_\_utma from the requests. A sensible addition.lowX-Forwarded-ProtocolVary on protocol such as http or https - use when the cache is behind a reverse-proxy, as there is often a difference in "BaseURL" which is not reflected in the URL the cache sees. A sensible addition.lowX-Forwarded-ProtoA variation on X-Forwarded-Protocol, choose one appropriate to your reverse-proxy.lowAcceptVary on the response format. Some URLs, especially the API endpoints, can produce different output depending on what the user accepts: i.e. JSON vs. XML. Avoid if possible, and instead encode the content type in the URL.mediumAccept-LanguageVary on the accepted language, if you are providing different language content depending on the user browser's setting. Avoid if possible, and instead encode the language in the URL.mediumUser-AgentVary on the user's device. There is so many user strings around this will effectively disable your cache. Avoid at all costs, and instead use responsive themes.extreme### Overriding policies

[](#overriding-policies)

If you apply a policy to a certain `Controller` it will apply to all inheriting controllers too. For example if we have `FooPageController extends PageController` then the `PageController` policy will also affect the `FooPageController`.

You can break that chain easily by applying a policy to the inheriting controller as long as you are not using arrays for configuration (which you ordinarily wouldn't be - but see the "Complex policies" chapter below):

```
FooPageController:
  dependencies:
    Policies: null
```

In SilverStripe 4 the config system allows you to set falsey values, which you can utilise to unset previously defined policies for a controller, or globally. This is useful for example for GET-based multi-step forms (via the [silverstripe-multiform](https://github.com/silverstripe/silverstripe-multiform)) module, where steps are traversed via GET requests, and URIs don't differ - hence preventing your from actually progressing through the form.

Note that you can also use any other policy to override the existing one - you don't only have to unset it.

### PageControlledPolicy

[](#pagecontrolledpolicy)

Here is an example of how to implement CMS capability to override the max-age per specific page. In your config file put the following statements:

```
SilverStripe\Core\Injector\Injector:
  GeneralCachingPolicy:
    class: SilverStripe\ControllerPolicy\Policies\CachingPolicy
    properties:
      CacheAge: 900

PageController:
  dependencies:
    Policies: '%$GeneralCachingPolicy'

Page:
  extensions:
    - SilverStripe\ControllerPolicy\PageControlledPolicy
```

Here, applying the `PageControlledPolicy` extension to the `Page` results in a new "MaxAge" field being written into the DB, and a new tab available ("Caching") which lets the an administrative user tweak the cache max-age header (denominated in minutes).

### Complex policies via array-merging

[](#complex-policies-via-array-merging)

This example illustrates the usage of array-merging capability of the config system, which will enable you to simulate policy inheritance that will reflect your class diagram.

In this example we want to configure a global setting consisting of two policies, one setting the max-age to 300, and second to configure custom header. Then we want to add more specific policy for the home page max-age, while keeping the custom header. Here is how to achieve this using the config system:

```
SilverStripe\Core\Injector\Injector:
  ShortCachingPolicy:
    class: SilverStripe\ControllerPolicy\Policies\CachingPolicy
    properties:
      CacheAge: 300
  LongCachingPolicy:
    class: SilverStripe\ControllerPolicy\Policies\CachingPolicy
    properties:
      CacheAge: 3600
  CustomPolicy:
     class: SilverStripe\ControllerPolicy\Policies\CustomHeaderPolicy
     properties:
       Headers:
         Custom-Header: "Hello"

HomePageController:
  dependencies:
    Policies:
      LongCachingPolicy: '%$LongCachingPolicy'

PageController:
  dependencies:
    Policies:
      ShortCachingPolicy: '%$ShortCachingPolicy'
      CustomPolicy: '%$CustomPolicy'
```

Outcome of the array merging for the home page will be as follows:

- LongCachingPolicy
- ShortCachingPolicy
- CustomPolicy

We handle this array in reverse order, meaning that by default the top policy (most specific Controller) will override the others. This does not mean many Controller policies will trigger - rather, one Controller will apply a merged set.

Caution: you can either use the array syntax, or value syntax. Choose what's easier. If using an array then we recommend giving each value a key as well, which will allow you to unset previously defined values in other config blocks, which would otherwise not be possible.

### Developer notes

[](#developer-notes)

For advanced usage of policies (e.g. returning a 304 header early) you can look at the `ControllerPolicyMiddleware::process` method. In such a situation, your custom policy could replace the HTTPResponse `$response` argument from its `applyToResponse` method with a new HTTPResponse with a 304 code.

Another thing is that the policies will be applied in the Controller order of initialisation, so if multiple Controllers are invoked the latter will override the former. HOWEVER this is very unlikely and has nothing to do with the inheritance of classes. This relates to how the Controller stack is invoked in SilverStripe. The extension point in `ControllerPolicyApplicator` has been chosen such that the `ModelAsController` and `RootURLController` do not trigger application of policies, and it is expected that only one controller will trigger the policy.

###  Health Score

38

—

LowBetter than 85% of packages

Maintenance13

Infrequent updates — may be unmaintained

Popularity32

Limited adoption so far

Community26

Small or concentrated contributor base

Maturity71

Established project with proven stability

 Bus Factor2

2 contributors hold 50%+ of commits

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~153 days

Recently: every ~79 days

Total

16

Last Release

1524d ago

Major Versions

1.0.x-dev → 2.0.02018-01-17

1.x-dev → 2.1.02018-07-25

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/654636?v=4)[Aaron Carlino](/maintainers/unclecheese)[@unclecheese](https://github.com/unclecheese)

![](https://www.gravatar.com/avatar/b0cba8b534e20e6ab4fff555a97b237a18436ebca1446fc0b29c8a8b504038b9?d=identicon)[GuySartorelli](/maintainers/GuySartorelli)

![](https://avatars.githubusercontent.com/u/111025?v=4)[Ingo Schommer](/maintainers/chillu)[@chillu](https://github.com/chillu)

![](https://www.gravatar.com/avatar/a25bc04c5720a36869d5a39c6449dde7eb43e19b7c8e666d5f632d6a9ab440b1?d=identicon)[emteknetnz](/maintainers/emteknetnz)

![](https://www.gravatar.com/avatar/be6648e60fbab6f70bfc34dd8c14259562d28a47510a934ea9c01fe98633f3c2?d=identicon)[sminnee](/maintainers/sminnee)

![](https://avatars.githubusercontent.com/u/1168676?v=4)[Maxime Rainville](/maintainers/maxime-rainville)[@maxime-rainville](https://github.com/maxime-rainville)

---

Top Contributors

[![mateusz](https://avatars.githubusercontent.com/u/118653?v=4)](https://github.com/mateusz "mateusz (35 commits)")[![robbieaverill](https://avatars.githubusercontent.com/u/5170590?v=4)](https://github.com/robbieaverill "robbieaverill (27 commits)")[![chillu](https://avatars.githubusercontent.com/u/111025?v=4)](https://github.com/chillu "chillu (8 commits)")[![emteknetnz](https://avatars.githubusercontent.com/u/4809037?v=4)](https://github.com/emteknetnz "emteknetnz (5 commits)")[![dnsl48](https://avatars.githubusercontent.com/u/9313746?v=4)](https://github.com/dnsl48 "dnsl48 (3 commits)")[![dhensby](https://avatars.githubusercontent.com/u/563596?v=4)](https://github.com/dhensby "dhensby (2 commits)")[![NightJar](https://avatars.githubusercontent.com/u/778003?v=4)](https://github.com/NightJar "NightJar (2 commits)")[![colinedmz](https://avatars.githubusercontent.com/u/12993019?v=4)](https://github.com/colinedmz "colinedmz (1 commits)")

---

Tags

silverstripecachingPolicy

###  Code Quality

Code StylePHP\_CodeSniffer

### Embed Badge

![Health badge](/badges/silverstripe-controllerpolicy/health.svg)

```
[![Health](https://phpackages.com/badges/silverstripe-controllerpolicy/health.svg)](https://phpackages.com/packages/silverstripe-controllerpolicy)
```

###  Alternatives

[silverstripe/staticpublishqueue

Static publishing queue to create static versions of pages for enhanced performance and security

45135.4k4](/packages/silverstripe-staticpublishqueue)[tractorcow/silverstripe-dynamiccache

FORK OF Silverstripe module for simple on the fly caching of dynamic content

3916.0k2](/packages/tractorcow-silverstripe-dynamiccache)[pstaender/silverstripe-redis-cache

Enables Redis cache for SilverStripe

1199.1k](/packages/pstaender-silverstripe-redis-cache)[silverstripe-terraformers/keys-for-cache

Silverstripe cache key management

1726.6k](/packages/silverstripe-terraformers-keys-for-cache)[steadlane/silverstripe-cloudflare

This module aims to relieve the stress of using Cloudflare caching with any SilverStripe project. Adds extension hooks that clears Cloudflare's cache for a specific page when that page is published or unpublished.

243.7k](/packages/steadlane-silverstripe-cloudflare)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
