4 Spaces is an API module intended to make configuration options generally
5 avaliable only at the sitewide level to be configurable and overridden by
6 individual "spaces" on a Drupal site. It has been described as:
8 - A way to make one Drupal site act like several sites
9 - A way to provide much more configurable, full-feature Organic Groups or user
11 - A generalized API for contextual configuration
14 Requirements & compatibility
15 ---------------------------
16 Use of spaces requires
18 - CTools: http://drupal.org/project/ctools
19 - Features: http://drupal.org/project/features
21 However, you will want the following modules in order to build or use reasonably
22 cool features with Spaces and take advantage of most space types:
24 - PURL: http://drupal.org/project/purl
25 - Context 3.x: http://drupal.org/project/context
26 - Strongarm 2.x: http://drupal.org/project/strongarm
27 - Views 2.x: http://drupal.org/project/views
29 Out of the box, Spaces provides integration modules for:
32 - Taxonomy: `spaces_taxonomy`
36 Coming from Spaces 2.x?
37 -----------------------
38 The Spaces 3.x branch makes significant departures from many of the concepts
39 in the 2.x branch. Here is a non-exhaustive list of important changes:
41 - Removed strict PURL dependency. Spaces can now be made active through means
42 other than a PURL provider (see `spaces_user_init()`).
43 - Usage of CTools plugins API and export API.
44 - `spaces_customizers()` and `spaces_settings()` have been replaced with a
45 general configuration override system using object controllers (more on this
48 If you are upgrading from Spaces 2.x, prepare for a rocky ride. Update scripts
49 are included to migrate as cleanly as possible from 2.x to 3.x but any custom
50 settings you have created will need to be managed manually. The update scripts
51 leave the `spaces_settings` table intact for this reason.
53 Here is a rough list of steps to consider when upgrading from 2.x to 3.x:
57 3. Upgrade your features to Context 3, Strongarm 2, etc.
58 4. Have you implemented any custom 2.x space types? You need to migrate them,
59 see `API.txt` and `spaces.api.php`.
60 5. Have you implemented any custom 2.x spaces settings? You need to migrate
61 them to use standard Drupal variables and `system_settings_form()` (see
62 the `features_test` module for an example).
63 6. Have you implemented any custom 2.x spaces customizers? The concept may not
64 transfer cleanly to Spaces 3, or if it does, it will probably make the most
65 sense as a custom controller.
68 Core concept behind Spaces 3
69 ----------------------------
70 Spaces 3 has been built outwards from the basic idea that it should be possible
71 for a "space" to override the values of a Drupal object that would otherwise
72 have a single, sitewide value. For our purposes
74 A space is a configuration environment that is triggered or made active by
75 some condition. For example, a "user space" might be made active when
76 viewing a user's profile. Once that user space is active, any customization
77 that user has made override sitewide values.
79 An object is a Drupal site building or configuration structure. Examples
80 include variables, contexts and views. Not included: nodes, users, taxonomy
81 terms, other "content".
83 Let's first look at storage of overridden values. Spaces stores all of its
84 overrides in the `spaces_overrides` table. Here is a sample row:
86 +------+----+-------------+------------------+------------------------+
87 | type | id | object_type | object_id | value |
88 +------+----+-------------+------------------+------------------------+
89 | og | 14 | variable | spaces_preset_og | s:13:"private_group"; |
90 +------+----+-------------+------------------+------------------------+
92 This row describes an overridde when a certain Organic Group (node 14) is
93 active. In particular, the variable `spaces_preset_og` has the value
94 `private_group` when this space is active. More generally, `spaces_overrides`
95 can store any value to override the default of an object, described by
96 (`object_type`, `object_id`), for any space, described by (`type`, `id`).
98 In practice, this means that when node 14 is active
100 variable_get('spaces_preset_og', NULL);
101 // returns "private_group"
103 While when node 14 is not active
105 variable_get('spaces_preset_og', NULL);
106 // returns NULL or sitewide value
109 Controllers & contextuality
110 ---------------------------
111 The example above shows that when a space is active you need to change some
112 basic assumptions about how Drupal works. In particular, spaces introduces
113 contextuality to settings and configuration.
115 Per-space overrides are handled by controllers. Controllers are CTools plugins
116 that manage retrieval and storage of overrides for a given object type. For
117 example, spaces comes with a variable controller and context controller. Each
118 controller should interface with its object's API at a retrieval point and at
119 a storage or save point.
121 +-------------------------------------+-----------------------------------+
122 |Drupal integration point |Controller method |
123 +-------------------------------------+-----------------------------------+
124 |hook_context_reaction_fetch_alter() |$space->controllers->context->get()|
125 |spaces_form_context_ui_editor_alter()|$space->controllers->context->set()|
126 +-------------------------------------+-----------------------------------+
128 Whenever a context's reaction value is fetched, the context controller's `get()`
129 method is invoked retrieving a value specific to the active space.
131 The controller's save integration point is triggered through a custom submit
132 handler to the context editor form through a `hook_form_alter()`.
134 Currently, our rule of thumb is that while retrieval may be contextual, actual
135 save API functions should not be overridden. In general, you should always be
136 able to retrieve and save the original values of an object in addition to
137 manipulating space overrides from the API.
140 Presets, levels of configuration
141 --------------------------------
142 Spaces presets are sets of configuration that apply to whole sets of spaces. For
143 example you may not want to make the same set of customizations for every new
144 user you add to the site. You can use a preset like "member" or "guest" to
145 capture a variety of settings and have new users use one of the presets.
147 With presets in the picture, `variable_get('foo', NULL)` can actually return one
148 of three possible values when a space is active:
150 1. `space`: is the override value for the active space. If the active space has
151 saved an override for `foo`, this is what you will get.
152 2. `preset` is the override value for the preset. If the active space has not
153 saved a value for `foo` the variable controller will fall back to the preset
154 if it has a value for `foo`.
155 3. `original` is the sitewide, canonical value for `foo`. If neither the space
156 nor the preset have an override for `foo`, you will get the sitewide value
157 like a call to `variable_get()` when no spaces are active.
159 This cascading of values applies to all object types with a spaces controller.
163 This architecture *strongly* implies that it could or should be possible to
164 stack configuration overrides n levels rather than the current fixed number. In
165 such a scenario, presets would themselves become stacked spaces, and the picture
166 would become even simpler:
168 - Fixed stacking model (where > can be read as "inherits from"):
170 space > preset > original
172 - Arbitrary stacking model (where space 0 is the preset space)
174 space n > space n-1 > ... > space 1 > space 0 > original
176 This model is very attractive but requires some serious study before it can be
177 realized. Spaces 3 currently implements the fixed stacking model.
180 Managing and editing presets
181 ----------------------------
182 The Spaces UI module allow provides the facility to manage presets. This
183 includes creating new presets, reverting overrides and editing preset metadata.
184 There is not a single UI for creating and editing all the elements of a
185 spaces preset. Presets can contain many settings about which the spaces module
186 actually knows nearly nothing, making it impossible to provide a useful
187 interface. Presets are meant to be edited through actual instance of a space.
189 For example, to change the features a preset has enabled you would:
191 1. Goto, or create, a space which uses the preset you wish to change.
192 2. Set the space to have the desired set of enabled feature.
193 3. Goto the "overrides" page (generally rendered as a tab) for the space.
194 4. Click the checkbox for the `space_menu_items` variable.
195 5. Click "Save to preset".
197 At this point any new groups created with this same preset will have the
198 configuration you've just specified. If the preset you've edited is provided
199 in code the interface at "admin > site building > spaces" (`admin/build/space`)
200 will show them as overriden.
205 There is quite a bit of functionality in Spaces that does not fit neatly into
206 the picture of each space as a "configuration override environemnt." This
207 functionality has survived to support the users and code implemented around
208 existing user stories that spaces currently serves. In the future the
209 functionality may be further abstracted out so that Spaces can play a much more
210 minimal and possibly flexible role.
212 1. Features can be set to a state per space (defaults to enabled/disabled, but
213 overridable by extending classes) that determine their behavior within a space.
214 In particular, features tend to hide or show menu items, alter access to parts
215 of the menu tree, etc.
216 2. Access to a space has several levels - space types can control degrees of
217 admin access, feature access and basic access to a space.
218 3. Spaces can determine routing of certain pages - for example, some nodes may
219 only be viewed when a certain space is active or a certain administrative page
220 may drop all active spaces.
222 Note that none of these user stories are necessarily implied by the
223 configuration override framework introduced above.
228 Spaces integrates with the Features built using the Features module. Features
229 that are compatible with spaces must declare themselves as such by including the
230 `spaces[types]` key in their `.info` file.
232 For example a "MyBlog" module may include the following snippet in
233 `myblog.info` to declare that is is spaces-enabled;
238 spaces[types] = "all"
240 `spaces[types]` may be declared to be one of the following values:
242 - `all` indicates that this feature is compatible with all space types.
243 - an array of space types where this feature may be enabled. Note that you may
244 also include the faux space type `site` in this array, indicating that this
245 feature may be enabled even and/or possibly only when no spaces are active.
247 For example, if my feature `my_cool_gallery` should only be available when
248 outside of any spaces, I would use the following entry:
250 spaces[types][] = "site"
252 If it can be enabled both outside of any spaces and inside of user spaces, but
253 not group spaces, I could use:
255 spaces[types][] = "site"
256 spaces[types][] = "user"
261 Settings can be defined for spaces features simply as Drupal variables by
262 implementing a `system_settings_form()` at `features/[my-feature]`. If spaces
263 finds such a page defined by your feature, it will expose it as a link in
264 the features form for any of the space types where the feature is enabled.
267 Creating your own space types or extending existing ones
268 --------------------------------------------------------
269 Please see `API.txt` for instructions on how you can create your own space types
270 or use your own class to extend or replace one of the existing classes.
275 - alex_b (Alex Barth)
276 - jmiccolis (Jeff Miccolis)