13. Creando complementos para personalizar Plone

En esta parte vamos a tratar:

  • Cree una distribución python personalizada llamada ploneconf.site para contener todo el código

  • Modificar la configuración buildout para instalar esa distribución

Tópicos cubiertos:

  • mr.bob y bobtemplates.plone

  • la estructura de los paquetes eggs

Creando la distribución

Nuestro propio código tiene que ser organizado como un paquete egg. Un paquete egg es un archivo zip o un directorio que sigue ciertas convenciones. Vamos a utilizar bobtemplates.plone para crear un proyecto de esqueleto. Tan sólo hay que responder a las preguntas del generador, las cuales crearán archivos necesarios para trabajar.

Nosotros accedemos al directorio src y ejecutamos un script llamado mrbob ubicado en nuestros directorio bin del buildout.

$ mkdir src      # (if src does not exist already)
$ cd src
$ ../bin/mrbob -O ploneconf.site bobtemplates:plone_addon

Tenemos que responder a algunas preguntas sobre el complemento. Vamos a presionar la tecla Enter (es decir, elegir el valor por defecto) para todas las preguntas, excepto la 3era pregunta (donde ingresa su nombre de usuario github si tiene uno) y la 5ta pregunta (versión Plone), donde ingresa 4.3.10.

--> What kind of package would you like to create? Choose between 'Basic', 'Dexterity', and 'Theme'. [Basic]:

--> Author's name [Philip Bauer]:

--> Author's email [bauer@starzel.de]:

--> Author's github username: fulv

--> Package description [An add-on for Plone]:

--> Plone version [4.3.9]: 4.3.10

Generated file structure at /vagrant/buildout/src/ploneconf.site

Si este es su primer paquete egg, éste es un momento muy especial. Vamos a crear el paquete egg con un script que genera una gran cantidad de archivos necesarios. Todos ellos son necesarios, pero a veces de una manera sutil. Se toma un tiempo entiendo su significado pleno. Sólo el año pasado he aprendido y entendido por qué debería tener un archivo MANIFEST.in. Usted puede vivir sin uno, pero confía en mí, te llevas mejor con un archivo de manifiesto adecuada.

Inspeccionando la distribución

En la carpeta src ahora hay una nueva carpeta ploneconf.site y ahí está la nueva distribución. Echemos un vistazo a algunos de los archivos:

bootstrap-buildout.py, buildout.cfg, travis.cfg, .travis.yml, .coveragerc

Puede pasar por alto estos archivos por ahora. Ellos están aquí para crear un buildout sólo para este paquete egg para hacer las pruebas más fáciles. Una vez que empezamos a escribir las pruebas para este paquete tendremos que actualizar estos archivos a las actuales mejores prácticas y versiones.

README.rst, CHANGES.rst, CONTRIBUTORS.rst, docs/

La documentación y el archivo de registro de cambios, el archivo de la lista de contribuidores y el archivo de la licencia de su paquete egg van allí.

setup.py

Este archivo configura el paquete, su nombre, las dependencias y algunos metadatos como el nombre del y correo electrónico del autor. Las dependencias listadas aquí son descargadas automáticamente por buildout.

src/ploneconf/site/

La distribución Python en si misma vive dentro de una estructura de carpetas especial. Eso parece confuso, pero es necesario para tener buena habilidad de prueba. Nuestra distribución contiene un paquete de espacio de nombres llamado ploneconf.site y debido a esto hay una carpeta ploneconf con un archivo __init__.py y allí hay otra carpeta site y ahí finalmente está nuestro código. Desde la perspectiva de buildout, nuestro código está en la ruta <su directorio buildout>/src/ploneconf.site/src/ploneconf/site/<real code>

Nota

A menos que discutamos el buildout, de ahora en adelante, omitiremos silenciosamente estas carpetas al describir los archivos y asumiremos que <su directorio buildout>/src/ploneconf.site/src/ploneconf/site/ ¡es el directorio raíz de nuestra distribución Python!

configure.zcml (src/ploneconf/site/configure.zcml)

La guía de los paquetes. De su lectura se puede averiguar qué funcionalidad está registrado a través de la arquitectura de componentes.

setuphandlers.py (src/ploneconf/site/setuphandlers.py)

Esto contiene el código que se ejecuta automáticamente al instalar y desinstalar nuestro complemento.

interfaces.py (src/ploneconf/site/interfaces.py)

Aquí se define un browserlayer en una simple clase de python. Lo necesitaremos más tarde.

testing.py

Esta contiene la configuración para correr las pruebas del paquete.

tests/

Esta contiene las pruebas del paquete.

browser/

Este directorio es un paquete python (porque tiene un __init__.py) y por convención contiene la mayoría de las cosas que son visibles en el navegador.

browser/configure.zcml

La guía del paquete del browser. Aquí se registran vistas, recursos y sobre-escrituras de Plone.

browser/overrides/

Este complemento ya está configurado para permitir la sustitución o sobre-escritura de las plantillas por defecto de Plone existentes.

browser/static/

Un directorio que contiene los recursos estáticos (archivos de imágenes, CSS y JS). Los archivos aquí serán accesibles a través de las URLs como ++resource++ploneconf.site/myawesome.css

profiles/default/

La carpeta contiene el perfil GenericSetup. Durante el entrenamiento pondrán algunos archivos XML ahí que tienen la configuración para el sitio.

profiles/default/metadata.xml

Número de versión y dependencias que son auto-instalado cuando esta instalando su propio complemento.

Incluyendo el paquete egg en Plone

Antes de poder utilizar nuestro nuevo complemento tenemos que indicarle de la existencia de este a Plone. Entonces edite el archivo buildout.cfg y descomente el paquete egg ploneconf.site en las secciones eggs y sources:

eggs =
    Plone
    ...
    ploneconf.site
#    starzel.votable_behavior

...

[sources]
collective.behavior.banner = git https://github.com/collective/collective.behavior.banner.git pushurl=git@github.com:collective/collective.behavior.banner.git rev=af2dc1f21b23270e4b8583cf04eb8e962ade4c4d
ploneconf.site = fs ploneconf.site full-path=${buildout:directory}/src/ploneconf.site
# starzel.votable_behavior = git https://github.com/collective/starzel.votable_behavior.git pushurl=git://github.com/collective/starzel.votable_behavior.git

Esto le dice a Buildout agregue el paquete egg ploneconf.site. Dado que también se encuentra en la sección sources en Buildout no intentará descargarlo de PYPI pero esperará en src/ploneconf.site. La opción fs le permite añadir paquetes en el sistema de ficheros sin un sistema de control de versiones, o con uno compatible.

Ahora ejecute buildout para reconfigurar Plone con la configuración actualizada:

$ ./bin/buildout

Después reinicie Plone con el comando ./bin/instance fg el nuevo complemento ploneconf.site está disponible para instalar como PloneFormGen o Plone True Gallery.

No vamos a instalarlo ahora, ya que no añadimos aun nada de nuestro propio código fuente o configuración todavía. Vamos a hacer eso.

Volver Dexterity: para mover tipos de contenidos a código fuente

¿Recuerda el tipo de contenido Talk que hemos creado a través de la Web con Dexterity? Vamos a pasar ese nuevo tipo de contenido a dentro de nuestro paquete egg para que pueda ser instalado en otros sitios sin manipulación a través de la Web.

Pasos:

  • Volver al panel del control Tipos de contenido Dexterity

  • Haga clic en la casilla junto al Tipo de contenido Talk y hace clic en el botón Exportar los perfiles del tipo y guardarlo en el archivo

  • Elimine el Tipo de contenido Talk desde el panel del control Tipos de contenido Dexterity en su sitio Plone ante de instalarlo desde el sistema de archivo

  • Extrae los archivos desde el archivo tar exportado y agréguelo entonces en nuestro paquete en la ruta ploneconf/site/profiles/default/

El archivo ploneconf/site/profiles/default/types.xml le dice a que allí tiene un nuevo tipo de contenido definido en el archivo talk.xml.

<?xml version="1.0"?>
<object name="portal_types" meta_type="Plone Types Tool">
 <property name="title">Controls the available content types in your portal</property>
 <object name="talk" meta_type="Dexterity FTI"/>
 <!-- -*- more types can be added here -*- -->
</object>

Tras la instalación, Plone lee el archivo ploneconf/site/profiles/default/types/talk.xml y registra un nuevo tipo de contenido en la herramienta portal_types (puede encontrar esta en el ZMI) con la información tomada de ese archivo.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
  <?xml version="1.0"?>
  <object name="talk" meta_type="Dexterity FTI" i18n:domain="plone"
     xmlns:i18n="http://xml.zope.org/namespaces/i18n">
   <property name="title" i18n:translate="">Talk</property>
   <property name="description" i18n:translate="">None</property>
   <property name="icon_expr">string:${portal_url}/document_icon.png</property>
   <property name="factory">talk</property>
   <property name="add_view_expr">string:${folder_url}/++add++talk</property>
   <property name="link_target"></property>
   <property name="immediate_view">view</property>
   <property name="global_allow">True</property>
   <property name="filter_content_types">True</property>
   <property name="allowed_content_types"/>
   <property name="allow_discussion">False</property>
   <property name="default_view">view</property>
   <property name="view_methods">
    <element value="view"/>
   </property>
   <property name="default_view_fallback">False</property>
   <property name="add_permission">cmf.AddPortalContent</property>
   <property name="klass">plone.dexterity.content.Container</property>
   <property name="behaviors">
    <element value="plone.app.dexterity.behaviors.metadata.IDublinCore"/>
    <element value="plone.app.content.interfaces.INameFromTitle"/>
   </property>
   <property name="schema"></property>
   <property
      name="model_source">&lt;model xmlns:security="http://namespaces.plone.org/supermodel/security" xmlns:marshal="http://namespaces.plone.org/supermodel/marshal" xmlns:form="http://namespaces.plone.org/supermodel/form" xmlns="http://namespaces.plone.org/supermodel/schema"&gt;
      &lt;schema&gt;
        &lt;field name="type_of_talk" type="zope.schema.Choice"&gt;
          &lt;description/&gt;
          &lt;title&gt;Type of talk&lt;/title&gt;
          &lt;values&gt;
            &lt;element&gt;Talk&lt;/element&gt;
            &lt;element&gt;Training&lt;/element&gt;
            &lt;element&gt;Keynote&lt;/element&gt;
          &lt;/values&gt;
        &lt;/field&gt;
        &lt;field name="details" type="plone.app.textfield.RichText"&gt;
          &lt;description&gt;Add a short description of the talk (max. 2000 characters)&lt;/description&gt;
          &lt;max_length&gt;2000&lt;/max_length&gt;
          &lt;title&gt;Details&lt;/title&gt;
        &lt;/field&gt;
        &lt;field name="audience" type="zope.schema.Set"&gt;
          &lt;description/&gt;
          &lt;title&gt;Audience&lt;/title&gt;
          &lt;value_type type="zope.schema.Choice"&gt;
            &lt;values&gt;
              &lt;element&gt;Beginner&lt;/element&gt;
              &lt;element&gt;Advanced&lt;/element&gt;
              &lt;element&gt;Professionals&lt;/element&gt;
            &lt;/values&gt;
          &lt;/value_type&gt;
        &lt;/field&gt;
        &lt;field name="speaker" type="zope.schema.TextLine"&gt;
          &lt;description&gt;Name (or names) of the speaker&lt;/description&gt;
          &lt;title&gt;Speaker&lt;/title&gt;
        &lt;/field&gt;
        &lt;field name="email" type="zope.schema.TextLine"&gt;
          &lt;description&gt;Adress of the speaker&lt;/description&gt;
          &lt;title&gt;Email&lt;/title&gt;
        &lt;/field&gt;
        &lt;field name="image" type="plone.namedfile.field.NamedBlobImage"&gt;
          &lt;description/&gt;
          &lt;required&gt;False&lt;/required&gt;
          &lt;title&gt;Image&lt;/title&gt;
        &lt;/field&gt;
        &lt;field name="speaker_biography" type="plone.app.textfield.RichText"&gt;
          &lt;description/&gt;
          &lt;max_length&gt;1000&lt;/max_length&gt;
          &lt;required&gt;False&lt;/required&gt;
          &lt;title&gt;Speaker Biography&lt;/title&gt;
        &lt;/field&gt;
      &lt;/schema&gt;
    &lt;/model&gt;</property>
   <property name="model_file"></property>
   <property name="schema_policy">dexterity</property>
   <alias from="(Default)" to="(dynamic view)"/>
   <alias from="edit" to="@@edit"/>
   <alias from="sharing" to="@@sharing"/>
   <alias from="view" to="(selected layout)"/>
   <action title="View" action_id="view" category="object" condition_expr=""
      description="" icon_expr="" link_target="" url_expr="string:${object_url}"
      visible="True">
    <permission value="View"/>
   </action>
   <action title="Edit" action_id="edit" category="object" condition_expr=""
      description="" icon_expr="" link_target=""
      url_expr="string:${object_url}/edit" visible="True">
    <permission value="Modify portal content"/>
   </action>
  </object>

Ahora nuestro paquete tiene algunos contenidos reales. Por lo tanto, tendremos que volver a instalarlo (si está instalado antes).

  • Reinicie Plone.

  • Reinstale el paquete ploneconf.site (desactive y active).

  • Valla a la ZMI y vea la definición del nuevo tipo de contenido en la herramienta portal_types.

  • Pruebe el tipo de contenido agregando un objeto o la edición de una de las entradas antiguas.

  • Mire cómo se presentan los tipo de contenidos talks en el navegador.