doc/book/en/A03a-concepts.en.txt
changeset 127 ae611743f5c6
parent 123 c5dd68070dea
child 229 767ff7f5d5a7
equal deleted inserted replaced
126:80c65c9f7c41 127:ae611743f5c6
       
     1 .. -*- coding: utf-8 -*-
       
     2 
       
     3 Concepts
       
     4 --------
       
     5 
       
     6 Global architecture
       
     7 ~~~~~~~~~~~~~~~~~~~
       
     8 .. image:: images/archi_globale.png
       
     9 
       
    10 .. note::
       
    11   For real, the client and server sides are integrated in the same
       
    12   process and interact directly, without the needs for distants
       
    13   calls using Pyro. It is important to note down that those two
       
    14   sides, client/server, are disjointed and it is possible to execute
       
    15   a couple of calls in distincts processes to balance the load of
       
    16   your web site on one or more machines.
       
    17 
       
    18 .. _TermsVocabulary:
       
    19 
       
    20 Terms and vocabulary
       
    21 ~~~~~~~~~~~~~~~~~~~~~
       
    22 
       
    23 *schema*
       
    24   The schema defines the data model of an application based on entities
       
    25   and relations, modeled with a comprehensive language made of Python
       
    26   classes based on `yams`_ library. This is the core piece
       
    27   of an application. It is initially defined in the file system and is
       
    28   stored in the database at the time an instance is created. `CubicWeb`
       
    29   provides a certain number of system entities included automatically as
       
    30   it is necessarry for the core of `CubicWeb` and a library of
       
    31   cubes that can be explicitely included if necessary.
       
    32 
       
    33 
       
    34 *entity type*
       
    35   An entity is a set of attributes; the essential attribute of
       
    36   an entity is its key, named eid
       
    37 
       
    38 *relation type*
       
    39   Entities are linked to each others by relations. In `CubicWeb`
       
    40   relations are binary: by convention we name the first item of
       
    41   a relation the `subject` and the second the `object`.
       
    42 
       
    43 *final entity type*
       
    44   Final types corresponds to the basic types such as string of characters,
       
    45   integers... Those types have a main property which is that they can
       
    46   only be used as `object` of a relation. The attributes of an entity
       
    47   (non final) are entities (finals).
       
    48 
       
    49 *final relation type*
       
    50   A relation is said final if its `object` is a final type. This is equivalent
       
    51   to an entity attribute.
       
    52 
       
    53 *relation definition*
       
    54   a relation definition is a 3-uple (subject entity type, relation type, object entity type),
       
    55   with an associated set of property such as cardinality, constraints...
       
    56   
       
    57 *repository*
       
    58   This is the RQL server side of `CubicWeb`. Be carefull not to get
       
    59   confused with a Mercurial repository or a debian repository.
       
    60 
       
    61 *source*
       
    62   A data source is a container of data (SGBD, LDAP directory, `Google
       
    63   App Engine`'s datastore ...) integrated in the
       
    64   `CubicWeb` repository. This repository has at least one source, `system` which 
       
    65   contains the schema of the application, plain-text index and others
       
    66   vital informations for the system.
       
    67 
       
    68 *configuration*
       
    69   It is possible to create differents configurations for an instance:
       
    70 
       
    71   - ``repository`` : repository only, accessible for clients using Pyro
       
    72   - ``twisted`` : web interface only, access the repository using Pyro
       
    73   - ``all-in-one`` : web interface and repository in a single process. 
       
    74      The repository could be or not accessible using Pyro.
       
    75 
       
    76 *cube*
       
    77   A cube is a model grouping one or multiple data types and/or views
       
    78   to provide a specific functionnality or a complete `CubicWeb` application
       
    79   potentially using other cubes. The available subes are located in the file
       
    80   system at `/path/to/forest/cubicweb/cubes`.
       
    81   Larger applications can be built faster by importing cubes,
       
    82   adding entities and relationships and overriding the
       
    83   views that need to display or edit informations not provided by
       
    84   cubes.
       
    85 
       
    86 *instance*
       
    87   An instance is a specific installation of a cube. All the required 
       
    88   configuration files necessarry for the well being of your web application
       
    89   are grouped in an instance. This will refer to the cube(s) your application
       
    90   is based on.
       
    91   By example logilab.org and our intranet are two instances of a single
       
    92   cube jpl, developped internally.
       
    93   The instances are defined in the directory `~/etc/cubicweb.d`.
       
    94 
       
    95 *application*
       
    96   The term application is sometime used to talk about an instance
       
    97   and sometimes to talk of a cube depending on the context. 
       
    98   So we would like to avoid using this term and try to use *cube* and
       
    99   *instance* instead.
       
   100 
       
   101 *result set*
       
   102   This object contains the results of an RQL query sent to the source
       
   103   and information on the query.
       
   104 
       
   105 *Pyro*
       
   106   `Python Remote Object`_, distributed objects system similar to Java's RMI
       
   107   (Remote Method Invocation), which can be used for the dialog between the web
       
   108   side of the framework and the RQL repository.
       
   109 
       
   110 *query language*
       
   111   A full-blown query language named RQL is used to formulate requests
       
   112   to the database or any sources such as LDAP or `Google App Engine`'s 
       
   113   datastore.
       
   114 
       
   115 *views*
       
   116   A view is applied to a `result set` to present it as HTML, XML,
       
   117   JSON, CSV, etc. Views are implemented as Python classes. There is no
       
   118   templating language.
       
   119 
       
   120 *generated user interface*
       
   121   A user interface is generated on-the-fly from the schema definition:
       
   122   entities can be created, displayed, updated and deleted. As display
       
   123   views are not very fancy, it is usually necessary to develop your
       
   124   own. Any generated view can be overridden by defining a new one with
       
   125   the same identifier.
       
   126 
       
   127 *rql*
       
   128  XXX
       
   129  
       
   130 .. _`Python Remote Object`: http://pyro.sourceforge.net/
       
   131 .. _`yams`: http://www.logilab.org/project/yams/
       
   132 
       
   133 
       
   134 `CubicWeb` engine
       
   135 ~~~~~~~~~~~~~~~~~
       
   136 
       
   137 The engine in `CubicWeb` is a set of classes managing a set of objects loaded
       
   138 dynamically at the startup of `CubicWeb` (*appobjects*). Those dynamics objects, based on the schema
       
   139 or the library, are building the final application. The differents dymanic components are
       
   140 by example:
       
   141 
       
   142 * client and server side
       
   143 
       
   144   - entities definition, containing the logic which enables application data manipulation
       
   145 
       
   146 * client side
       
   147 
       
   148   - *views*, or more specifically
       
   149 
       
   150     - boxes
       
   151     - header and footer
       
   152     - forms
       
   153     - page templates
       
   154 
       
   155   - *actions*
       
   156   - *controllers*
       
   157 
       
   158 * server side
       
   159 
       
   160   - notification hooks
       
   161   - notification views
       
   162 
       
   163 The components of the engine are:
       
   164 
       
   165 * a frontal web (only twisted is available so far), transparent for dynamic objects
       
   166 * an object that encapsulates the configuration
       
   167 * a `registry` (`cubicweb.cwvreg`) containing the dynamic objects loaded automatically
       
   168 
       
   169 Every *appobject* may access to the instance configuration using its *config* attribute
       
   170 and to the registry using its *vreg* attribute.
       
   171 
       
   172 API Python/RQL
       
   173 ~~~~~~~~~~~~~~
       
   174 
       
   175 Inspired from the standard db-api, with a Connection object having the methods
       
   176 cursor, rollback and commit essentially. The most important method is
       
   177 the `execute` method of a cursor :
       
   178 
       
   179 `execute(rqlstring, args=None, eid_key=None, build_descr=True)`
       
   180 
       
   181 :rqlstring: the RQL query to execute (unicode)
       
   182 :args: if the query contains substitutions, a dictionnary containing the values to use
       
   183 :eid_key: 
       
   184    an implementation detail of the RQL queries cache implies that if a substitution
       
   185    is used to introduce an eid *susceptible to raise the ambiguities in the query
       
   186    type resolution*, then we have to specify the correponding key in the dictionnary
       
   187    through this argument
       
   188 
       
   189 
       
   190 The `Connection` object owns the methods `commit` and `rollback`. You *should
       
   191 never need to use them* during the development of the web interface based on
       
   192 the `CubicWeb` framework as it determines the end of the transaction depending 
       
   193 on the query execution success.
       
   194 
       
   195 .. note::
       
   196   While executing updates queries (SET, INSERT, DELETE), if a query generates
       
   197   an error related to security, a rollback is automatically done on the current
       
   198   transaction.
       
   199   
       
   200 
       
   201 The `Request` class (`cubicweb.web`)
       
   202 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
       
   203 
       
   204 A request instance is created when an HTPP request is sent to the web server.
       
   205 It contains informations such as forms parameters, user authenticated, etc.
       
   206 
       
   207 **Globally, a request represents a user query, either through HTTP or not
       
   208 (we also talk about RQL queries on the server side by example)**
       
   209 
       
   210 An instance of `Request` has the following attributes:
       
   211 
       
   212 * `user`, instance of `cubicweb.common.utils.User` corresponding to the authenticated
       
   213   user
       
   214 * `form`, dictionnary containing the values of a web form
       
   215 * `encoding`, characters encoding to use in the response
       
   216 
       
   217 But also:
       
   218 
       
   219 :Session data handling:
       
   220   * `session_data()`, returns a dictinnary containing all the session data
       
   221   * `get_session_data(key, default=None)`, returns a value associated to the given
       
   222     key or the value `default` if the key is not defined
       
   223   * `set_session_data(key, value)`, assign a value to a key
       
   224   * `del_session_data(key)`,  suppress the value associated to a key
       
   225     
       
   226 
       
   227 :Cookies handling:
       
   228   * `get_cookie()`, returns a dictionnary containing the value of the header
       
   229     HTTP 'Cookie'
       
   230   * `set_cookie(cookie, key, maxage=300)`, adds a header HTTP `Set-Cookie`,
       
   231     with a minimal 5 minutes length of duration by default (`maxage` = None
       
   232     returns a *session* cookie which will expire when the user closes the browser
       
   233     window
       
   234   * `remove_cookie(cookie, key)`, forces a value to expire
       
   235 
       
   236 :URL handling:
       
   237   * `url()`, returns the full URL of the HTTP request
       
   238   * `base_url()`, returns the root URL of the web application
       
   239   * `relative_path()`, returns the relative path of the request
       
   240 
       
   241 :And more...:
       
   242   * `set_content_type(content_type, filename=None)`, adds the header HTTP
       
   243     'Content-Type'
       
   244   * `get_header(header)`, returns the value associated to an arbitrary header
       
   245     of the HTTP request
       
   246   * `set_header(header, value)`, adds an arbitrary header in the response
       
   247   * `cursor()` returns a RQL cursor on the session
       
   248   * `execute(*args, **kwargs)`, shortcut to ``.cursor().execute()``
       
   249   * `property_value(key)`, properties management (`EProperty`)
       
   250   * dictionnary `data` to store data to share informations between components
       
   251     *while a request is executed*
       
   252 
       
   253 Please note down that this class is abstract and that a concrete implementation
       
   254 will be provided by the *frontend* web used (in particular *twisted* as of
       
   255 today). For the views or others that are executed on the server side,
       
   256 most of the interface of `Request` is defined in the session associated
       
   257 to the client.
       
   258 
       
   259 The `AppObject` class
       
   260 ~~~~~~~~~~~~~~~~~~~~~
       
   261 
       
   262 In general:
       
   263 
       
   264 * we do not inherit directly from this class but from a more specific
       
   265   class such as `AnyEntity`, `EntityView`, `AnyRsetView`,
       
   266   `Action`...
       
   267 
       
   268 * to be recordable, a subclass has to define its own register (attribute
       
   269   `__registry__`) and its identifier (attribute `id`). Usually we do not have
       
   270   to take care of the register, only the identifier `id`.
       
   271 
       
   272 We can find a certain number of attributes and methods defined in this class 
       
   273 and so common to all the application objects:
       
   274 
       
   275 At the recording, the following attributes are dynamically added to
       
   276 the *subclasses*:
       
   277 
       
   278 * `vreg`, the `vregistry` of the application
       
   279 * `schema`, the application schema
       
   280 * `config`, the application configuration
       
   281 
       
   282 We also find on instances, the following attributes:
       
   283 
       
   284 * `req`, `Request` instance
       
   285 * `rset`, the *result set* associated to the object if necessarry
       
   286 * `cursor`, rql cursor on the session
       
   287 
       
   288 
       
   289 :URL handling:
       
   290   * `build_url(method=None, **kwargs)`, returns an absolute URL based on
       
   291     the given arguments. The *controller* supposed to handle the response
       
   292     can be specified through the special parameter `method` (the connection
       
   293     is theoretically done automatically :).
       
   294 
       
   295   * `datadir_url()`, returns the directory of the application data
       
   296     (contains static files such as images, css, js...)
       
   297 
       
   298   * `base_url()`, shortcut to `req.base_url()`
       
   299 
       
   300   * `url_quote(value)`, version *unicode safe* of the function `urllib.quote`
       
   301 
       
   302 :Data manipulation:
       
   303 
       
   304   * `etype_rset(etype, size=1)`, shortcut to `vreg.etype_rset()`
       
   305 
       
   306   * `eid_rset(eid, rql=None, descr=True)`, returns a *result set* object for
       
   307     the given eid
       
   308   * `entity(row, col=0)`, returns the entity corresponding to the data position
       
   309     in the *result set* associated to the object
       
   310 
       
   311   * `complete_entity(row, col=0, skip_bytes=True)`, is equivalent to `entity` but
       
   312     also call the method `complete()` on the entity before returning it
       
   313 
       
   314 :Data formatting:
       
   315   * `format_date(date, date_format=None, time=False)`
       
   316   * `format_time(time)`
       
   317 
       
   318 :And more...:
       
   319 
       
   320   * `external_resource(rid, default=_MARKER)`, access to a value defined in the
       
   321     configuration file `external_resource`
       
   322     
       
   323   * `tal_render(template, variables)`, 
       
   324 
       
   325 
       
   326 .. note::
       
   327   When we inherit from `AppObject` (even not directly), you *always* have to use
       
   328   **super()** to get the methods and attributes of the superclasses, and not
       
   329   use the class identifier.
       
   330   By example, instead of writting: ::
       
   331 
       
   332       class Truc(PrimaryView):
       
   333           def f(self, arg1):
       
   334               PrimaryView.f(self, arg1)
       
   335 
       
   336   You'd better write: ::
       
   337   
       
   338       class Truc(PrimaryView):
       
   339           def f(self, arg1):
       
   340               super(Truc, self).f(arg1)
       
   341 
       
   342 
       
   343 Standard structure for a cube
       
   344 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
       
   345 
       
   346 A complex cube is structured as follows:
       
   347 
       
   348 ::
       
   349   
       
   350   mycube/
       
   351   |
       
   352   |-- schema.py
       
   353   |
       
   354   |-- entities/
       
   355   |
       
   356   |-- sobjects/
       
   357   |
       
   358   |-- views/
       
   359   |
       
   360   |-- test/
       
   361   |
       
   362   |-- i18n/
       
   363   |
       
   364   |-- data/
       
   365   |
       
   366   |-- migration/
       
   367   | |- postcreate.py
       
   368   | \- depends.map
       
   369   |
       
   370   |-- debian/
       
   371   |
       
   372   \-- __pkginfo__.py
       
   373     
       
   374 We can use simple Python module instead of packages, by example: 
       
   375 
       
   376 ::
       
   377   
       
   378   mycube/
       
   379   |
       
   380   |-- entities.py
       
   381   |-- hooks.py
       
   382   \-- views.py
       
   383     
       
   384 
       
   385 where :
       
   386 
       
   387 * ``schema`` contains the schema definition (server side only)
       
   388 * ``entities`` contains the entities definition (server side and web interface)
       
   389 * ``sobjects`` contains hooks and/or views notifications (server side only)
       
   390 * ``views`` contains the different components of the web interface (web interface only)
       
   391 * ``test`` contains tests specifics to the application (not installed)
       
   392 * ``i18n`` contains the messages catalog for supported languages (server side and 
       
   393   web interface) 
       
   394 * ``data`` contains arbitrary data files served statically
       
   395   (images, css, javascripts files)... (web interface only)
       
   396 * ``migration`` contains the initialization file for new instances
       
   397   (``postcreate.py``) and in general a file containing the `CubicWeb` dependancies 
       
   398   of the cube depending on its version (``depends.map``)
       
   399 * ``debian`` contains all the files that manages the debian packaging
       
   400   (you would find there the classical structure with ``control``, ``rules``, 
       
   401   ``changelog``... (not installed)
       
   402 * the file ``__pkginfo__.py`` provides meta-data on the cube, especially the 
       
   403   distribution name and the current version (server side and web interface) or
       
   404   also the sub-cubes used by this cube
       
   405 
       
   406 The only required files are:
       
   407 
       
   408 * the file ``__pkginfo__.py``
       
   409 * the schema definition
       
   410   XXX false, we may want to have cubes which are only adding a service, no persistent data (eg embeding for instance)
       
   411