server/hook.py
branchstable
changeset 6753 2bbc1010494c
parent 6730 253dd28cc35f
child 6765 b922e3a817e9
equal deleted inserted replaced
6752:7351806cd485 6753:2bbc1010494c
   103 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   103 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   104 
   104 
   105 When called for one of these events, hook will have an `entity` attribute
   105 When called for one of these events, hook will have an `entity` attribute
   106 containing the entity instance.
   106 containing the entity instance.
   107 
   107 
   108 * 'before_add_entity', 'before_update_entity':
   108 * `before_add_entity`, `before_update_entity`:
   109 
   109 
   110   - on those events, you can check what attributes of the entity are modified in
   110   - on those events, you can check what attributes of the entity are modified in
   111     `entity.cw_edited` (by definition the database is not yet updated in a before
   111     `entity.cw_edited` (by definition the database is not yet updated in a before
   112     event)
   112     event)
   113 
   113 
   114   - you are allowed to further modify the entity before database operations,
   114   - you are allowed to further modify the entity before database
   115     using the dictionary notation. By doing this, you'll avoid the need for a
   115     operations, using the dictionary notation on `cw_edited`. By doing
   116     whole new rql query processing, the only difference is that the underlying
   116     this, you'll avoid the need for a whole new rql query processing,
   117     backend query (eg usually sql) will contains the additional data. For
   117     the only difference is that the underlying backend query (eg
   118     example:
   118     usually sql) will contains the additional data. For example:
   119 
   119 
   120     .. sourcecode:: python
   120     .. sourcecode:: python
   121 
   121 
   122        self.entity.set_attributes(age=42)
   122        self.entity.set_attributes(age=42)
   123 
   123 
   134     one that triggered the hook.
   134     one that triggered the hook.
   135 
   135 
   136     Similarly, removing an attribute from `cw_edited` will cancel its
   136     Similarly, removing an attribute from `cw_edited` will cancel its
   137     modification.
   137     modification.
   138 
   138 
   139   - on 'before_update_entity' event, you can access to old and new values in
   139   - on `before_update_entity` event, you can access to old and new values in
   140     this hook, by using `entity.cw_edited.oldnewvalue(attr)`
   140     this hook, by using `entity.cw_edited.oldnewvalue(attr)`
   141 
   141 
   142 
   142 
   143 * 'after_add_entity', 'after_update_entity'
   143 * `after_add_entity`, `after_update_entity`
   144 
   144 
   145   - on those events, you can still check what attributes of the entity are
   145   - on those events, you can still check what attributes of the entity are
   146     modified in `entity.cw_edited` but you can't get anymore the old value, nor
   146     modified in `entity.cw_edited` but you can't get anymore the old value, nor
   147     modify it.
   147     modify it.
   148 
   148 
   149 * 'before_delete_entity', 'after_delete_entity'
   149 * `before_delete_entity`, `after_delete_entity`
   150 
   150 
   151   - on those events, the entity has no `cw_edited` set.
   151   - on those events, the entity has no `cw_edited` set.
   152 
   152 
   153 
   153 
   154 Relation modification related events
   154 Relation modification related events
   156 
   156 
   157 When called for one of these events, hook will have `eidfrom`, `rtype`, `eidto`
   157 When called for one of these events, hook will have `eidfrom`, `rtype`, `eidto`
   158 attributes containing respectivly the eid of the subject entity, the relation
   158 attributes containing respectivly the eid of the subject entity, the relation
   159 type and the eid of the object entity.
   159 type and the eid of the object entity.
   160 
   160 
   161 * 'before_add_relation', 'before_delete_relation'
   161 * `before_add_relation`, `before_delete_relation`
   162 
   162 
   163   - on those events, you can still get original relation by issuing a rql query
   163   - on those events, you can still get original relation by issuing a rql query
   164 
   164 
   165 * 'after_add_relation', 'after_delete_relation'
   165 * `after_add_relation`, `after_delete_relation`
   166 
   166 
   167 This is an occasion to remind us that relations support the add / delete
   167 This is an occasion to remind us that relations support the add / delete
   168 operation, but no update.
   168 operation, but no update.
   169 
   169 
   170 
   170 
   171 Non data events
   171 Non data events
   172 ~~~~~~~~~~~~~~~
   172 ~~~~~~~~~~~~~~~
   173 
   173 
   174 Hooks called on server start/maintenance/stop event (eg 'server_startup',
   174 Hooks called on server start/maintenance/stop event (eg `server_startup`,
   175 'server_maintenance', 'server_shutdown') have a `repo` attribute, but *their
   175 `server_maintenance`, `server_shutdown`) have a `repo` attribute, but *their
   176 `_cw` attribute is None*.  The `server_startup` is called on regular startup,
   176 `_cw` attribute is None*.  The `server_startup` is called on regular startup,
   177 while `server_maintenance` is called on cubicweb-ctl upgrade or shell
   177 while `server_maintenance` is called on cubicweb-ctl upgrade or shell
   178 commands. `server_shutdown` is called anyway.
   178 commands. `server_shutdown` is called anyway.
   179 
   179 
   180 Hooks called on backup/restore event (eg 'server_backup', 'server_restore') have
   180 Hooks called on backup/restore event (eg 'server_backup', 'server_restore') have
   181 a `repo` and a `timestamp` attributes, but *their `_cw` attribute is None*.
   181 a `repo` and a `timestamp` attributes, but *their `_cw` attribute is None*.
   182 
   182 
   183 Hooks called on session event (eg 'session_open', 'session_close') have no
   183 Hooks called on session event (eg `session_open`, `session_close`) have no
   184 special attribute.
   184 special attribute.
   185 
   185 
   186 
   186 
   187 API
   187 API
   188 ---
   188 ---
   398     on the right events. It is possible to dispatch on multiple events at once
   398     on the right events. It is possible to dispatch on multiple events at once
   399     if needed (though take care as hook attribute may vary as described above).
   399     if needed (though take care as hook attribute may vary as described above).
   400 
   400 
   401     .. Note::
   401     .. Note::
   402 
   402 
   403       Do not forget to extend the base class selectors as in ::
   403       Do not forget to extend the base class selectors as in:
   404 
   404 
   405       .. sourcecode:: python
   405       .. sourcecode:: python
   406 
   406 
   407           class MyHook(Hook):
   407           class MyHook(Hook):
   408             __regid__ = 'whatever'
   408             __regid__ = 'whatever'
   607     operation instance.
   607     operation instance.
   608 
   608 
   609     An operation is triggered on connections pool events related to
   609     An operation is triggered on connections pool events related to
   610     commit / rollback transations. Possible events are:
   610     commit / rollback transations. Possible events are:
   611 
   611 
   612     * 'precommit':
   612     * `precommit`:
   613 
   613 
   614       the transaction is being prepared for commit. You can freely do any heavy
   614       the transaction is being prepared for commit. You can freely do any heavy
   615       computation, raise an exception if the commit can't go. or even add some
   615       computation, raise an exception if the commit can't go. or even add some
   616       new operations during this phase. If you do anything which has to be
   616       new operations during this phase. If you do anything which has to be
   617       reverted if the commit fails afterwards (eg altering the file system for
   617       reverted if the commit fails afterwards (eg altering the file system for
   618       instance), you'll have to support the 'revertprecommit' event to revert
   618       instance), you'll have to support the 'revertprecommit' event to revert
   619       things by yourself
   619       things by yourself
   620 
   620 
   621     * 'revertprecommit':
   621     * `revertprecommit`:
   622 
   622 
   623       if an operation failed while being pre-commited, this event is triggered
   623       if an operation failed while being pre-commited, this event is triggered
   624       for all operations which had their 'precommit' event already fired to let
   624       for all operations which had their 'precommit' event already fired to let
   625       them revert things (including the operation which made the commit fail)
   625       them revert things (including the operation which made the commit fail)
   626 
   626 
   627     * 'rollback':
   627     * `rollback`:
   628 
   628 
   629       the transaction has been either rollbacked either:
   629       the transaction has been either rollbacked either:
   630 
   630 
   631        * intentionaly
   631        * intentionaly
   632        * a 'precommit' event failed, in which case all operations are rollbacked
   632        * a 'precommit' event failed, in which case all operations are rollbacked
   633          once 'revertprecommit'' has been called
   633          once 'revertprecommit'' has been called
   634 
   634 
   635     * 'postcommit':
   635     * `postcommit`:
   636 
   636 
   637       the transaction is over. All the ORM entities accessed by the earlier
   637       the transaction is over. All the ORM entities accessed by the earlier
   638       transaction are invalid. If you need to work on the database, you need to
   638       transaction are invalid. If you need to work on the database, you need to
   639       start a new transaction, for instance using a new internal session, which
   639       start a new transaction, for instance using a new internal session, which
   640       you will need to commit (and close!).
   640       you will need to commit (and close!).
   641 
   641 
   642     For an operation to support an event, one has to implement the `<event
   642     For an operation to support an event, one has to implement the `<event
   643     name>_event` method with no arguments.
   643     name>_event` method with no arguments.
   644 
   644 
   645     Notice order of operations may be important, and is controlled according to
   645     The order of operations may be important, and is controlled according to
   646     the insert_index's method output (whose implementation vary according to the
   646     the insert_index's method output (whose implementation vary according to the
   647     base hook class used).
   647     base hook class used).
   648     """
   648     """
   649 
   649 
   650     def __init__(self, session, **kwargs):
   650     def __init__(self, session, **kwargs):
   734 
   734 
   735     You should try to use this instead of creating on operation for each
   735     You should try to use this instead of creating on operation for each
   736     `value`, since handling operations becomes costly on massive data import.
   736     `value`, since handling operations becomes costly on massive data import.
   737 
   737 
   738     Usage looks like:
   738     Usage looks like:
       
   739 
   739     .. sourcecode:: python
   740     .. sourcecode:: python
   740 
   741 
   741         class MyEntityHook(Hook):
   742         class MyEntityHook(Hook):
   742             __regid__ = 'my.entity.hook'
   743             __regid__ = 'my.entity.hook'
   743             __select__ = Hook.__select__ & is_instance('MyEntity')
   744             __select__ = Hook.__select__ & is_instance('MyEntity')