The Optimizely Content Management System (CMS) user interface makes extensive use of the object store API available in the Dojo Toolkit.
## Implementation in the CMS user interface
To create an environment where object store data can be shared across components with minimal dependencies, we have created a `epi.shell.store.Registry
` object. This object is responsible for maintaining a dictionary of key and object store pairs.
For example:
It also has a convenience method for creating `epi.shell.store.Patch
`able stores.
An `epi.shell.store.Patchable
` is essentially an `epi.shell.store.JsonRest
` store which is wrapped with both cache and observable functionality, and having additional functionality to refresh and patch particular items in the store.
**patch** – Updates an item in the object store cache and note on the server. The intention of this is to minify requests to the server but still populate updates to the user interface via the store.
**refresh** – Will cause the item to be dropped from the cache store, if it exists, and the latest version retrieved from the server and put back into the cache.
## Dependencies between object stores
You can have multiple object stores that have dependencies on each other. If you have an _authoritative_ store with a subset of data stores as _dependents_, you can make updated to the authoritative store on the client and push those changes to the dependent stores with the patch method so they do not query the server again.
For example, the content data store contains all the content (and associated property values) that was viewed or edited, which can be a lot of information. Widgets, like the page tree, need a subset of information placed in a separate store that depends on the content data store. You create this dependency using the `addDependentStore
` method as shown in the following example:
When you call patch or refresh on the authoritative store, changes also are populated through to the dependent store.
## Create a REST store
### Server
On the server side, the store controller needs to be decorated with a `RestStoreAttribute
`Â that has the store's name as argument. This name will be used as part of the route to the store. The store should also extend the `RestControllerBase
` class since this adds support for converting responses to JSON using the serializers configured in CMS. For example:
Methods on the store should be named after the HTTP method for which they are created. For example:
### Client
On the client side, store instances should be created from the epi/shell/store/JsonRest class as this extends the standard REST store included in dojo with validation for cross-site request forgery.
When the REST store is created a route to the server side controller will need to be provided. The epi/routes module provides helper methods for calculating the route based on the store name and package/module area it belongs to. For example:
Having calculated the route to the controller, a REST store can then be created as follows:
The store API provided by Dojo has methods that map easily to the standard CRUD operations that a REST store may perform. In the case of the REST store, these methods will perform XHR requests against the server controller. The request and response bodies are expected to be JSON formatted.
See the [dojo/store/JsonRest](🔗) implementation for more detailed information.
### Observable
The dojo/store/Observable decorates a store by adding an observe method on the results object returned by the query method. This can be used to monitor the store for changes that may affect the results returned by the query. This means that when an item is added, updated, or removed from the store, then the observer is notified if the modified item matches the observer's query. A store can be decorated as follows:
## Use the stores
If you are creating a new store to use across multiple components, use epi.shell.store.Registry to create and register your store in an initialization module. Then you can retrieve it when needed and request the wanted store.
When you have a store, you can initialize the view for your component and look for other areas of the application that trigger an update in the component’s view. For example, the following page version component requests versions for a particular page from the server and listens to any changes to update the details in the list when an edit is made to the version.
If another part of the application calls add, put, delete, refresh, or patch and the data being modified matches the query, then the `onChange
` method is triggered.
## Available object stores
Store Key | Description |
**epi.shell.context** | Used by the context manager to retrieve the current context. Is a cache of current and previous contexts. |
**epi.shell.profile** | Stores information about the current user profile. |
**epi.shell.metadata** | Contains metadata for an object or type. This is used to set up editing of content. |
**epi.cms.contentdata** | Contains content items such as pages and blocks with defined properties. |
**epi.cms.content.light** | Contains a light version of content, specifically containing properties needed for the page tree. |
**epi.cms.category** | Contains the CMS categories. |
**epi.cms.contentversion** | Contains information about versions of a content item. |