You are here

README.txt in Spaces 7

Spaces 3.x
----------
Spaces is an API module intended to make configuration options generally
avaliable only at the sitewide level to be configurable and overridden by
individual "spaces" on a Drupal site. It has been described as:

- A way to make one Drupal site act like several sites
- A way to provide much more configurable, full-feature Organic Groups or user
  homepages
- A generalized API for contextual configuration


Requirements & compatibility
---------------------------
Use of spaces requires

- CTools: http://drupal.org/project/ctools
- Features: http://drupal.org/project/features

However, you will want the following modules in order to build or use reasonably
cool features with Spaces and take advantage of most space types:

- PURL: http://drupal.org/project/purl
- Context 3.x: http://drupal.org/project/context
- Strongarm 2.x: http://drupal.org/project/strongarm
- Views 2.x: http://drupal.org/project/views

Out of the box, Spaces provides integration modules for:

- User: `spaces_user`
- Taxonomy: `spaces_taxonomy`
- OG: `spaces_og`


Coming from Spaces 2.x?
-----------------------
The Spaces 3.x branch makes significant departures from many of the concepts
in the 2.x branch. Here is a non-exhaustive list of important changes:

- Removed strict PURL dependency. Spaces can now be made active through means
  other than a PURL provider (see `spaces_user_init()`).
- Usage of CTools plugins API and export API.
- `spaces_customizers()` and `spaces_settings()` have been replaced with a
  general configuration override system using object controllers (more on this
  below).

If you are upgrading from Spaces 2.x, prepare for a rocky ride. Update scripts
are included to migrate as cleanly as possible from 2.x to 3.x but any custom
settings you have created will need to be managed manually. The update scripts
leave the `spaces_settings` table intact for this reason.

Here is a rough list of steps to consider when upgrading from 2.x to 3.x:

1. Backup everything.
2. Run `update.php`.
3. Upgrade your features to Context 3, Strongarm 2, etc.
4. Have you implemented any custom 2.x space types? You need to migrate them,
   see `API.txt` and `spaces.api.php`.
5. Have you implemented any custom 2.x spaces settings? You need to migrate
   them to use standard Drupal variables and `system_settings_form()` (see
   the `features_test` module for an example).
6. Have you implemented any custom 2.x spaces customizers? The concept may not
   transfer cleanly to Spaces 3, or if it does, it will probably make the most
   sense as a custom controller.


Core concept behind Spaces 3
----------------------------
Spaces 3 has been built outwards from the basic idea that it should be possible
for a "space" to override the values of a Drupal object that would otherwise
have a single, sitewide value. For our purposes

  A space is a configuration environment that is triggered or made active by
    some condition. For example, a "user space" might be made active when
    viewing a user's profile. Once that user space is active, any customization
    that user has made override sitewide values.

  An object is a Drupal site building or configuration structure. Examples
    include variables, contexts and views. Not included: nodes, users, taxonomy
    terms, other "content".

Let's first look at storage of overridden values. Spaces stores all of its
overrides in the `spaces_overrides` table. Here is a sample row:

    +------+----+-------------+------------------+------------------------+
    | type | id | object_type | object_id        | value                  |
    +------+----+-------------+------------------+------------------------+
    | og   | 14 | variable    | spaces_preset_og | s:13:"private_group";  |
    +------+----+-------------+------------------+------------------------+

This row describes an overridde when a certain Organic Group (node 14) is
active. In particular, the variable `spaces_preset_og` has the value
`private_group` when this space is active. More generally, `spaces_overrides`
can store any value to override the default of an object, described by
(`object_type`, `object_id`), for any space, described by (`type`, `id`).

In practice, this means that when node 14 is active

    variable_get('spaces_preset_og', NULL);
    // returns "private_group"

While when node 14 is not active

    variable_get('spaces_preset_og', NULL);
    // returns NULL or sitewide value


Controllers & contextuality
---------------------------
The example above shows that when a space is active you need to change some
basic assumptions about how Drupal works. In particular, spaces introduces
contextuality to settings and configuration.

Per-space overrides are handled by controllers. Controllers are CTools plugins
that manage retrieval and storage of overrides for a given object type. For
example, spaces comes with a variable controller and context controller. Each
controller should interface with its object's API at a retrieval point and at
a storage or save point.

    +-------------------------------------+-----------------------------------+
    |Drupal integration point             |Controller method                  |
    +-------------------------------------+-----------------------------------+
    |hook_context_reaction_fetch_alter()  |$space->controllers->context->get()|
    |spaces_form_context_ui_editor_alter()|$space->controllers->context->set()|
    +-------------------------------------+-----------------------------------+

Whenever a context's reaction value is fetched, the context controller's `get()`
method is invoked retrieving a value specific to the active space.

The controller's save integration point is triggered through a custom submit
handler to the context editor form through a `hook_form_alter()`.

Currently, our rule of thumb is that while retrieval may be contextual, actual
save API functions should not be overridden. In general, you should always be
able to retrieve and save the original values of an object in addition to
manipulating space overrides from the API.


Presets, levels of configuration
--------------------------------
Spaces presets are sets of configuration that apply to whole sets of spaces. For
example you may not want to make the same set of customizations for every new
user you add to the site. You can use a preset like "member" or "guest" to
capture a variety of settings and have new users use one of the presets.

With presets in the picture, `variable_get('foo', NULL)` can actually return one
of three possible values when a space is active:

1. `space`: is the override value for the active space. If the active space has
    saved an override for `foo`, this is what you will get.
2. `preset` is the override value for the preset. If the active space has not
    saved a value for `foo` the variable controller will fall back to the preset
    if it has a value for `foo`.
3. `original` is the sitewide, canonical value for `foo`. If neither the space
    nor the preset have an override for `foo`, you will get the sitewide value
    like a call to `variable_get()` when no spaces are active.

This cascading of values applies to all object types with a spaces controller.

**Aside**

This architecture *strongly* implies that it could or should be possible to
stack configuration overrides n levels rather than the current fixed number. In
such a scenario, presets would themselves become stacked spaces, and the picture
would become even simpler:

- Fixed stacking model (where > can be read as "inherits from"):

        space > preset > original

- Arbitrary stacking model (where space 0 is the preset space)

        space n > space n-1 > ... > space 1 > space 0 > original

This model is very attractive but requires some serious study before it can be
realized. Spaces 3 currently implements the fixed stacking model.


Managing and editing presets
----------------------------
The Spaces UI module allow provides the facility to manage presets. This
includes creating new presets, reverting overrides and editing preset metadata.
There is not a single UI for creating and editing all the elements of a
spaces preset. Presets can contain many settings about which the spaces module
actually knows nearly nothing, making it impossible to provide a useful
interface. Presets are meant to be edited through actual instance of a space.

For example, to change the features a preset has enabled you would:

1. Goto, or create, a space which uses the preset you wish to change.
2. Set the space to have the desired set of enabled feature.
3. Goto the "overrides" page (generally rendered as a tab) for the space.
4. Click the checkbox for the `space_menu_items` variable.
5. Click "Save to preset".

At this point any new groups created with this same preset will have the
configuration you've just specified. If the preset you've edited is provided
in code the interface at "admin > site building > spaces" (`admin/build/space`)
will show them as overriden.


Other functionality
-------------------
There is quite a bit of functionality in Spaces that does not fit neatly into
the picture of each space as a "configuration override environemnt." This
functionality has survived to support the users and code implemented around
existing user stories that spaces currently serves. In the future the
functionality may be further abstracted out so that Spaces can play a much more
minimal and possibly flexible role.

1. Features can be set to a state per space (defaults to enabled/disabled, but
overridable by extending classes) that determine their behavior within a space.
In particular, features tend to hide or show menu items, alter access to parts
of the menu tree, etc.
2. Access to a space has several levels - space types can control degrees of
admin access, feature access and basic access to a space.
3. Spaces can determine routing of certain pages - for example, some nodes may
only be viewed when a certain space is active or a certain administrative page
may drop all active spaces.

Note that none of these user stories are necessarily implied by the
configuration override framework introduced above.


Features
--------
Spaces integrates with the Features built using the Features module. Features
that are compatible with spaces must declare themselves as such by including the
`spaces[types]` key in their `.info` file.

For example a "MyBlog" module may include the following snippet in
`myblog.info` to declare that is is spaces-enabled;

    name = "MyBlog"
    package = "Features"
    ...
    spaces[types] = "all"

`spaces[types]` may be declared to be one of the following values:

- `all` indicates that this feature is compatible with all space types.
- an array of space types where this feature may be enabled. Note that you may
  also include the faux space type `site` in this array, indicating that this
  feature may be enabled even and/or possibly only when no spaces are active.

For example, if my feature `my_cool_gallery` should only be available when
outside of any spaces, I would use the following entry:

    spaces[types][] = "site"

If it can be enabled both outside of any spaces and inside of user spaces, but
not group spaces, I could use:

    spaces[types][] = "site"
    spaces[types][] = "user"


Settings
--------
Settings can be defined for spaces features simply as Drupal variables by
implementing a `system_settings_form()` at `features/[my-feature]`. If spaces
finds such a page defined by your feature, it will expose it as a link in
the features form for any of the space types where the feature is enabled.


Creating your own space types or extending existing ones
--------------------------------------------------------
Please see `API.txt` for instructions on how you can create your own space types
or use your own class to extend or replace one of the existing classes.


Maintainers
-----------
- alex_b (Alex Barth)
- jmiccolis (Jeff Miccolis)
- yhahn (Young Hahn)
- Ian Ward

File

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