src/source/zca.rst
changeset 53 05a4f2c07b84
parent 51 5ebe61e3a965
child 59 9155d1640237
equal deleted inserted replaced
46:5fe8d5ffccde 53:05a4f2c07b84
     1 .. _zca:
     1 .. _zca:
     2 
     2 
     3 Managing ZCA 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 
    29 
       
    30 .. seealso::
       
    31     Zope Documentations:
       
    32         - `Components and Interfaces <http://zope.readthedocs.io/en/latest/zdgbook/ComponentsAndInterfaces.html>`_
       
    33         - `Zope component <http://zopecomponent.readthedocs.io/en/latest/narr.html>`_
       
    34         - `Zope interface <https://docs.zope.org/zope.interface/README.html>`_
       
    35 
       
    36 
       
    37 Utilities
       
    38 ---------
    14 
    39 
    15 Local utilities
    40 Local utilities
    16 ---------------
    41 '''''''''''''''
    17 
    42 
    18 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
    19 **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.
    20 
    45 
    21 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
    22 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.
    23 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
    24 manager**.
    49 **site manager**.
    25 
       
    26 
       
    27 Defining site root
       
    28 ------------------
       
    29 
       
    30 One of PyAMS pre-requisites is to use the ZODB, at least to store the site root application, it's configuration and a
       
    31 set of local utilities. :ref:`site` describes application startup and **local site manager** initialization process.
       
    32 
       
    33 This site can be used to store **local utilities** whose configuration, which is easily available to site
       
    34 administrators through management interface, is stored in the ZODB.
       
    35 
       
    36 
       
    37 Registering global utilities
       
    38 ----------------------------
       
    39 
       
    40 **Global utilities** are components providing an interface which are registered in the global registry.
       
    41 PyAMS_utils package provides custom annotations to register global utilities without using ZCML. For example, a skin
       
    42 is nothing more than a simple utility providing the *ISkin* interface:
       
    43 
       
    44 .. code-block:: python
       
    45 
       
    46     from pyams_default_theme.layer import IPyAMSDefaultLayer
       
    47     from pyams_skin.interfaces import ISkin
       
    48     from pyams_utils.registry import utility_config
       
    49 
       
    50     @utility_config(name='PyAMS default skin', provides=ISkin)
       
    51     class PyAMSDefaultSkin(object):
       
    52         """PyAMS default skin"""
       
    53 
       
    54         label = _("PyAMS default skin")
       
    55         layer = IPyAMSDefaultLayer
       
    56 
       
    57 This annotation registers a utility, named *PyAMS default skin*, providing the *ISkin* interface. It's the developer
       
    58 responsibility to provide all attributes and methods required by the provided interface.
       
    59 
    50 
    60 
    51 
    61 Registering local utilities
    52 Registering local utilities
    62 ---------------------------
    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 
    63 
    61 
    64 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
    65 a component provides several interfaces, it can be registered several times).
    63 a component provides several interfaces, it can be registered several times).
    66 
    64 
    67 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
   141 
   139 
   142 *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
   143 by an event is providing given interface.
   141 by an event is providing given interface.
   144 
   142 
   145 
   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 
   146 Looking for utilities
   168 Looking for utilities
   147 ---------------------
   169 '''''''''''''''''''''
   148 
   170 
   149 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
   150 global registry.
   172 global registry.
   151 
   173 
   152 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
   164 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*,
   165 *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
   166 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.
   167 
   189 
   168 
   190 
       
   191 Adapters
       
   192 --------
       
   193 
   169 Registering adapters
   194 Registering adapters
   170 --------------------
   195 ''''''''''''''''''''
   171 
   196 
   172 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,
   173 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
   174 adapter to use at a given time.
   199 adapter to use at a given time.
   175 
   200 
   239         weight = 10
   264         weight = 10
   240 
   265 
   241 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.
   242 
   267 
   243 
   268 
       
   269 Vocabularies
       
   270 ------------
       
   271 
   244 Registering vocabularies
   272 Registering vocabularies
   245 ------------------------
   273 ''''''''''''''''''''''''
   246 
   274 
   247 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*.
   248 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.
   249 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:
   250 
   278 
   259         """Timezones vocabulary"""
   287         """Timezones vocabulary"""
   260 
   288 
   261         def __init__(self, *args, **kw):
   289         def __init__(self, *args, **kw):
   262             terms = [SimpleTerm(t, t, t) for t in pytz.all_timezones]
   290             terms = [SimpleTerm(t, t, t) for t in pytz.all_timezones]
   263             super(TimezonesVocabulary, self).__init__(terms)
   291             super(TimezonesVocabulary, self).__init__(terms)
       
   292 
       
   293 
       
   294 
       
   295