|
1 .. -*- coding: utf-8 -*- |
|
2 |
|
3 .. _Concepts: |
|
4 |
|
5 The Core Concepts of |cubicweb| |
|
6 =============================== |
|
7 |
|
8 This section defines some terms and core concepts of the |cubicweb| framework. To |
|
9 avoid confusion while reading this book, take time to go through the following |
|
10 definitions and use this section as a reference during your reading. |
|
11 |
|
12 |
|
13 .. _Cube: |
|
14 |
|
15 Cubes |
|
16 ----- |
|
17 |
|
18 A cube is a software component made of three parts: its data model |
|
19 (:file:`schema`), its logic (:file:`entities`) and its user interface |
|
20 (:file:`views`). |
|
21 |
|
22 A cube can use other cubes as building blocks and assemble them to provide a |
|
23 whole with richer functionnalities than its parts. The cubes `cubicweb-blog`_ and |
|
24 `cubicweb-comment`_ could be used to make a cube named *myblog* with commentable |
|
25 blog entries. |
|
26 |
|
27 The `CubicWeb.org Forge`_ offers a large number of cubes developed by the community |
|
28 and available under a free software license. |
|
29 |
|
30 The command :command:`cubicweb-ctl list` displays the list of cubes installed on |
|
31 your system. |
|
32 |
|
33 On a Unix system, the available cubes are usually stored in the directory |
|
34 :file:`/usr/share/cubicweb/cubes`. If you're using the cubicweb forest |
|
35 (:ref:SourceInstallation), the cubes are searched in the directory |
|
36 :file:`/path/to/cubicweb_forest/cubes`. The environment variable |
|
37 :envvar:`CW_CUBES_PATH` gives additionnal locations where to search for cubes. |
|
38 |
|
39 .. _`CubicWeb.org Forge`: http://www.cubicweb.org/project/ |
|
40 .. _`cubicweb-blog`: http://www.cubicweb.org/project/cubicweb-blog |
|
41 .. _`cubicweb-comment`: http://www.cubicweb.org/project/cubicweb-comment |
|
42 |
|
43 |
|
44 .. _Instance: |
|
45 |
|
46 Instances |
|
47 --------- |
|
48 |
|
49 An instance is a runnable application installed on a computer and based on a |
|
50 cube. |
|
51 |
|
52 The instance directory contains the configuration files. Several instances can be |
|
53 created and based on the same cube. For exemple, several software forges can be |
|
54 set up on one computer system based on the `cubicweb-forge`_ cube. |
|
55 |
|
56 .. _`cubicweb-forge`: http://www.cubicweb.org/project/cubicweb-forge |
|
57 |
|
58 Instances can be of three different types: all-in-one, web engine or data |
|
59 repository. For applications that support high traffic, several web (front-end) |
|
60 and data (back-end) instances can be set-up to share the load. |
|
61 |
|
62 .. image:: ../../images/archi_globale.en.png |
|
63 |
|
64 The command :command:`cubicweb-ctl list` also displays the list of instances |
|
65 installed on your system. |
|
66 |
|
67 On a Unix system, the instances are usually stored in the directory |
|
68 :file:`/etc/cubicweb.d/`. During development, the :file:`~/etc/cubicweb.d/` |
|
69 directory is looked up, as well as the paths in :envvar:`CW_INSTANCES_DIR` |
|
70 environment variable. |
|
71 |
|
72 |
|
73 .. Note:: |
|
74 |
|
75 The term application is used to refer to "something that should do something as |
|
76 a whole", eg more like a project and so can refer to an instance or to a cube, |
|
77 depending on the context. This book will try to use *application*, *cube* and |
|
78 *instance* as appropriate. |
|
79 |
|
80 |
|
81 .. _RepositoryIntro: |
|
82 |
|
83 Data Repository |
|
84 --------------- |
|
85 |
|
86 The data repository [1]_ provides access to one or more data sources (including |
|
87 SQL databases, LDAP repositories, other |cubicweb| instance repositories, GAE's |
|
88 DataStore, etc). |
|
89 |
|
90 All interactions with the repository are done using the Relation Query Language |
|
91 (:ref:`RQL`). The repository federates the data sources and hides them from the |
|
92 querier, which does not realize when a query spans accross several data sources |
|
93 and requires running sub-queries and merges to complete. |
|
94 |
|
95 It is common to run the web engine and the repository in the same process (see |
|
96 instances of type all-in-one above), but this is not a requirement. A repository |
|
97 can be set up to be accessed remotely using Pyro (`Python Remote Objects`_) and |
|
98 act as a server. However, it's important to know if code you're writing is |
|
99 executed on the repository side, on our client side (the web engine being a |
|
100 client for instance): you don't have the same abilities on both side. On the |
|
101 repository side, you can for instance by-pass security checks, which isn't |
|
102 possible from client code. |
|
103 |
|
104 Some logic can be attached to events that happen in the repository, like |
|
105 creation of entities, deletion of relations, etc. This is used for example to |
|
106 send email notifications when the state of an object changes. See :ref:`HookIntro` below. |
|
107 |
|
108 .. [1] not to be confused with a Mercurial repository or a Debian repository. |
|
109 .. _`Python Remote Objects`: http://pyro.sourceforge.net/ |
|
110 |
|
111 |
|
112 .. _WebEngineIntro: |
|
113 |
|
114 Web Engine |
|
115 ---------- |
|
116 |
|
117 The web engine replies to http requests and runs the user interface |
|
118 and most of the application logic. |
|
119 |
|
120 By default the web engine provides a `CRUD`_ user interface based on |
|
121 the data model of the instance. Entities can be created, displayed, |
|
122 updated and deleted. As the default user interface is not very fancy, |
|
123 it is usually necessary to develop your own. |
|
124 |
|
125 .. _`CRUD`: http://en.wikipedia.org/wiki/Create,_read,_update_and_delete |
|
126 |
|
127 .. _SchemaIntro: |
|
128 |
|
129 Schema (Data Model) |
|
130 ------------------- |
|
131 |
|
132 The data model of a cube is described as an entity-relationship schema using a |
|
133 comprehensive language made of Python classes imported from the yams_ library. |
|
134 |
|
135 .. _yams: http://www.logilab.org/project/yams/ |
|
136 |
|
137 An `entity type` defines a set of attributes and is used in some relations. |
|
138 Attributes may be of the following types: `String`, `Int`, `Float`, `Boolean`, |
|
139 `Date`, `Time`, `Datetime`, `Interval`, `Password`, `Bytes`, `RichString`. |
|
140 |
|
141 A `relation type` is used to define an oriented binary relation between two |
|
142 entity types. The left-hand part of a relation is named the `subject` and the |
|
143 right-hand part is named the `object`. |
|
144 |
|
145 A `relation definition` is a triple (*subject entity type*, *relation type*, *object |
|
146 entity type*) associated with a set of properties such as cardinality, |
|
147 constraints, etc. |
|
148 |
|
149 Permissions can be set on entity types and relation definition to control who |
|
150 will be able to create, read, update or delete entities and relations. Permissions |
|
151 are granted to groups (to which users may belong) or using rql expression (if the |
|
152 rql expression returns some results, the permission is granted). |
|
153 |
|
154 Some meta-data necessary to the system is added to the data model. That includes |
|
155 entities like users and groups, the entities used to store the data model |
|
156 itself and attributes like unique identifier, creation date, creator, etc. |
|
157 |
|
158 When you create a new |cubicweb| instance, the schema is stored in the database. |
|
159 When the cubes the instance is based on evolve, they may change their data model |
|
160 and provide migration scripts that will be executed when the administrator will |
|
161 run the upgrade process for the instance. |
|
162 |
|
163 |
|
164 .. _VRegistryIntro: |
|
165 |
|
166 Registries and application objects |
|
167 ---------------------------------- |
|
168 |
|
169 Application objects |
|
170 ~~~~~~~~~~~~~~~~~~~ |
|
171 |
|
172 Beside a few core functionalities, almost every feature of the framework is |
|
173 achieved by dynamic objects (`application objects` or `appobjects`) stored in a |
|
174 two-levels registry (the `vregistry`). Each object is affected to a registry with |
|
175 an identifier in this registry. You may have more than one object sharing an |
|
176 identifier in the same registry, At runtime, appobjects are selected in a |
|
177 registry according to the context. Selection is done by comparing *score* |
|
178 returned by each appobject's *selector*. |
|
179 |
|
180 Application objects are stored in the vregistry using a two-level hierarchy : |
|
181 |
|
182 object's `__registry__` : object's `__regid__` : [list of app objects] |
|
183 |
|
184 E.g. The `vregistry` contains several registries which hold a list of |
|
185 appobjects associated to an identifier. |
|
186 |
|
187 The base class of appobjects is :class:`cubicweb.appobject.AppObject`. |
|
188 |
|
189 Selectors |
|
190 ~~~~~~~~~ |
|
191 |
|
192 Each appobject has a selector, that is used to compute how well the object fits a |
|
193 given context. The better the object fits the context, the higher the score. They |
|
194 are the glue that tie appobjects to the data model. Using them appropriately is |
|
195 an essential part of the construction of well behaved cubes. |
|
196 |
|
197 |cubicweb| provides a set of basic selectors that may be parametrized. Also, |
|
198 selectors can be combined with the `~` unary operator (negation) and the binary |
|
199 operators `&` and `|` (respectivly 'and' and 'or') to build more complex |
|
200 selector. Of course complex selector may be combined too. Last but not least, you |
|
201 can write your own selectors. |
|
202 |
|
203 The `vregistry` |
|
204 ~~~~~~~~~~~~~~~ |
|
205 |
|
206 At startup, the `vregistry` inspects a number of directories looking for |
|
207 compatible classes definition. After a recording process, the objects are |
|
208 assigned to registries so that they can be selected dynamically while the |
|
209 instance is running. |
|
210 |
|
211 In a cube, application object classes are looked in the following modules or |
|
212 packages: |
|
213 |
|
214 - `entities` |
|
215 - `views` |
|
216 - `sobjects` |
|
217 - `hooks` |
|
218 |
|
219 |
|
220 Once initialized, there are three common ways to retrieve some application object |
|
221 from a registry: |
|
222 |
|
223 * get the most appropriate object by specifying an identifier. In that case, the |
|
224 object with the greatest score is selected. There should always be a single |
|
225 appobject with a greater score than others for a particular context. |
|
226 |
|
227 * get all objects applying to a context by specifying a registry. In that case, a |
|
228 list of objects will be returned containing the object with the highest score |
|
229 (> 0) for each identifier in that registry. |
|
230 |
|
231 * get the object within a particular registry/identifier. In that case no |
|
232 selection process is involved, the vregistry will expect to find a single |
|
233 object in that cell. |
|
234 |
|
235 |
|
236 .. _RQLIntro: |
|
237 |
|
238 The RQL query language |
|
239 ---------------------- |
|
240 |
|
241 **No need for a complicated ORM when you have a powerful query language** |
|
242 |
|
243 All the persistent data in a |cubicweb| instance is retrieved and modified by |
|
244 using the Relation Query Language. |
|
245 |
|
246 This query language is inspired by SQL but is on a higher level in order to |
|
247 emphasize browsing relations. |
|
248 |
|
249 |
|
250 db-api |
|
251 ~~~~~~ |
|
252 |
|
253 The repository exposes a `db-api`_ like api but using the RQL instead of SQL. |
|
254 |
|
255 You basically get a connection using :func:`cubicweb.dbapi.connect` , then |
|
256 get a cursor to call its `execute` method which will return result set for the |
|
257 given rql query. |
|
258 |
|
259 You can also get additional information through the connection, such as the |
|
260 repository'schema, version configuration, etc. |
|
261 |
|
262 |
|
263 Result set |
|
264 ~~~~~~~~~~ |
|
265 |
|
266 Every request made (using RQL) to the data repository returns an object we call a |
|
267 Result Set. It enables easy use of the retrieved data, providing a translation |
|
268 layer between the backend's native datatypes and |cubicweb| schema's EntityTypes. |
|
269 |
|
270 Result sets provide access to the raw data, yielding either basic Python data |
|
271 types, or schema-defined high-level entities, in a straightforward way. |
|
272 |
|
273 |
|
274 .. _ViewIntro: |
|
275 |
|
276 Views |
|
277 ----- |
|
278 |
|
279 **CubicWeb is data driven** |
|
280 |
|
281 The view system is loosely coupled to data through the selection system explained |
|
282 above. Views are application objects with a dedicated interface to 'render' |
|
283 something, eg producing some html, text, xml, pdf, or whatsover that can be |
|
284 displayed to a user. |
|
285 |
|
286 The two main entry points of a view are: |
|
287 |
|
288 * `call()`, used to render a view on a context with no result set, or on a whole |
|
289 result set |
|
290 |
|
291 * `cell_call(row, col)`, used to render a view on a the cell with index `row` and |
|
292 `col` of the context's result set (remember result set may be seen as a two |
|
293 dimensions array). |
|
294 |
|
295 Then view may gets refined into different kind of objects such as `template`, |
|
296 `boxes`, `components`, which are more high-level abstraction useful to build |
|
297 the user interface in an object oriented way. |
|
298 |
|
299 |
|
300 .. _HookIntro: |
|
301 |
|
302 Hooks and operations |
|
303 -------------------- |
|
304 |
|
305 **CubicWeb provides an extensible data repository** |
|
306 |
|
307 The data model defined using Yams types allows to express the data |
|
308 model in a comfortable way. However several aspects of the data model |
|
309 can not be expressed there. For instance: |
|
310 |
|
311 * managing computed attributes |
|
312 |
|
313 * enforcing complicated structural invariants |
|
314 |
|
315 * real-world side-effects linked to data events (email notification |
|
316 being a prime example) |
|
317 |
|
318 The hook system is much like the triggers of an SQL database engine, |
|
319 except that: |
|
320 |
|
321 * it is not limited to one specific SQL backend (every one of them |
|
322 having an idiomatic way to encode triggers), nor to SQL backends at |
|
323 all (think about LDAP or a Subversion repository) |
|
324 |
|
325 * it is well-coupled to the rest of the framework |
|
326 |
|
327 Hooks are also application objects registered on events such as after/before |
|
328 add/update/delete on entities/relations, server startup or shutdown, etc. As all |
|
329 application objects, they have a selector defining when they should be called or |
|
330 not. |
|
331 |
|
332 `Operations` may be instantiated by hooks to do further processing at different |
|
333 steps of the transaction's commit / rollback, which usually can not be done |
|
334 safely at the hook execution time. |
|
335 |
|
336 Hooks and operation are an essential building block of any moderately complicated |
|
337 cubicweb application. |
|
338 |
|
339 .. Note: |
|
340 RQL queries executed in hooks and operations are *unsafe* by default, e.g. the |
|
341 read and write security is deactivated unless explicitly asked. |
|
342 |
|
343 .. |cubicweb| replace:: *CubicWeb* |