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 --- |
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') |