Manual de Estilo de Código

De MoodleDocs

Cualquier proyecto colaborativo necesita que la consistencia y la estabilidad sean fuertes.

Este manual de estilo ha sido escrito para conseguir que todo el código de Moodle cumpla estas características. Es cierto que la parte más antigua del código no cumple lo aquí especificado en algunos casos, pero esto será solucionado gradualmente. Todo el código nuevo definitivamente deberá adherirse a estos estándares de la forma más exacta posible.


Reglas Generales

  1. Todos los ARCHIVOS DE CÓDIGO deberían utilizar la extensión .php.
  2. Todas las PLANTILLAS deberían utilizar la extensión .html.
  3. Todos los ARCHIVOS DE TEXTO deberían utilizar el formato de texto Unix (la mayoría de los editores de texto tienen esto como una opción).
  4. Todas las ETIQUETAS php deben ser 'completas' como <?php ?> ... no 'reducidas' como <? ?>.
  5. Todos los AVISOS DE COPYRIGHT deben ser mantenidos. Puede incluir los suyos propios si resulta necesario.
  6. Todos los ARCHIVOS deben incluir el archivo principal config.php.
  7. Cualquier otro include/require debería utilizar una RUTA absoluta que comience por $CFG->dirroot o $CFG->libdir, nunca relativos, ya que estos en algunas ocasiones funcionan de forma extraña en PHP.
  8. Cada archivo debería comprobar que el usuario está AUTENTICADO correctamente, utilizando las funciones require_login() y isadmin(), isteacher(), iscreator() o isstudent().
  9. Todos los ACCESOS A LA BASE DE DATOS deberían utilizar las funciones definidas en lib/datalib.php cuando sea posible - esto permite la compatibilidad con un gran número de bases de datos. Debería encontrar que prácticamente todo es posible utilizando estas funciones. Si quiere escribir código SQL entonces deberá comprobar que: funciona en cualquier plataforma; restringido a funciones específicas de su código (normalmente un archivo lib.php); y claramente comentado.
  10. No cree o utilice VARIABLES globales distintas de las estándar $CFG, $SESSION, $THEME, $SITE, $COURSE y $USER.
  11. Todas las VARIABLES deberían ser inicializadas o, al menos, comprobada su existencia utilizando isset() o empty() antes de ser utilizadas.
  12. Todas las CADENAS deberían ser traducibles - cree nuevos textos en los archivos "lang/es_utf8" con palabras reducidas en inglés y su traducción completa al Español y recupérelas en su código utilizando las funciones get_string() or print_string().
  13. Todos los ERRORES deberían ser visualizados utilizando la función print_error() para maximizar la traducción y ayudar a los usuarios (Automáticamente se enlaza con Moodle Docs).
  14. Todos los FICHEROS DE AYUDA deben ser traducibles - cree nuevos textos en el directorio "lang/es_utf8/help" y llámelos utilizando la función helpbutton(). Si necesita actualizar un fichero de ayuda:
    • para un pequeño CAMBIO, donde la traducción antigua del fichero podría tener todavía sentido, está permitido que haga el cambio, pero debería notificárselo a translation@moodle.org
    • para un CAMBIO importante tendrá que crear un nuevo fichero añadiéndole en el nombre un número incrementado (p.ej. filename2.html) para que los traductores puedan ver fácilmente que se trata de una nueva versión del archivo. Obviamente el nuevo código y los índices de las páginas de ayuda deben ser modificados para apuntar a las versiones más recientes.
  15. La INFORMACIÓN que llega desde el navegador (enviada con los métodos GET o POST) automáticamente tiene las "magic_quotes" aplicadas (sin importar la configuración de PHP) por lo que puedes insertarla con total seguridad en la base de datos. El resto de la información(obtenida desde los archivos, o desde la base de datos) debe ser escapada con la función addslashes() antes de insertarla en la base de datos.
  16. MUY IMPORTANTE: Todos los textos dentro de Moodle, especialmente aquellos que han sido introducidos por los usuarios, deben ser mostrados utilizando la FUNCIÓN format_text(). Esto asegura que el texto es filtrado y limpiado correctamente.
  17. Las ACCIONES DE LOS USUARIOS deberían ser grabadas utilizando la función add_to_log(). Estos registros son utilizados para la generación de los "Informes de Actividad" y los Registros.
  18. Al generar ENLACES HTML, hágalos siempre relativos a la raíz del sitio Moodle, por ejemplo, enlace a $CFG->wwwroot/mod/blonk/view.php?id=99 en lugar de únicamente view.php?id=99. Esto causa que su código funcionará aunque sea llamado por un script que se encuentre en otra carpeta diferente.


Estilo del Código

Comprendo que puede ser un poco frustrante modificar su estilo de programación si ha trabajado en otras cosas, pero compara esa frustración con la frustración de toda la gente que intente, más adelante, encontrar el sentido del código de Moodle si es una mezcla de estilos. Obviamente, hay muchos puntos a favor y en contra de cada estilo que la gente utiliza, pero el que se detalla aquí es el que deberá utilizar.

1. El sangrado del texto debe ser siempre de 4 espacios. No utilices los tabuladosres NUNCA. 2. Los nombres de las variables tienen que ser siempre fáciles de leer, procurando que sean palabras en minúsculas con significado en Inglés. Si realmente necesita más de una palabra, póngalas juntas, pero procure mantenerlas tan breves como sea posible. Utilize nombres en plural para las matrices de objetos.

     BIEN: $quiz
     BIEN: $errorstring
     BIEN: $assignments (for an array of objects)
     BIEN: $i (but only in little loops)
     MAL: $Quiz 
     MAL: $aReallyLongVariableNameWithoutAGoodReason
     MAL: $error_string

3. Las constantes tienen que definirse siempre en mayúsculas, y empezar siempre por el nombre del módulo al que pertenecen. Deberían tener las palabras separadas por guiones bajos.

     define("FORUM_MODE_FLATOLDEST", 1);

4. Los nombres de las funciones tienen que ser palabras sencillas en minúsculas y en Inglés, y empezar con el nombre del módulo al que pertenecen para evitar conflictos entre módulos. Las palabras deberían separarse por guiones bajos. Los parámetros, si es posible, tendrán valores por defecto. Compruebe que no haya espacio entre el nombre de la función y lo siguiente (paréntesis).

     function forum_set_display_mode($mode=0) {
         global $USER, $CFG;
     
         if ($mode) {
             $USER->mode = $mode;
         } else if (empty($USER->mode)) {
             $USER->mode = $CFG->forum_displaymode;
         }
     }

5. Los bloques de código siempre deben estar encerrados por llaves (incluso si solo constan de una línea). Moodle utiliza este estilo:

     if ($quiz->attempts) {
         if ($numattempts > $quiz->attempts) {
             error($strtoomanyattempts, "view.php?id=$cm->id");
         }
     }

6. Las cadenas tienen que ser definidas utilizando comillas simples siempre que sea posible, para obtener un mejor rendimiento.

     $var = 'some text without any variables';
     $var = "with special characters like a new line \n";
     $var = 'a very, very long string with a '.$single.' variable in it';
     $var = "some $text with $many variables $within it";

7. Los comentarios deben ser añadidos de forma que resulten prácticos, para explicar el flujo del código y el propósito de las funciones y variables.

  • Cada función (y cada clase) debería utilizar el popular formato phpDoc. Esto permite que la documentación sea generada automáticamente.
  • Los comentarios en línea deberían utilizar los caracteres //, alineados con cuidado por encima de las líneas de código que comenta.
     /**
     * The description should be first, with asterisks laid out exactly
     * like this example. If you want to refer to a another function,
     * do it like this: {@link clean_param()}. Then, add descriptions 
     * for each parameter as follows.
     *
     * @param int $postid The PHP type is followed by the variable name
     * @param array $scale The PHP type is followed by the variable name
     * @param array $ratings The PHP type is followed by the variable name
     * @return mixed
     */
     function forum_get_ratings_mean($postid, $scale, $ratings=NULL) {
         if (!$ratings) {
             $ratings = array();     // Initialize the empty array
             if ($rates = get_records("forum_ratings", "post", $postid)) {
                 // Process each rating in turn
                 foreach ($rates as $rate) { 
     ....etc

8. El espacio en blanco se puede utilizar con bastante libertad - no se preocupe por separar las cosas un poco para ganar en claridad. Generalmente, debería haber un espacio entre llaves y líneas normales y ninguno entre llaves y variables o funciones:

     foreach ($objects as $key => $thing) {
         process($thing); 
     } 
     
     if ($x == $y) {
         $a = $b;
     } else if ($x == $z) {
         $a = $c;
     } else {
         $a = $d;
     }

9. Cuando esté realizando una COPIA de un objeto, utilice siempre la función clone() originalmente sólo disponible en php5 (en caso contrario simplemente tendrá una referencia al primer objeto). Moodle le garantiza que este método funcionará también bajo php4.

     MAL:   $b = $a;
     BIEN:  $b = clone($a);

Si la "cosa" que quiere copiar no es un objeto, pero puede contener objetos (p.ej. un array de objetos) utilice la función fullclone() en su lugar.

Estructuras de la base de datos

  1. Cada tabla debe tener un campo autonumérico id (INT10) como clave primaria.
  2. La tabla principal que contiene instancias de cada módulo debe tener el mismo nombre que el módulo y contener, por lo menos, los siguientes campos:
    • id - descrito arriba
    • course - el identificador del curso al que la instancia pertenece
    • name - el nombre completo de la instancia
  3. El resto de las tablas asociadas con un módulo que contiene información sobre 'cosas', deberían ser llamandas modulo_cosas (fíjese en el plural!).
  4. Los nombres de las tablas y de los campos tienen que evitar el uso de palabras reservadas por las Bases de Datos. Por favor, compruébelo antes de crearlas.
  5. Los nombres de los campos (columnas) deberían ser sencillos y cortos, siguiendo las mismas reglas que los nombres de las variables.
  6. Cuando sea posible, las columnas que contengan una referencia al campo id de otra tabla (por ejemplo, modulo) debería ser llamado moduloid. (fíjate que esta norma es nueva y no es seguida por algunas tablas antiguas).
  7. Los campos booleanos serán implementados como enteros cortos (por ejemplo, INT4) con los valores 0 o 1, para permitir la futura expansión de los valores si fuera necesario.
  8. La mayoría de las tablas tienen que tener un campo timemodified (INT10) que será actualizado con la fecha actual (timestamp de UNIX) obtenida con la función time() de PHP.
  9. Defina siempre un valor por defecto para cada campo (y haga que tenga sentido).
  10. Cada tabla debe comenzar con el prefijo de la base de datos ($CFG->prefix). En muchos casos esto es gestionado automáticamente. Además, bajo PostgreSQL, el nombre de cada índice debe empezar también con el prefijo.
  11. Para garantizar la compatibilidad entre bases de datos, por favor, siga las reglas siguientes sobre el uso del comando AS (solo si necesita alias en tablas/campos, por supuesto):
    • No utilice el comando AS para alias de tablas.
    • Utilice el comando AS para alias de campos (columnas).
  12. Nunca cree UNIQUE KEYs (restricciones) para nada. En su lugar utilice UNIQUE INDEXes. En el futuro, si se decide añadir integridad referencial a Moodle y si se necesitan UNIQUE KEYs, serán utilizadas, pero no por ahora. Por favor, fíjese que el Editor XMLDB permite especificar tanto restricciones UNIQUE y FOREIGN (y eso es bueno, teniendo el XML bien definido), pero solo los índices subyacentes serán realmente generados en la DB.
  13. Esas UNIQUE KEYs creadas en el Editor XMLDB (lea el punto anterior) solo debe ser definida si el campo/campos van a ser el objetivo para alguna FOREIGN KEY (a nivel de Editor). En caso contrario, creelas como UNIQUE INDEXes.
  14. Las tablas asociadas con un bloque deben seguir las siguientes convenciones en sus nombres: $CFG->prefix + "block_" + nombre del bloque + añadidos. Por ejemplo, asumiendo que $CFG->prefix es 'mdl_', todas las tablas para el bloque "rss_client" deberán empezar por 'mdl_block_rss_client' (siendo posible añadir más palabras al final, p.ej. 'mdl_block_rss_client_anothertable'...). Esta regla será completamente forzada con Moodle 2.0, dando algo de tiempo a los desarrolladores hasta entonces. Vea la Tarea 6786 para más información sobre esto.
  15. Nunca realice cambios a la base de datos en ramas ESTABLES. Si hacemos eso, entonces los sitios actualizando de una versión estable a la siguiente pueden encontrarse con cambios por duplicado, lo cual puede producir errores serios.
  16. Cuando haga referencia a una variable entera en consultas SQL, no entrecomille el valor. Por ejemplo, get_records_select('question', "category=$catid") es correcto. get_records_select('question', "category='$catid'") es incorrecto. Ese uso oculta posibles errores cuando $catid está sin definir. (Esta discusión lo explica.)

Normas de Seguridad (y control de la información de formularios y URLs)

  1. No se base en 'register_globals'. Cada variable debe ser correctamente inicializada en cada fichero de código. Debe ser obvia la procedencia de cada variable.
  2. Inicialice todos los arrays y objetos aunque estén vacíos. $a = array() o $obj = new stdClass();.
  3. No utilice la función optional_variable(). En su lugar, utilice la función optional_param(). Seleccione la opción PARAM_XXXX apropiada al tipo de parámetro que espera. Para comprobar y definir un valor opcional para una variable, utilice la función set_default().
  4. No utilice la función require_variable(). En su lugar, utilice la función required_param(). Seleccione la opción PARAM_XXXX apropiada al tipo de parámetro que espera.
  5. Utilice data_submitted(), con cuidado. La información todavía debe ser limpiada antes de utilizarla.
  6. No utilice $_GET, $_POST o $_REQUEST. En su lugar, utilice las funciones required_param() o optional_param() apropiadas.
  7. No compruebe las acciones con código como: if (isset($_GET['algo'])). Utilice, por ejemplo, $algo = optional_param( algo, -1, PARAM_INT ) y entonces compruebe que está dentro de los valores esperados, por ejemplo, if ($something>=0) {....
  8. Cuando sea posible agrupe todas sus llamadas a required_param(), optional_param() y el resto de inicialización de variables en el principio de cada fichero (o función) para que sea fácilmenente localizable.
  9. Utilice el mecanismo 'sesskey' para proteger el envío de formularios de ataques. Un ejemplo de uso: cuando el formulario es generado, incluya <input type="hidden" name="sesskey" value="<?php echo sesskey(); ?>" />. Cuando el formulario es procesado, compruebe if (!confirm_sesskey()) {error('Bad Session Key');}.
  10. Todos los nombres de ficheros deben ser 'limpiados' utilizando la función clean_filename(), si esto no ha sido realizado con el uso de las funciones required_param() o optional_param() con anterioridad.
  11. Cualquier información leída desde la base de datos debe tener la función addslashes() aplicada antes de volver a enviar la información a la base de datos. Un objeto completo puede ser procesado con la función addslashes_object().
  12. Cuando sea posible, la información que se almacenará en la base de datos debe venir de peticiones POST (por ejemplo, información de un formulario) en lugar de utilizar peticiones GET (por ejemplo, información de la URL).
  13. No utilice información obtenida de $_SERVER si puede evitarlo. Presenta algunos problemas de portabilidad.
  14. Si no ha sido realizado en ningún otro lugar, asegurese de que la información enviada a la base de datos ha sido filtrada mediante la función clean_param() utilizando la opción PARAM_XXXX apropiada.
  15. Si escribe código SQL, asegurese completamente de que es correcto. En particular, compruebe la falta de comillas en las variables utilizadas. Es un punto de entrada para ataques de tipo 'SQL injection'.
  16. Compruebe toda la información (especialmente la que es enviada a la base de datos) en cada archivo que es utilizada. Nunca confíe en que otro código estará haciendo ese trabajo.
  17. Los bloques de código que se incluyan deben presentar una estructura PHP correcta (por ejemplo, con una declaración de una clase, de funciónes, etc.) - los bloques de código lineales ("espagueti") suelen tender a utilizar variables sin inicializar (y son menos legibles).
  18. Si necesita usar shell_exec() (o cualquier otra función que invoque un shell), asegúrese de que ha limpiado los parámetros anteriormente con escapeshellcmd()/escapeshellarg() (de lo contrario abrimos la puerta a ataques de inyección de shell).