cwvreg.py
branchstable
changeset 5147 70181998897f
parent 5143 43afbdd5c8b4
child 5174 78438ad513ca
child 5273 c4caef6f09c9
equal deleted inserted replaced
5146:fe56baf63ecb 5147:70181998897f
     1 """extend the generic VRegistry with some cubicweb specific stuff
     1 # :organization: Logilab
     2 
     2 # :copyright: 2001-2010 LOGILAB S.A. (Paris, FRANCE), license is LGPL v2.
     3 :organization: Logilab
     3 # :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
     4 :copyright: 2001-2010 LOGILAB S.A. (Paris, FRANCE), license is LGPL v2.
     4 # :license: GNU Lesser General Public License, v2.1 - http://www.gnu.org/licenses
     5 :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
     5 """.. VRegistry:
     6 :license: GNU Lesser General Public License, v2.1 - http://www.gnu.org/licenses
     6 
       
     7 The `VRegistry`
       
     8 ---------------
       
     9 
       
    10 The `VRegistry` can be seen as a two level dictionary. It contains all objects
       
    11 loaded dynamically to build a |cubicweb| application. Basically:
       
    12 
       
    13 * first level key return a *registry*. This key corresponds to the `__registry__`
       
    14   attribute of application object classes
       
    15 
       
    16 * second level key return a list of application objects which share the same
       
    17   identifier. This key corresponds to the `__regid__` attribute of application
       
    18   object classes.
       
    19 
       
    20 A *registry* hold a specific kind of application objects. You've for instance
       
    21 a registry for entity classes, another for views, etc...
       
    22 
       
    23 The `VRegistry` has two main responsibilities:
       
    24 
       
    25 - being the access point to all registries
       
    26 
       
    27 - handling the registration process at startup time, and during automatic
       
    28   reloading in debug mode.
       
    29 
       
    30 
       
    31 .. _AppObjectRecording:
       
    32 
       
    33 Details of the recording process
       
    34 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
       
    35 
       
    36 .. index::
       
    37    vregistry: registration_callback
       
    38 
       
    39 On startup, |cubicweb| have to load application objects defined in its library
       
    40 and in cubes used by the instance. Application objects from the library are
       
    41 loaded first, then those provided by cubes are loaded in an ordered way (e.g. if
       
    42 your cube depends on an other, objects from the dependancy will be loaded
       
    43 first). Cube's modules or packages where appobject are looked at is explained in
       
    44 :ref:`cubelayout`.
       
    45 
       
    46 For each module:
       
    47 
       
    48 * by default all objects are registered automatically
       
    49 
       
    50 * if some objects have to replace other objects, or be included only if some
       
    51   condition is true, you'll have to define a `registration_callback(vreg)`
       
    52   function in your module and explicitly register **all objects** in this module,
       
    53   using the api defined below.
       
    54 
       
    55 .. Note::
       
    56     Once the function `registration_callback(vreg)` is implemented in a module,
       
    57     all the objects from this module have to be explicitly registered as it
       
    58     disables the automatic objects registration.
       
    59 
       
    60 
       
    61 API for objects registration
       
    62 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
       
    63 
       
    64 Here are the registration methods that you can use in the `registration_callback`
       
    65 to register your objects to the `VRegistry` instance given as argument (usually
       
    66 named `vreg`):
       
    67 
       
    68 .. automethod:: cubicweb.cwvreg.CubicWebVRegistry.register_all
       
    69 .. automethod:: cubicweb.cwvreg.CubicWebVRegistry.register_and_replace
       
    70 .. automethod:: cubicweb.cwvreg.CubicWebVRegistry.register
       
    71 .. automethod:: cubicweb.cwvreg.CubicWebVRegistry.register_if_interface_found
       
    72 .. automethod:: cubicweb.cwvreg.CubicWebVRegistry.unregister
       
    73 
       
    74 
       
    75 Examples:
       
    76 
       
    77 .. sourcecode:: python
       
    78 
       
    79    # web/views/basecomponents.py
       
    80    def registration_callback(vreg):
       
    81       # register everything in the module except SeeAlsoComponent
       
    82       vreg.register_all(globals().values(), __name__, (SeeAlsoVComponent,))
       
    83       # conditionally register SeeAlsoVComponent
       
    84       if 'see_also' in vreg.schema:
       
    85           vreg.register(SeeAlsoVComponent)
       
    86 
       
    87 In this example, we register all application object classes defined in the module
       
    88 except `SeeAlsoVComponent`. This class is then registered only if the 'see_also'
       
    89 relation type is defined in the instance'schema.
       
    90 
       
    91 .. sourcecode:: python
       
    92 
       
    93    # goa/appobjects/sessions.py
       
    94    def registration_callback(vreg):
       
    95       vreg.register(SessionsCleaner)
       
    96       # replace AuthenticationManager by GAEAuthenticationManager
       
    97       vreg.register_and_replace(GAEAuthenticationManager, AuthenticationManager)
       
    98       # replace PersistentSessionManager by GAEPersistentSessionManager
       
    99       vreg.register_and_replace(GAEPersistentSessionManager, PersistentSessionManager)
       
   100 
       
   101 In this example, we explicitly register classes one by one:
       
   102 
       
   103 * the `SessionCleaner` class
       
   104 * the `GAEAuthenticationManager` to replace the `AuthenticationManager`
       
   105 * the `GAEPersistentSessionManager` to replace the `PersistentSessionManager`
       
   106 
       
   107 If at some point we register a new appobject class in this module, it won't be
       
   108 registered at all without modification to the `registration_callback`
       
   109 implementation. The previous example will register it though, thanks to the call
       
   110 to the `register_all` method.
       
   111 
       
   112 
       
   113 .. _Selection:
       
   114 
       
   115 Runtime objects selection
       
   116 ~~~~~~~~~~~~~~~~~~~~~~~~~
       
   117 
       
   118 Now that we've all application objects loaded, the question is : when I want some
       
   119 specific object, for instance the primary view for a given entity, how do I get
       
   120 the proper object ? This is what we call the **selection mechanism**.
       
   121 
       
   122 As explained in the :ref:`Concepts` section:
       
   123 
       
   124 * each application object has a **selector**, defined by its `__select__` class attribute
       
   125 
       
   126 * this selector is responsible to return a **score** for a given context
       
   127 
       
   128   - 0 score means the object doesn't apply to this context
       
   129 
       
   130   - else, the higher the score, the better the object suits the context
       
   131 
       
   132 * the object with the higher score is selected.
       
   133 
       
   134 .. Note::
       
   135 
       
   136   When no score is higher than the others, an exception is raised in development
       
   137   mode to let you know that the engine was not able to identify the view to
       
   138   apply. This error is silenced in production mode and one of the objects with
       
   139   the higher score is picked.
       
   140 
       
   141   In such cases you would need to review your design and make sure your selectors
       
   142   or appobjects are properly defined.
       
   143 
       
   144 For instance, if you are selecting the primary (eg `__regid__ = 'primary'`) view (eg
       
   145 `__registry__ = 'views'`) for a result set containing a `Card` entity, 2 objects
       
   146 will probably be selectable:
       
   147 
       
   148 * the default primary view (`__select__ = implements('Any')`), meaning
       
   149   that the object is selectable for any kind of entity type
       
   150 
       
   151 * the specific `Card` primary view (`__select__ = implements('Card')`,
       
   152   meaning that the object is selectable for Card entities
       
   153 
       
   154 Other primary views specific to other entity types won't be selectable in this
       
   155 case. Among selectable objects, the implements selector will return a higher
       
   156 score than the second view since it's more specific, so it will be selected as
       
   157 expected.
       
   158 
       
   159 .. _SelectionAPI:
       
   160 
       
   161 API for objects selections
       
   162 ~~~~~~~~~~~~~~~~~~~~~~~~~~
       
   163 
       
   164 Here is the selection API you'll get on every registry. Some of them, as the
       
   165 'etypes' registry, containing entity classes, extend it. In those methods,
       
   166 `*args, **kwargs` is what we call the **context**. Those arguments are given to
       
   167 selectors that will inspect there content and return a score accordingly.
       
   168 
       
   169 .. automethod:: cubicweb.vregistry.Registry.select
       
   170 
       
   171 .. automethod:: cubicweb.vregistry.Registry.select_or_none
       
   172 
       
   173 .. automethod:: cubicweb.vregistry.Registry.possible_objects
       
   174 
       
   175 .. automethod:: cubicweb.vregistry.Registry.object_by_id
     7 """
   176 """
     8 __docformat__ = "restructuredtext en"
   177 __docformat__ = "restructuredtext en"
     9 _ = unicode
   178 _ = unicode
    10 
   179 
    11 from logilab.common.decorators import cached, clear_cache
   180 from logilab.common.decorators import cached, clear_cache