goa/doc/devmanual_fr/chap_bases_framework_erudi.txt
author Julien Jehannet <Julien Jehannet <julien.jehannet@logilab.fr>>
Tue, 02 Mar 2010 21:48:36 +0100
branchstable
changeset 4783 6dc34d4cf892
parent 1398 5fe84a5f7035
permissions -rw-r--r--
[F] views: fix 2 unicode errors 1. You can now use valid unicode strings in ValidationError exception. Previously, if 'err' contains unicode, UnicodeDecodeError was raised by format_errors() >>> templstr = '<li>%s</li>\n' >>> e = ValidationError(None, {None: u'oué, une exception en unicode!'}) >>> templstr % e '<li>None (None): ou\xc3\xa9, une exception en unicode!</li>\n' >>> templstr = u'<li>%s</li>\n' >>> templstr % e u'<li>None (None): ou\xe9, une exception en unicode!</li>\n' 2. The message of an Exception can contains unicode. But it now properly managed by “informal” string representation. We can easily fix the problem by using the Exception.message attribute that still contains the original message. >>> a = AssertionError(u'séfdsdf') >>> a.message u's\xe9fdsdf' >>> str(a) Traceback (most recent call last): File "<stdin>", line 1, in <module> UnicodeEncodeError: 'ascii' codec can't encode character u'\xe9' in position 1: ordinal not in range(128) >>> a = ValueError(u'fsdfsdéfsdfs') >>> str(a) Traceback (most recent call last): File "<stdin>", line 1, in <module> UnicodeEncodeError: 'ascii' codec can't encode character u'\xe9' in position 6: ordinal not in range(128) >>> a ValueError(u'fsdfsd\xe9fsdfs',) >>> unicode(a) Traceback (most recent call last): File "<stdin>", line 1, in <module> UnicodeEncodeError: 'ascii' codec can't encode character u'\xe9' in position 6: ordinal not in range(128) >>> a.message u'fsdfsd\xe9fsdfs'

Fondements du framework CubicWeb
=============================

Le moteur web d'cubicweb consiste en quelques classes grant un ensemble d'objets
chargs dynamiquement au lancement d'cubicweb. Ce sont ces objets dynamiques, issus
du modle ou de la librairie, qui construisent le site web final. Les diffrents
composants dynamiques sont par exemple : 

* cot client et serveur

 - les dfinitions d'entits, contenant la logique permettant la manipulation des
   donnes de l'application

* cot client

  - les *vues* , ou encore plus spcifiquement 

    - les boites
    - l'en-tte et le pied de page
    - les formulaires
    - les gabarits de pages

  - les *actions*
  - les *controleurs*

* cot serveur

  - les crochets de notification
  - les vues de notification

Les diffrents composants du moteur sont :

* un frontal web (seul twisted disponible pour le moment), transparent du point
  de vue des objets dynamiques
* un objet encapsulant la configuration
* un `vregistry` (`cubicweb.cwvreg`) contenant les objets chargs dynamiquements


Dtail de la procdure d'enregistrement
---------------------------------------
Au dmarage le `vregistry` ou base de registres inspecte un certain nombre de
rpertoires  la recherche de dfinition de classes "compatible". Aprs une
procdure d'enregistrement les objets sont affects dans diffrents registres
afin d'tre ensuite slctionn dynamiquement pendant le fonctionnement de
l'application.

La classe de base de tout ces objets est la classe `AppRsetObject` (module
`cubicweb.common.appobject`). 


API Python/RQL
--------------

Inspir de la db-api standard, avec un object Connection possdant les mthodes
cursor, rollback et commit principalement. La mthode importante est la mthode
`execute` du curseur :

`execute(rqlstring, args=None, eid_key=None, build_descr=True)`

:rqlstring: la requte rql  xcuter (unicode)
:args: si la requte contient des substitutions, un dictionnaire contenant les
       valeurs  utiliser
:eid_key: 
   un dtail d'implmentation du cache de requtes RQL fait que si une substitution est
   utilise pour introduire un eid *levant des ambiguits dans la rsolution de
   type de la requte*, il faut spcifier par cet argument la cl correspondante
   dans le dictionnaire

C'est l'objet Connection qui possde les mthodes classiques `commit` et
`rollback`. Vous ne *devriez jamais avoir  les utiliser* lors du dveloppement
d'interface web sur la base du framework CubicWeb tant donn que la fin de la
transaction est dtermine par celui-ci en fonction du succs d'xcution de la
requte. 

NOTE : lors de l'xcution de requtes de modification (SET,INSERT,DELETE), si une
requte gnre une erreur lie  la scurit, un rollback est systmatiquement
effectue sur la transaction courante.


La classe `Request` (`cubicweb.web`)
---------------------------------
Une instance de requte est cre lorsque une requte HTTP est transmise au
serveur web. Elle contient des informations telles que les paramtres de
formulaires, l'utilisateur connect, etc. 

**De manire plus gnrale une requte reprsente une demande d'un utilisateur,
que se soit par HTTP ou non (on parle galement de requte rql cot serveur par
exemple)**

Une instance de la classe `Request` possde les attributs :

* `user`, instance de`cubicweb.common.utils.User` correspondant  l'utilisateur
  connect 
* `form`, dictionaire contenant les valeurs de formulaire web
* `encoding`, l'encodage de caractre  utiliser dans la rponse

Mais encore :

:Gestion des donnes de session:        
  * `session_data()`, retourne un dictionaire contenant l'intgralit des
    donnes de la session
  * `get_session_data(key, default=None)`, retourne la valeur associe 
    la cl ou la valeur `default` si la cl n'est pas dfinie
  * `set_session_data(key, value)`, associe une valeur  une cl
  * `del_session_data(key)`,  supprime la valeur associ  une cl
    

:Gestion de cookie:
  * `get_cookie()`, retourne un dictionnaire contenant la valeur de l'entte
    HTTP 'Cookie'
  * `set_cookie(cookie, key, maxage=300)`, ajoute un en-tte HTTP `Set-Cookie`,
    avec une dure de vie 5 minutes par dfault (`maxage` = None donne un cooke
    *de session"* expirant quand l'utilisateur ferme son navigateur
  * `remove_cookie(cookie, key)`, fait expirer une valeur

:Gestion d'URL:
  * `url()`, retourne l'url complte de la requte HTTP
  * `base_url()`, retourne l'url de la racine de l'application
  * `relative_path()`, retourne chemin relatif de la requte

:Et encore...:
  * `set_content_type(content_type, filename=None)`, place l'en-tte HTTP
    'Content-Type'
  * `get_header(header)`, retourne la valeur associ  un en-tte HTTP
    arbitraire de la requte
  * `set_header(header, value)`, ajoute un en-tte HTTP arbitraire dans la
    rponse 
  * `cursor()` retourne un curseur RQL sur la session
  * `execute(*args, **kwargs)`, raccourci vers .cursor().execute()
  * `property_value(key)`, gestion des proprits (`CWProperty`)
  * le dictionaire `data` pour stocker des donnes pour partager de
    l'information entre les composants *durant l'xcution de la requte*.

A noter que cette classe est en ralit abstraite et qu'une implmentation
concrte sera fournie par le *frontend* web utilis (en l'occurent *twisted*
aujourd'hui). Enfin pour les vues ou autres qui sont xcuts cot serveur,
la majeure partie de l'interface de `Request` est dfinie sur la session
associe au client. 


La classe `AppObject`
---------------------

En gnral :

* on n'hrite pas directement des cette classe mais plutt d'une classe
  plus spcifique comme par exemple `AnyEntity`, `EntityView`, `AnyRsetView`,
  `Action`...

* pour tre enregistrable, un classe fille doit dfinir son registre (attribut
  `__registry__`) et son identifiant (attribut `id`). Gnralement on n'a pas 
  s'occuper du registre, uniquement de l'identifiant `id` :) 

On trouve un certain nombre d'attributs et de mthodes dfinis dans cette classe
et donc commune  tous les objets de l'application :

A l'enregistrement, les attributs suivants sont ajouts dynamiquement aux
*classes* filles:

* `vreg`, le `vregistry` de l'application
* `schema`, le schma de l'application
* `config`, la configuration de l'application

On trouve galement sur les instances les attributs :

* `req`, instance de `Request`
* `rset`, le "result set" associ  l'objet le cas chant
* `cursor`, curseur rql sur la session


:Gestion d'URL:
  * `build_url(method=None, **kwargs)`, retourne une URL absolue construites 
    partir des arguments donns. Le *controleur* devant grer la rponse
    peut-tre spcifi via l'argument spcial `method` (le branchement est
    thoriquement bien effectu automatiquement :).

  * `datadir_url()`, retourne l'url du rpertoire de donnes de l'application
    (contenant les fichiers statiques tels que les images, css, js...)

  * `base_url()`, raccourci sur `req.base_url()`

  * `url_quote(value)`, version *unicode safe* de de la fonction `urllib.quote`

:Manipulation de donnes:

  * `etype_rset(etype, size=1)`, raccourci vers `vreg.etype_rset()`

  * `eid_rset(eid, rql=None, descr=True)`, retourne un objet result set pour
    l'eid donn
  * `entity(row, col=0)`, retourne l'entit correspondant  la position donnes
    du "result set" associ  l'objet

  * `complete_entity(row, col=0, skip_bytes=True)`, quivalent  `entity` mais
    appelle galement la mthode `complete()` sur l'entit avant de la retourner

:Formattage de donnes:
  * `format_date(date, date_format=None, time=False)`
  * `format_time(time)`,

:Et encore...:

  * `external_resource(rid, default=_MARKER)`, accde  une valeur dfinie dans
    le fichier de configuration `external_resource`
    
  * `tal_render(template, variables)`, 


**NOTE IMPORTANTE**
Lorsqu'on hrite d'`AppObject` (mme indirectement), il faut **toujours**
utiliser **super()** pour rcuprer les mthodes et attributs des classes
parentes, et pas passer par l'identifiant de classe parente directement.
(sous peine de tomber sur des bugs bizarres lors du rechargement automatique
des vues). Par exemple, plutt que d'crire::

      class Truc(PrimaryView):
          def f(self, arg1):
              PrimaryView.f(self, arg1)

Il faut crire::
      
      class Truc(PrimaryView):
          def f(self, arg1):
              super(Truc, self).f(arg1)


XXX FILLME diagramme interaction application/controller/template/view