src/source/zca.rst
branchdoc-dc
changeset 51 5ebe61e3a965
parent 50 6ed429390935
child 59 9155d1640237
equal deleted inserted replaced
50:6ed429390935 51:5ebe61e3a965
     1 .. _zca:
     1 .. _zca:
     2 
     2 
     3 Zope Component Architecture with PyAMS
     3 Zope Component Architecture with PyAMS
     4 ======================================
     4 ++++++++++++++++++++++++++++++++++++++
     5 
     5 
     6 The **Zope Component Architecture** (aka **ZCA**) is used by the Pyramid framework "under the hood" to handle interfaces,
     6 The **Zope Component Architecture** (aka **ZCA**) is used by the Pyramid framework "under the hood" to handle interfaces,
     7 adapters and utilities. You don't **have to** use it in your own applications. But you can.
     7 adapters and utilities. You don't **have to** use it in your own applications. But you can.
     8 
     8 
     9 The ZCA is mainly adding elements like **interfaces**, **adapters** and **utilities** to the Python language. It
     9 The ZCA is mainly adding elements like **interfaces**, **adapters** and **utilities** to the Python language. It
    10 allows you to write a framework or an application by using **components** which can be extended easily.
    10 allows you to write a framework or an application by using **components** which can be extended easily.
    11 
    11 
       
    12 Interfaces
       
    13     Interfaces are objects that specify (document) the external behavior
       
    14     of objects that "provide" them.  An interface specifies behavior through, a documentation in a doc string,
       
    15     attribute definitions and conditions of attribute values.
       
    16 
       
    17 Components
       
    18     Components are objects that are associated with interfaces.
       
    19 
       
    20 Utilities
       
    21     Utilities are just components that provide an interface and that are looked up by an interface and a name
       
    22 
       
    23 Adapters
       
    24     Adapters are components that are computed from other components to adapt them to some interface.
       
    25     Because they are computed from other objects, they are provided as factories, usually classes.
       
    26 
       
    27 
    12 You will find several useful resources about ZCA concepts on the internet.
    28 You will find several useful resources about ZCA concepts on the internet.
    13 
       
    14 
    29 
    15 .. seealso::
    30 .. seealso::
    16     Zope Documentations:
    31     Zope Documentations:
    17     - `Components and Interfaces <http://zope.readthedocs.io/en/latest/zdgbook/ComponentsAndInterfaces.html>`_
    32         - `Components and Interfaces <http://zope.readthedocs.io/en/latest/zdgbook/ComponentsAndInterfaces.html>`_
    18     - `Zope component <http://zopecomponent.readthedocs.io/en/latest/narr.html>`_
    33         - `Zope component <http://zopecomponent.readthedocs.io/en/latest/narr.html>`_
    19     - `Zope interface <https://docs.zope.org/zope.interface/README.html>`_
    34         - `Zope interface <https://docs.zope.org/zope.interface/README.html>`_
    20 
    35 
       
    36 
       
    37 Utilities
       
    38 ---------
    21 
    39 
    22 Local utilities
    40 Local utilities
    23 ---------------
    41 '''''''''''''''
    24 
    42 
    25 In ZCA, a **utility** is a **registered** component which provides an **interface**. This interface is the
    43 In ZCA, a **utility** is a **registered** component which provides an **interface**. This interface is the
    26 **contract** which defines features (list of attributes and methods) provided by the component which implements it.
    44 **contract** which defines features (list of attributes and methods) provided by the component which implements it.
    27 
    45 
    28 When a Pyramid application starts, a **global registry** is created to register a whole set of utilities and
    46 When a Pyramid application starts, a **global registry** is created to register a whole set of utilities and
    29 adapters; this registration can be done via ZCML directives or via native Python code.
    47 adapters; this registration can be done via ZCML directives or via native Python code.
    30 In addition, PyAMS allows you to define **local utilities**, which are stored and registered in the ZODB via a **site
    48 In addition, PyAMS allows you to define **local utilities**, which are stored and registered in the ZODB via a
    31 manager**.
    49 **site manager**.
    32 
       
    33 
       
    34 Defining site root
       
    35 ------------------
       
    36 
       
    37 One of PyAMS pre-requisites is to use the ZODB, at least to store the site root application, it's configuration and a
       
    38 set of local utilities. :ref:`site` describes application startup and **local site manager** initialization process.
       
    39 
       
    40 This site can be used to store **local utilities** whose configuration, which is easily available to site
       
    41 administrators through management interface, is stored in the ZODB.
       
    42 
       
    43 
       
    44 Registering global utilities
       
    45 ----------------------------
       
    46 
       
    47 **Global utilities** are components providing an interface which are registered in the global registry.
       
    48 PyAMS_utils package provides custom annotations to register global utilities without using ZCML. For example, a skin
       
    49 is nothing more than a simple utility providing the *ISkin* interface:
       
    50 
       
    51 .. code-block:: python
       
    52 
       
    53     from pyams_default_theme.layer import IPyAMSDefaultLayer
       
    54     from pyams_skin.interfaces import ISkin
       
    55     from pyams_utils.registry import utility_config
       
    56 
       
    57     @utility_config(name='PyAMS default skin', provides=ISkin)
       
    58     class PyAMSDefaultSkin(object):
       
    59         """PyAMS default skin"""
       
    60 
       
    61         label = _("PyAMS default skin")
       
    62         layer = IPyAMSDefaultLayer
       
    63 
       
    64 This annotation registers a utility, named *PyAMS default skin*, providing the *ISkin* interface. It's the developer
       
    65 responsibility to provide all attributes and methods required by the provided interface.
       
    66 
    50 
    67 
    51 
    68 Registering local utilities
    52 Registering local utilities
    69 ---------------------------
    53 '''''''''''''''''''''''''''
       
    54 
       
    55 
       
    56 .. tip::
       
    57 
       
    58     :ref:`site` can be used to store **local utilities** whose configuration, which is easily
       
    59     available to site administrators through management interface, is stored in the ZODB.
       
    60 
    70 
    61 
    71 A local utility is a persistent object, registered in a *local site manager*, and providing a specific interface (if
    62 A local utility is a persistent object, registered in a *local site manager*, and providing a specific interface (if
    72 a component provides several interfaces, it can be registered several times).
    63 a component provides several interfaces, it can be registered several times).
    73 
    64 
    74 Some components can be required by a given package, and created automatically via the *pyams_upgrade* command line
    65 Some components can be required by a given package, and created automatically via the *pyams_upgrade* command line
   148 
   139 
   149 *context_selector* is a custom subscriber predicate, so that subscriber event is activated only if object concerned
   140 *context_selector* is a custom subscriber predicate, so that subscriber event is activated only if object concerned
   150 by an event is providing given interface.
   141 by an event is providing given interface.
   151 
   142 
   152 
   143 
       
   144 Registering global utilities
       
   145 ''''''''''''''''''''''''''''
       
   146 
       
   147 **Global utilities** are components providing an interface which are registered in the global registry.
       
   148 PyAMS_utils package provides custom annotations to register global utilities without using ZCML. For example, a skin
       
   149 is nothing more than a simple utility providing the *ISkin* interface:
       
   150 
       
   151 .. code-block:: python
       
   152 
       
   153     from pyams_default_theme.layer import IPyAMSDefaultLayer
       
   154     from pyams_skin.interfaces import ISkin
       
   155     from pyams_utils.registry import utility_config
       
   156 
       
   157     @utility_config(name='PyAMS default skin', provides=ISkin)
       
   158     class PyAMSDefaultSkin(object):
       
   159         """PyAMS default skin"""
       
   160 
       
   161         label = _("PyAMS default skin")
       
   162         layer = IPyAMSDefaultLayer
       
   163 
       
   164 This annotation registers a utility, named *PyAMS default skin*, providing the *ISkin* interface. It's the developer
       
   165 responsibility to provide all attributes and methods required by the provided interface.
       
   166 
       
   167 
   153 Looking for utilities
   168 Looking for utilities
   154 ---------------------
   169 '''''''''''''''''''''
   155 
   170 
   156 ZCA provides the *getUtility* and *queryUtility* functions to look for a utility. But these methods only applies to
   171 ZCA provides the *getUtility* and *queryUtility* functions to look for a utility. But these methods only applies to
   157 global registry.
   172 global registry.
   158 
   173 
   159 PyAMS package provides equivalent functions, which are looking for components into local registry before looking into
   174 PyAMS package provides equivalent functions, which are looking for components into local registry before looking into
   171 All ZCA utility functions have been ported to use local registry: *registered_utilities*, *query_utility*,
   186 All ZCA utility functions have been ported to use local registry: *registered_utilities*, *query_utility*,
   172 *get_utility*, *get_utilities_for*, *get_all_utilities_registered_for* functions all follow the equivalent ZCA
   187 *get_utility*, *get_utilities_for*, *get_all_utilities_registered_for* functions all follow the equivalent ZCA
   173 functions API, but are looking for utilities in the local registry before looking in the global registry.
   188 functions API, but are looking for utilities in the local registry before looking in the global registry.
   174 
   189 
   175 
   190 
       
   191 Adapters
       
   192 --------
       
   193 
   176 Registering adapters
   194 Registering adapters
   177 --------------------
   195 ''''''''''''''''''''
   178 
   196 
   179 An adapter is also a kind of utility. But instead of *just* providing an interface, it adapts an input object,
   197 An adapter is also a kind of utility. But instead of *just* providing an interface, it adapts an input object,
   180 providing a given interface, to provide another interface. An adapter can also be named, so that you can choose which
   198 providing a given interface, to provide another interface. An adapter can also be named, so that you can choose which
   181 adapter to use at a given time.
   199 adapter to use at a given time.
   182 
   200 
   246         weight = 10
   264         weight = 10
   247 
   265 
   248 As you can see, adapted objects can be given as functions or as classes.
   266 As you can see, adapted objects can be given as functions or as classes.
   249 
   267 
   250 
   268 
       
   269 Vocabularies
       
   270 ------------
       
   271 
   251 Registering vocabularies
   272 Registering vocabularies
   252 ------------------------
   273 ''''''''''''''''''''''''
   253 
   274 
   254 A **vocabulary** is a custom factory which can be used as source for several field types, like *choices* or *lists*.
   275 A **vocabulary** is a custom factory which can be used as source for several field types, like *choices* or *lists*.
   255 Vocabularies have to be registered in a custom registry, so PyAMS_utils provide another annotation to register them.
   276 Vocabularies have to be registered in a custom registry, so PyAMS_utils provide another annotation to register them.
   256 This example is based on the *Timezone* component which allows you to select a timezone between a list of references:
   277 This example is based on the *Timezone* component which allows you to select a timezone between a list of references:
   257 
   278 
   266         """Timezones vocabulary"""
   287         """Timezones vocabulary"""
   267 
   288 
   268         def __init__(self, *args, **kw):
   289         def __init__(self, *args, **kw):
   269             terms = [SimpleTerm(t, t, t) for t in pytz.all_timezones]
   290             terms = [SimpleTerm(t, t, t) for t in pytz.all_timezones]
   270             super(TimezonesVocabulary, self).__init__(terms)
   291             super(TimezonesVocabulary, self).__init__(terms)
       
   292 
       
   293 
       
   294 
       
   295