doc/book/en/development/devrepo/hooks.rst
author Aurelien Campeas <aurelien.campeas@logilab.fr>
Mon, 12 Apr 2010 16:49:35 +0200
branchstable
changeset 5220 42f854b6083d
parent 5202 4a77da652759
child 5221 b851558456bb
permissions -rw-r--r--
[doc/book] complete chapter on hooks & ops
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
1714
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
     1
.. -*- coding: utf-8 -*-
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
     2
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
     3
.. _hooks:
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
     4
5191
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
     5
Hooks and Operations
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
     6
====================
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
     7
5202
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
     8
Generalities
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
     9
------------
1714
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
    10
5191
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
    11
Paraphrasing the `emacs`_ documentation, let us say that hooks are an
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
    12
important mechanism for customizing an application. A hook is
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
    13
basically a list of functions to be called on some well-defined
5202
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
    14
occasion (this is called `running the hook`).
5191
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
    15
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
    16
.. _`emacs`: http://www.gnu.org/software/emacs/manual/html_node/emacs/Hooks.html
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
    17
5202
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
    18
In CubicWeb, hooks are subclasses of the Hook class in
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
    19
`server/hook.py`, implementing their own `call` method, and selected
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
    20
over a set of pre-defined `events` (and possibly more conditions,
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
    21
hooks being selectable AppObjects like views and components).
5191
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
    22
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
    23
There are two families of events: data events and server events. In a
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
    24
typical application, most of the Hooks are defined over data
5202
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
    25
events.
1714
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
    26
5191
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
    27
The purpose of data hooks is to complement the data model as defined
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
    28
in the schema.py, which is static by nature, with dynamic or value
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
    29
driven behaviours. It is functionally equivalent to a `database
5202
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
    30
trigger`_, except that database triggers definition languages are not
5191
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
    31
standardized, hence not portable (for instance, PL/SQL works with
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
    32
Oracle and PostgreSQL but not SqlServer nor Sqlite).
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
    33
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
    34
.. _`database trigger`: http://en.wikipedia.org/wiki/Database_trigger
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
    35
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
    36
Data hooks can serve the following purposes:
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
    37
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
    38
* enforcing constraints that the static schema cannot express
5220
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
    39
  (spanning several entities/relations, exotic value ranges and
5202
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
    40
  cardinalities, etc.)
1714
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
    41
5220
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
    42
* implement computed attributes
5191
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
    43
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
    44
Operations are Hook-like objects that are created by Hooks and
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
    45
scheduled to happen just before (or after) the `commit` event. Hooks
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
    46
being fired immediately on data operations, it is sometime necessary
5220
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
    47
to delay the actual work down to a time where all other Hooks have
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
    48
run, for instance a validation check which needs that all relations be
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
    49
already set on an entity. Also while the order of execution of Hooks
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
    50
is data dependant (and thus hard to predict), it is possible to force
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
    51
an order on Operations.
5191
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
    52
5202
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
    53
Operations are subclasses of the Operation class in `server/hook.py`,
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
    54
implementing `precommit_event` and other standard methods (wholly
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
    55
described later in this chapter).
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
    56
5191
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
    57
Events
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
    58
------
2172
cf8f9180e63e delete-trailing-whitespace
Nicolas Chauvat <nicolas.chauvat@logilab.fr>
parents: 1714
diff changeset
    59
5191
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
    60
Hooks are mostly defined and used to handle `dataflow`_ operations. It
5202
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
    61
means as data gets in (entities added, updated, relations set or
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
    62
unset), specific events are issued and the Hooks matching these events
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
    63
are called.
5191
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
    64
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
    65
.. _`dataflow`: http://en.wikipedia.org/wiki/Dataflow
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
    66
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
    67
Below comes a list of the dataflow events related to entities operations:
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
    68
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
    69
* before_add_entity
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
    70
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
    71
* before_update_entity
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
    72
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
    73
* before_delete_entity
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
    74
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
    75
* after_add_entity
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
    76
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
    77
* after_update_entity
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
    78
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
    79
* after_delete_entity
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
    80
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
    81
These define ENTTIES HOOKS. RELATIONS HOOKS are defined
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
    82
over the following events:
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
    83
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
    84
* after_add_relation
1714
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
    85
5191
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
    86
* after_delete_relation
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
    87
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
    88
* before_add_relation
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
    89
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
    90
* before_delete_relation
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
    91
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
    92
This is an occasion to remind us that relations support the add/delete
5220
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
    93
operation, but no update.
5191
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
    94
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
    95
Non data events also exist. These are called SYSTEM HOOKS.
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
    96
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
    97
* server_startup
2172
cf8f9180e63e delete-trailing-whitespace
Nicolas Chauvat <nicolas.chauvat@logilab.fr>
parents: 1714
diff changeset
    98
5191
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
    99
* server_shutdown
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
   100
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
   101
* server_maintenance
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
   102
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
   103
* server_backup
2172
cf8f9180e63e delete-trailing-whitespace
Nicolas Chauvat <nicolas.chauvat@logilab.fr>
parents: 1714
diff changeset
   104
5191
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
   105
* server_restore
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
   106
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
   107
* session_open
1714
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
   108
5191
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
   109
* session_close
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
   110
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
   111
5220
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   112
Using dataflow Hooks
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   113
--------------------
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   114
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   115
XXX blabla
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   116
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   117
Validation Errors
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   118
~~~~~~~~~~~~~~~~~
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   119
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   120
When a condition is not met in a Hook/Operation, it must raise a
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   121
`ValidationError`. Raising anything but a (subclass of)
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   122
ValidationError is a programming error. Raising a ValidationError
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   123
entails aborting the current transaction.
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   124
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   125
The ValidationError exception is used to convey enough information up
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   126
to the user interface. Hence its constructor is different from the
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   127
default Exception constructor. It accepts, positionally:
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   128
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   129
* an entity eid,
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   130
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   131
* a dict whose keys represent attribute (or relation) names and values
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   132
  an end-user facing message (hence properly translated) relating the
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   133
  problem.
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   134
5202
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   135
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   136
We will use a very simple example to show hooks usage. Let us start
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   137
with the following schema.
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   138
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   139
.. sourcecode:: python
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   140
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   141
   class Person(EntityType):
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   142
       age = Int(required=True)
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   143
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   144
An entity hook
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   145
~~~~~~~~~~~~~~
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   146
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   147
We would like to add a range constraint over a person's age. Let's
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   148
write an hook. It shall be placed into mycube/hooks.py. If this file
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   149
were to grow too much, we can easily have a mycube/hooks/... package
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   150
containing hooks in various modules.
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   151
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   152
.. sourcecode:: python
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   153
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   154
   from cubicweb import ValidationError
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   155
   from cubicweb.selectors import implements
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   156
   from cubicweb.server.hook import Hook
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   157
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   158
   class PersonAgeRange(Hook):
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   159
        __regid__ = 'person_age_range'
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   160
        events = ('before_add_entity', 'before_update_entity')
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   161
        __select__ = Hook.__select__ & implements('Person')
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   162
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   163
        def __call__(self):
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   164
            if 0 >= self.entity.age <= 120:
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   165
               return
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   166
            msg = self._cw._('age must be between 0 and 120')
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   167
            raise ValidationError(self.entity.eid, {'age': msg})
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   168
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   169
Hooks being AppObjects like views, they have a __regid__ and a
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   170
__select__ class attribute. The base __select__ is augmented with an
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   171
`implements` selector matching the desired entity type. The `events`
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   172
tuple is used by the Hook.__select__ base selector to dispatch the
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   173
hook on the right events. In an entity hook, it is possible to
5220
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   174
dispatch on any entity event (e.g. 'before_add_entity',
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   175
'before_update_entity') at once if needed.
5202
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   176
5220
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   177
Like all appobjects, hooks have the `self._cw` attribute which
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   178
represents the current session. In entity hooks, a `self.entity`
5202
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   179
attribute is also present.
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   180
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   181
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   182
A relation hook
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   183
~~~~~~~~~~~~~~~
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   184
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   185
Let us add another entity type with a relation to person (in
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   186
mycube/schema.py).
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   187
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   188
.. sourcecode:: python
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   189
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   190
   class Company(EntityType):
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   191
        name = String(required=True)
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   192
        boss = SubjectRelation('Person', cardinality='1*')
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   193
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   194
We would like to constrain the company's bosses to have a minimum
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   195
(legal) age. Let's write an hook for this, which will be fired when
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   196
the `boss` relation is established.
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   197
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   198
.. sourcecode:: python
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   199
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   200
   class CompanyBossLegalAge(Hook):
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   201
        __regid__ = 'company_boss_legal_age'
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   202
        events = ('before_add_relation',)
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   203
        __select__ = Hook.__select__ & match_rtype('boss')
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   204
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   205
        def __call__(self):
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   206
            boss = self._cw.entity_from_eid(self.eidto)
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   207
            if boss.age < 18:
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   208
                msg = self._cw._('the minimum age for a boss is 18')
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   209
                raise ValidationError(self.eidfrom, {'boss': msg})
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   210
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   211
We use the `match_rtype` selector to select the proper relation type.
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   212
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   213
The essential difference with respect to an entity hook is that there
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   214
is no self.entity, but `self.eidfrom` and `self.eidto` hook attributes
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   215
which represent the subject and object eid of the relation.
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   216
5220
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   217
Using Operations
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   218
----------------
5202
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   219
5220
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   220
Let's augment our example with a new `subsidiary_of` relation on Company.
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   221
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   222
.. sourcecode:: python
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   223
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   224
   class Company(EntityType):
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   225
        name = String(required=True)
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   226
        boss = SubjectRelation('Person', cardinality='1*')
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   227
        subsidiary_of = SubjectRelation('Company', cardinality='*?')
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   228
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   229
Base example
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   230
~~~~~~~~~~~~
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   231
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   232
We would like to check that there is no cycle by the `subsidiary_of`
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   233
relation. This is best achieved in an Operation since all relations
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   234
are likely to be set at commit time.
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   235
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   236
.. sourcecode:: python
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   237
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   238
    def check_cycle(self, session, eid, rtype, role='subject'):
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   239
        parents = set([eid])
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   240
        parent = session.entity_from_eid(eid)
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   241
        while parent.related(rtype, role):
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   242
            parent = parent.related(rtype, role)[0]
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   243
            if parent.eid in parents:
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   244
                msg = session._('detected %s cycle' % rtype)
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   245
                raise ValidationError(eid, {rtype: msg})
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   246
            parents.add(parent.eid)
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   247
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   248
    class CheckSubsidiaryCycleOp(Operation):
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   249
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   250
        def precommit_event(self):
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   251
            check_cycle(self.session, self.eidto, 'subsidiary_of')
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   252
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   253
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   254
    class CheckSubsidiaryCycleHook(Hook):
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   255
        __regid__ = 'check_no_subsidiary_cycle'
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   256
        events = ('after_add_relation',)
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   257
        __select__ = Hook.__select__ & match_rtype('subsidiary_of')
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   258
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   259
        def __call__(self):
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   260
            CheckSubsidiaryCycleOp(self._cw, eidto=self.eidto)
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   261
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   262
The operation is instantiated in the Hook.__call__ method.
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   263
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   264
An operation always takes a session object as first argument
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   265
(accessible as `.session` from the operation instance), and optionally
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   266
all keyword arguments needed by the operation. These keyword arguments
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   267
will be accessible as attributes from the operation instance.
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   268
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   269
Like in Hooks, ValidationError can be raised in Operations. Other
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   270
exceptions are programming errors.
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   271
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   272
Notice how our hook will instantiate an operation each time the Hook
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   273
is called, i.e. each time the `subsidiary_of` relation is set.
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   274
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   275
Using set_operation
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   276
~~~~~~~~~~~~~~~~~~~
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   277
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   278
There is an alternative method to schedule an Operation from a Hook,
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   279
using the `set_operation` function.
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   280
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   281
.. sourcecode:: python
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   282
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   283
   class CheckSubsidiaryCycleHook(Hook):
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   284
       __regid__ = 'check_no_subsidiary_cycle'
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   285
       events = ('after_add_relation',)
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   286
       __select__ = Hook.__select__ & match_rtype('subsidiary_of')
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   287
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   288
       def __call__(self):
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   289
           set_operation(self._cw, 'subsidiary_cycle_detection', self.eidto,
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   290
                         CheckCycleOp, rtype=self.rtype)
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   291
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   292
   class CheckSubsidiaryCycleOp(Operation):
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   293
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   294
       def precommit_event(self):
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   295
           for eid in self._cw.transaction_data['subsidiary_cycle_detection']:
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   296
               check_cycle(self.session, eid, self.rtype)
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   297
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   298
Here, we call set_operation with a session object, a specially forged
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   299
key, a value that is the actual payload of an individual operation (in
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   300
our case, the object of the subsidiary_of relation) , the class of the
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   301
Operation, and more optional parameters to give to the operation (here
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   302
the rtype which do not vary accross operations).
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   303
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   304
The body of the operation must then iterate over the values that have
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   305
been mapped in the transaction_data dictionary to the forged key.
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   306
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   307
This mechanism is especially useful on two occasions (not shown in our
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   308
example):
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   309
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   310
* massive data import (reduced memory consumption within a large
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   311
  transaction)
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   312
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   313
* when several hooks need to instantiate the same operation (e.g. an
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   314
  entity and a relation hook).
5202
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   315
5220
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   316
Operation: a small API overview
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   317
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   318
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   319
.. autoclass:: cubicweb.server.hook.Operation
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   320
.. autoclass:: cubicweb.server.hook.LateOperation
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   321
.. autofunction:: cubicweb.server.hook.set_operation
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   322
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   323
Hooks writing rules
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   324
-------------------
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   325
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   326
Remainder
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   327
~~~~~~~~~
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   328
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   329
Never, ever use the `entity.foo = 42` notation to update an entity. It
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   330
will not work.
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   331
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   332
How to choose between a before and an after event ?
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   333
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   334
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   335
Before hooks give you access to the old attribute (or relation)
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   336
values. By definition the database is not yet updated in a before
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   337
hook.
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   338
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   339
To access old and new values in an before_update_entity hook, one can
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   340
use the `server.hook.entity_oldnewvalue` function which returns a
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   341
tuple of the old and new values. This function takes an entity and an
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   342
attribute name as parameters.
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   343
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   344
In a 'before_add|update_entity' hook the self.entity contains the new
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   345
values. One is allowed to further modify them before database
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   346
operations, using the dictionary notation.
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   347
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   348
.. sourcecode:: python
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   349
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   350
   self.entity['age'] = 42
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   351
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   352
This is because using self.entity.set_attributes(age=42) will
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   353
immediately update the database (which does not make sense in a
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   354
pre-database hook), and will trigger any existing
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   355
before_add|update_entity hook, thus leading to infinite hook loops or
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   356
such awkward situations.
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   357
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   358
Beyond these specific cases, updating an entity attribute or relation
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   359
must *always* be done using `set_attributes` and `set_relations`
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   360
methods.
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   361
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   362
(Of course, ValidationError will always abort the current transaction,
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   363
whetever the event).
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   364
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   365
Peculiarities of inlined relations
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   366
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   367
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   368
Some relations are defined in the schema as `inlined` (see
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   369
:ref:`RelationType` for details). In this case, they are inserted in
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   370
the database at the same time as entity attributes.
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   371
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   372
Hence in the case of before_add_relation, such relations already exist
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   373
in the database.
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   374
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   375
Edited attributes
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   376
~~~~~~~~~~~~~~~~~
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   377
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   378
On udpates, it is possible to ask the `entity.edited_attributes`
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   379
variable whether one attribute has been updated.
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   380
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   381
.. sourcecode:: python
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   382
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   383
  if 'age' not in entity.edited_attribute:
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   384
      return
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   385
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   386
Deleted in transaction
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   387
~~~~~~~~~~~~~~~~~~~~~~
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   388
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   389
The session object has a deleted_in_transaction method, which can help
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   390
writing deletion Hooks.
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   391
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   392
.. sourcecode:: python
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   393
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   394
   if self._cw.deleted_in_transaction(self.eidto):
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   395
      return
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   396
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   397
Given this predicate, we can avoid scheduling an operation.
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   398
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   399
Disabling hooks
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   400
~~~~~~~~~~~~~~~
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   401
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   402
It is sometimes convenient to disable some hooks. For instance to
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   403
avoid infinite Hook loops. One uses the `hooks_control` context
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   404
manager.
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   405
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   406
This can be controlled more finely through the `category` Hook class
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   407
attribute.
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   408
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   409
.. sourcecode:: python
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   410
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   411
   with hooks_control(self.session, self.session.HOOKS_ALLOW_ALL, <category>):
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   412
       # ... do stuff
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   413
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   414
.. autoclass:: cubicweb.server.session.hooks_control