Spip es una herramienta ya utilizada por miles de personas, que tiene un pasado y un futuro. En su desarrollo, se han tomado ciertas decisiones, no siempre felices, que le han dado una consistencia al conjunto del código, facilitando su evolución. Así es que cuando una decisión se revela francamente incompatible con una nueva tecnología interesante a integrar, una reescritura de la parte problemática se pone en marcha, aún cuando puede tardar muchos meses.
Comprendemos entonces que es necesario evitar tanto como sea posible esas decisiones, y aceptar que ahí donde la nueva regla del código no se cumpla, la reescritura de esa parte del código se debe realizar.
Comprendemos también que si bien el estilo de programación puede variar un poco de un lugar a otro, se trata de construir una identidad común en perpetuo desarrollo de un software útil y usable no siendo las sagradas escrituras fijadas en papel biblia, sino la expresión de una comunidad viva y libre.
Organización del código fuente
A partir de la versión 1.9, es posible modificar el comportamiento de SPIP sin alterar el código fuente, gracias a la ruta de acceso definida por la constante SPIP_PATH
.
Toda extensión de SPIP debe operar entonces de manera tal que una prueba de integración sea desmontable mediante la simple redefinición de la ruta de acceso, estando la distribución de SPIP en solo lectura.
Si estás convencido que cierto comportamiento no se puede obtener de esa manera, escribí a la lista de correo de desarrolladores spip-dev [1].
Las contribuciones a SPIP deben ser descritas en un artículo en Spip-Contrib y su contenido debe estar disponible como archivos adjuntos a este artículo, o bien, mejor aún, en spip-zone que proporciona un servidor Subversion administrado por Trac.
Para extender SPIP así, se debe entender bien la organización de los directorios y el rol de sus archivos. Este es el objetivo del presente artículo, pero también se leerá el artículo anunciando SPIP 1.9 que lo introduce.
La raíz de una distribución de SPIP se compone esencialmente :
- un archivo
spip.php
, alias
index.php
, generando la compatibilidad con versiones anteriores, cargando el fichero de inicialización ecrire/inc_version.php
y pasando inmediatamente la mano al script principal ecrire/public.php
;
- un directorio
ecrire
compuesto exclusivamente de los archivos interpretados por la parte del servidor (PHP y MySQL);
- un directorio
dist
compuesto exclusivamente de los archivos interpretables por la parte del cliente (HTML, Javascript, hojas de estilo, imágenes de distintos formatos) así como los esquemas de compaginación llamados esqueletos. Estos esqueletos son interpretados por las dos partes:
se trata de archivos compuestos por un formato MIME y varias directivas SPIP, directivas tratadas por la parte del servidor con el fin de enviar al cliente un texto puramente MIME (la mayor parte del tiempo HTML, aunque también RSS, SVG, ICS, etc).
Según la manera en que esté instalado SPIP, otros directorios pueden aparecer en la raíz pero están vacíos en la instalación : contendrán los datos, temporales o permanentes, necesarios para la vida del sitio.
Funciones del directorio dist
y sus sub-directorios
directorio | función |
---|---|
/ |
contiene los esqueletos. Sus nombres terminan en .html por cuestiones históricas, pero esto no debe prejuzgar su contenido. Basta con poner el nombre, sin la extensión, en el parámetro page de la URL del sitio SPIP para desencadenar la utilización de este esqueleto.
La raíz del directorio |
formulaires/ |
contiene el contenido html de las balizas dinámicas, esqueletos de formularios cuyo código PHP se guarda en el directorio ecrire/balise |
icones_barre/ |
contiene las imágenes destinadas a ilustrar la barra de tipos |
images/ |
imágenes del espacio privado |
javascript/ |
bibliotecas javascript (jQuery, barra de tipos, ...) |
modeles/ |
esqueletos invocables con la baliza #MODELE o con los atajos <article6|modele> |
polices/ |
políticas utilizables por las imágenes tipográficas |
vignettes/ |
miniaturas estándar para los tipos de documentos que pueden estar asociados a un artículo |
Funciones del directorio ecrire
y sus sub-directorios
El directorio ecrire
se compone de muchos sub-directorios compuestos de archivos PHP que definen las funciones y procedimientos oportunamente, con menor frecuencia, de alguna inicialización de carga (se espera que estás excepciones tiendan a desaparecer). Los archivos situados al nivel del directorio principal son los más importantes de incluir para contribuir a SPIP, se tratan de inc_version.php
, public.php
e index.php
.
El archivo ecrire/inc_version.php
inicializa las constantes y las variables globales necesarias para el funcionamiento de SPIP, en particular aquellas que garantizan su portabilidad entre distintas plataformas.
Bien al principio de su carga, incluye el archivo inc/utils.php
, donde están las funciones indispensables para SPIP, un archivo ajeno a la distribución llamado mes_options.php
permite modifica la inicialización sin modificar el archivo inc_version.php
. En particular, es posible dentro de este mismo archivo invocar la función spip_initialisation
para definir directorios de datos y disponer así de varios sitios SPIP utilizando una sola distribución. (el llamado estándar de esta función, más abajo en el archivo inc_version.php
, sera neutralizado automáticamente). Otra función indispensable para SPIP es find_in_path
, donde se indica la ruta de acceso, así como include_spip
que a su vez se basa
find_in_path
,
y
charger_fonction
que se basa en
include_spip
. Todos los archivos de SPIP son cargados por estas dos últimas funciones.
El archivo
ecrire/public.php
, llamado por
spip.php
, tiene por función esencial devolver las páginas del espacio público controlado cuando la petición HTTP incluye (eventualmente después de una reescritura) el parámetro page
. Este script se aplica al esqueleto que tenga por nombre el valor de este parámetro. Envía las cabeceras HTTP y el contenido obtenido, generando los eventuales errores y lanzando las tareas en segunda plano con la ayuda de la función cron
. Contribuir al espacio público de SPIP consiste entonces de proveer nuevos esqueletos, con oportunamente sus hojas de estilo y sus imágenes.
La otra función de
ecrire/public.php
se ocupa del caso en que la petición HTTP incluye el argumento action
. Este aplica entonces la función
charger_fonction
al el valor v de este parámetro
exec
. Esta aplicación tiene por efecto la carga del archivo homónimo en el directorio action
, donde la función principal action_
v_dist
es invocada. Estos scripts efectúan distintas tareas que no retornan en general resultados, escapando así a las cuestiones de la compaginación.
El archivo
index.php
es el archivo central de acceso a los formularios del espacio privado. Este identifica al internauta, inicializa sus datos personales y aplica la función
charger_fonction
al valor v del parámetro exec
, donde la función principal exec_
v_dist
es invocada.
Esta está acargo de entregar la integridad del flujo de salida, incluso los encabezados HTTP. Es entonces posible extender a SPIP simplemente añadiendo un archivo PHP dentro de un sub-directorio llamado exec
de un directorio que aparezca dentro de SPIP_PATH
.
El directorio
exec
contiene exclusivamente los archivos que definen las funciones directamente invocables por el parámetro de la URL
exec
. El código fuente PHP de estos archivos no debe jamás acceder en escritura a la base de datos (las excepciones a esta regla están en vías de extinción). Por otra parte, hay abundantes accesos de lectura con el fin de verificar los derechos del solicitante y determinar los datos a mostrar. Si se quisiera ver a SPIP según la arquitectura Modelo-Vista-Controlador, los archivos de
exec
cumplen el papel del Controlador. Si vemos a SPIP según la arquitectura (Print(Eval(Read))) de Lisp, este es la parte Read. A largo plazo, este directorio deberá devenir en un directorio de esqueletos. Se pide para las nuevas contribuciones a SPIP pensar en este objetivo en sus desarrollo.
El directorio
action
, volviendo a este tema, contiene los scripts que acceden en escritura a la base de datos. Si se quisiera ver a SPIP según la arquitectura Modelo-Vista-Controlador, los archivos de
action
cumplen el papel del Modelo. Si vemos a SPIP según la arquitectura (Print(Eval(Read))) de Lisp, este es la parte Eval.
A partir de esto, contribuir a SPIP consiste en escribir tales scripts e invocarlos desde formularios construidos con la función generer_action_auteur
asegurando la autorización del acceso a estos scripts, que por otra parte invocarán a la función controler_action_auteur
para verificar los derechos del solicitante. Esta arquitectura permite calcular estos derechos solamente para la generación de los formularios invocando a los scripts de acceso de escritura: en vez de recalcular todos los derechos, estos scripts verifican simplemente la clave que aparece en los argumentos sea la misma que aquella que se recalcula a partir de los otros argumentos, a partir de la identidad del solicitante y de un número aleatorio renovado periódicamente. Estos scripts no devuelven resultados por lo general, ni generan tampoco código HTML, ni invoca a la función echo
(las excepciones deben ir desapareciendo)
En cambio, a menudo se llaman con un parámetro HTTP llamado redirect
, solicitando una redirección que será entonces automáticamente realizada por public.php
, que envía un status HTTP 204 en caso de ausencia de este parámetro.
Dentro de los formularios construidos con la función ajax_action_auteur
, esta redirección conduce a un script homónimo dentro del directorio exec
. Este segundo script se reduce generalmente a cargar un archivo homónimo en el directorio inc
, y de llamar a su función principal la cual su resultado es devuelto al cliente por medio de la función ajax_retour
. De esta manera es muy fácil de extender a SPIP en modo AJAX con el uso de esta infraestructura.
El directorio
inc
, el más voluminoso, contiene esencialmente las funciones que construyen las páginas del espacio privado devueltas al cliente, estas funciones deberán ser con el tiempo los filtros utilizados por los archivos de exec
cuando estos sean esqueletos. Si se quisiera ver a SPIP según la arquitectura Modelo-Vista-Controlador, los archivos de
inc
cumplen el papel de la Vista. Si vemos a SPIP según la arquitectura (Print(Eval(Read))) de Lisp, este es la parte Print. No obstante este directorio contiene igualmente muchas funciones relevantes que dependen más bien del Controlador y deberá entonces ser reorganizado. La mayoría de los archivos de
inc
son cargados por intermedio de
charger_fonction
, y este será el caso por un largo tiempo.
Ninguna de las funciones de este directorio deberán utilizar la función echo
. Se espera que las contribuciones a SPIP respecten esta regla de ahora en más.
El directorio
install
contiene exclusivamente las funciones necesarias para la instalación de SPIP. Cada etapa puede ser sobrecargada o completada por otras, la función principal de exec/install.php
utiliza este directorio según el mismo principio de ecrire/index.php
con el directorio exec
.
El directorio
urls
contiene los archivos que definen cada uno el mismo juego de funciones de reescritura de URL.
Se trata de funciones que calculan, a partir de un índice numérico dentro de una tabla de la base de datos, una notación más fácil de leer y escribir que invoca al script PHP operada por el servidor HTTP para este índice y tabla. De esta manera, basta con agregar un archivo nuevo a este directorio para obtener un nuevo juego, cuyo nombre modificará a la variable global type_urls
El directorio lang
contiene exclusivamente los archivos de datos, vectores indicando la traducción, para todos los idiomas conocidos por SPIP, de todos los argumentos que la función _T
, definida dentro de inc/utils.php
, es susceptible de recibir. Los archivos son cargados exclusivamente por las funciones de inc/lang.php
. Traducir los archivos de referencia *fr*
y dando un nombre convencional a los archivos obtenidos basta para declarar un nuevo idioma para SPIP.
El directorio charset
contiene él también exclusivamente archivos de datos, vectores constantes de conversión de un código de caracteres a otro (utf, iso, ascii, entidades html etc). Estos son usado exclusivo por las funciones de inc/charsets.php
. Basta entonces agregar un archivo para disponer de un nuevo código de caracteres, pero SPIP ya trae todos los juegos de caracteres usados generalmente, por lo tanto tal intervención es rarísima.
El directorio
base
contiene las funciones de interfaz entre PHP y la base de datos MySQL instalada. Las contribuciones posibles son esencialmente portar hacia otros servidores de bases de datos. No estuvo previsto desde el principio de SPIP, por lo tanto la interfaz para estas contribuciones está aún incompleta.
Se puede ver, que a pesar de estar incompleto, el archivo genérico
abstract_sql.php
, y su aplicación para MySQL dentro de db_mysql.php
si se quiere intentar la aventura de portarlo (los portages parciales se han realizado así).
Obviamente no debe aparecer ningún tipo MIME dentro de este directorio.
El directorio
balise
contiene los archivos PHP asociados a las balizas dinámicas de SPIP.
Sus nombre son homónimos de los esqueletos de dist/formulaires
. Completar el espacio público de SPIP para un formulario F consiste en crear un archivo F.html dentro del SPIP_PATH
y un archivo F.php dentro de un sub-directorio balise
del SPIP_PATH
. La función de este archivo PHP es la de recibir las datos introducidos en la petición para este formulario, y eventualmente de volver a indicar para complementarlo en caso de los datos introducidos sean inválidos. Es sin duda el tipo de contribución al espacio público más difícil de hacer, ya que la mecánica subyacente exige dos pasos de ejecución de PHP lo cual es necesario comprender los roles específicos.
Antes de que este mecanismo existiera, la estrategia de desarrollo de formularios consistía en escribir los esqueletos incluyendo las instrucciones PHP. Todavía hoy se puede hacer, sin embargo el resultado será poco eficiente ya que nunca se guarda en CACHE; ni tampoco evita tener que pasar por los dos pasos de PHP intrínsecos al fenómeno.
El directorio
public
contiene el compilador de esqueletos. Es una parte del código bastante complicada, pero a partir de SPIP 1.8 se beneficia de una interfaz de programación extensible que vuelve a este compilador totalmente extensible sin exigir incluir todos los detalles. Hay una descripción menos incompleta aquí.
El directorio
safehtml
es de hecho una biblioteca independiente de SPIP, que proporciona utilidades de protección de las páginas scriptables. Para contribuir en esta parte, remitirte directamente a site.
Último punto: la mayor parte de los archivos de SPIP son utilizados mediante charger_fonction
que carga un archivo e invoca su función homónima supuesta y definida allí. Por lo tanto se espera que el nombre de un archivo PHP debe estar compuesto exclusivamente por caracteres aceptables para un nombre de función PHP: evitar entonces los signos menos, el punto, etc.
Reglas de Programación
SPIP empezó en la época en que PHP transformaba automáticamente en variables globales los parámetros HTTP. Este estilo de programación suicida se abandonó en PHP4, en lo que se refiere a SPIP este cambio no se ha realizado por completo hasta el momento. Si bien todo el código actual no sigue estas reglas que debería seguir, se exige que se sigan en las contribuciones venideras como en las presentes, sin esperar que SPIP vaya corrigiéndose en un lugar u otro.
Se puede leer atentamente el archivo ecrire/articles.php
, el mejor se ajusta a las especificaciones que hay que seguir.
- Privilegiar la escritura por funciones. La filosofía del software libre es ser utilizado en la mayor cantidad de contextos diferentes, en consecuencia el código debe ser escrito dentro de un óptica de reutilización además de su contexto inicial de desarrollo. La escritura por funciones no referencia ninguna variable global ni efectúa ninguna llamada a echo
o
print
garantizando una carga silenciosa y una llamada sin efectos secundarios indeseables.
- Evitar al máximo la utilización de variables globales. Ellas son las responsables de numerosos fallos de seguridad y de imposibilitar la reutilización del código. Las alternativas a su uso son:
— las constantes, que tienen la ventaja de indicar al lector que este valor no cambiará a lo largo del script;
— las variables estáticas, que tienen la ventaja de indicar al lector que este se trata de un valor que tiene una larga vida aunque solo le concierne a la función que la declaró.
- Escribir código que no produzca ningún error ni warning en modo error_reporting(E_ALL)
. Eso facilita la depuración en caso de que una variable haya quedado indefinida por accidente. Si uno realmente necesita ejecutar código en otro modo que no sea este, usar el operador @ para la limitar el impacto del código problemático, y proveer un mensaje de error dentro del log, usando la función
spip_log
.
- Comentar el contexto, no el texto. No sirve de nada citar el nombre de las variables y las funciones, ni las funciones de PHP descritas en el manual:
los comentarios como iterando el vector de valores delante de un foreach
no hace más que agrandar innecesariamente el tamaño de los archivos. En cambio, es deseable indicar el tipo de los argumentos (como PHP es un lenguaje de tipos dinámicos, es difícil andar deduciéndolo) y las limitaciones que se esperan como valores de entrada (por ejemplo: no nulo). Cuando un bug difícil es corregido o anticipado, explicar porqué el código original era incorrecto para evitar que una reescritura ulterior lo reintroduzca creyendo que se está optimizando. Por último, SPIP está desarrollado en francés, evitar los términos que no aparezcan en los diccionarios de este idioma con el fin de facilitar la comprensión para aquellos los que este no es su idioma nativo.
- Nombrar racionalmente las funciones y variables. La organización del código de SPIP está más basada en el desacople en directorios dedicados que en las reglas de nomenclatura estrictas, pero se deben evitar de todos modos la inconsistencias como en la internacionalización en el interior de un nombre. Las funciones de un mismo archivo tenderán a tener un prefijo o sufijo común, inspirado en el nombre del archivo.
- Probar sobre un máximo de configuraciones. No te olvides que SPIP debe funcionar sobre toda plataforma, tanto del lado del cliente como del lado del servidor. Hay varios navegadores para tu máquina, testeá tu código con la menos dos de ellos. En la medida de lo posible, probalo también en varios hostings. Cuando una plataforma obligue una escritura extraña, mencionarlo explícitamente, especificando la versión y la fecha de la prueba.
Reglas de presentación y de escritura
SPIP se preocupa por la calidad tipográfica de las páginas que envía a los clientes HTTP, también se preocupa de sus propios archivos. Se recomienda respetar las siguientes reglas, casi estándares en programación.
Presentación
- El texto de las funciones debe ser corto, idealmente inferior al tamaño de una pantalla estándard, a fin de que la totalidad de su estructura sea visible de una sola ojeada.
- El texto de las funciones debe estar identado, cada bloque contenido dentro de un par de llaves debe ser corrido una unidad de identación más que el exterior, lo mismo se aplica, desde ya, recursivamente.
- Usar el caracter de tabulación para identar, lo que permite a cada uno elegir libremente la profundidad de identación dentro de las opciones de su editor de textos.
- Cuando una instrucción PHP ocupe varias líneas, dejar una línea en blanco antes y después.
- Los fragmentos HTML, que se traten de transiciones (<?php
y ?>
) o de expresiones PHP serán bloques XHTML completos: evitar poner meter un tag de apertura al principio de una función y su cierre al final, esto no permite mover fácilmente este par en caso de necesidad.
Tipográfico
- Sobre el uso de paréntesis o de corchetes, evitar los espacios después de la apertura y delante del cierre.
- Dentro de las expresiones PHP dejar un espacio de cada lado de los operadores binarios (+, =, *, AND, ...).
- Los operadores unarios (!, ...) debe estar pegados al parámetro sobre el que se aplican.
- Por convención, cuando se llama a una función, no ha de haber un espacio antes de abrir paréntesis : « f($x) » y no « f ($x) ». Por otra parte, y para distinguir bien, dejar un espacio delante del paréntesis cuando se trate de una estructura de control integrada al lenguaje : « if (!$x) » y no « if(!$x) ».
- Las comas y los punto pueden preceder un espacio, pero no ser precedidas por uno.