Note:

If you want to create a new page for developers, you should create it on the Moodle Developer Resource site.

Coding: Difference between revisions

From MoodleDocs
(Note regarding new page(s) added)
(DRAFT!)
Line 1: Line 1:
<p class="note">'''Note''': This page is in the process of a major overhaul, see [[Coding style]].   
This page is the top-level page describing Moodle's coding guidelinesIt's the place to start if you want to know how to write code for Moodle.
</p>


Any collaborative project needs consistency and stability to stay strong.
WARNING: Under construction RIGHT NOW!


These '''coding guidelines''' are to provide a goal for all Moodle code to strive to. It's true that some of the older existing code falls short in a few areas, but it will all be fixed eventually. All new code definitely must adhere to these standards as closely as possible.


==General rules==


# All '''code''' files should use the '''.php''' extension.
==Moodle architecture==
# All '''template''' files should use the '''.html''' extension.
# All text files should use '''Unix-style text format''' (most text editors have this as an option).
# All php tags must be 'full' tags like '''<?php ?>''' ... not 'short' tags like <? ?>.
# All existing '''copyright notices must be retained'''. You can add your own if necessary.
# Each file should '''include (require_once) the main config.php''' file.
# Any '''other include/require should use an absolute path''' beginning with $CFG->dirroot or  $CFG->libdir, not relative includes, which [http://uk.php.net/manual/en/function.include.php sometimes behave strangely under PHP].
# Includes should be done at the top of files or inside functions/methods, do not include/require in the middle of file in global scope
# Each file should '''check that the user is authenticated correctly''', using require_login() and has_capability() or require_capability().
# All '''access to databases should use the functions in ''lib/dmllib.php''''' whenever possible - this allows compatibility across a wide range of databases. You should find that almost anything is possible using these functions. If you must write SQL code then make sure it is: cross-platform; restricted to specific functions within your code (usually a lib.php file); and clearly marked.
# '''Don't create new global variables'''. Use only the Moodle-standard $CFG, $SESSION, $THEME, $SITE, $COURSE and $USER global variables.
# '''All variables should be initialised''' or at least tested for existence using isset() or empty() before they are used.
# '''All strings should be translatable''' - create new texts in the "lang/en_utf8" files with concise English lowercase names and retrieve them from your code using get_string() or print_string(). Never delete strings to ensure backwards compatibility of the language packs is maintained.
# '''Don't use p() and s() functions''' to print language strings. Those functions are not designed to print html with tags. Use echo() instead.
# All '''errors should be printed using print_error()''' to maximise translation and help for users (it automatically links to the docs wiki).
# All '''help files should be translatable''' - create new texts in the "lang/en_utf8/help" directory and call them using helpbutton(). If you need to update a help file:
#* with a minor change, where an old translation of the file would still make sense, then it's OK to make the change but you should notify translation AT moodle DOT org.
#* for a major change you should create a new file by adding an incrementing number (eg filename2.html) so that translators can easily see it's a new version of the file. Obviously the new code and the help index files should also be modified to point to the newest versions.
# Incoming data from the browser (sent via '''GET or POST) automatically has magic_quotes applied''' (regardless of the PHP settings) so that you can safely insert it straight into the database. '''All other raw data (from files, or from databases) must be escaped with addslashes()''' before inserting it into the database. Because this is so often done incorrectly, there is more explanation on this issue of adding and stripping slashes on a [[Developer:Slashes|separate page]].
# VERY IMPORTANT: Within Moodle, '''All texts should be printed using the format_text() function''', especially those that have come from users. This ensures that text is filtered and cleaned correctly. More information can be found on the page about [[Output_functions|output functions]].
# User actions should be logged using the [[Logs|add_to_log()]] function. These logs are used for [[Settings#Show_activity_reports|activity reports]] and [[Logs]].
# '''Always create HTML links relative to the full site root''', i.e. link to  ''$CFG->wwwroot/mod/blonk/view.php?id=99'' rather than just ''view.php?id=99''. This means that your code will work if called by a script in another folder, among other things.
# Modules should '''store config variables using ''set_config('varname', $value, 'mod/modulename')''''' where the last parameter is the path to the module directory.
# '''Respect decimal separators specified''' in language pack - do not use number_format() directly, instead use format_float() and unformat_float() when displaying or processing floating point numbers (mandatory in 2.0)


==Coding style==
Moodle tries to run on the widest possible range of platforms, for the widest possible number of people, while remaining easy to install, use, upgrade and integrate with other systems.


I know it can be a little annoying to change your style if you're used to something else, but balance that annoyance against the annoyance of all the people trying later on to make sense of Moodle code with mixed styles. There are obviously many good points for and against any style that people use, but the current style just is, so please stick to it.
For more about this, see: [[Moodle_architecture]].


=== Indentation ===
==Plugins==  
Indenting should be consistently '''4 spaces'''. Don't use tabs AT ALL. Do not indent the main script level.


GOOD:
Moodle has a general philosophy of modularity.  There are over 25 different types of plugins, however many of these plugin types work the same way.
<code php>
<?php // $Id$
$a = required_param('a', PARAM_INT);
do_something_with($a);
?>
</code>


BAD:
For more about the structure of plugins, see [[Plugins|Moodle plugins]].
<code php>
<?php // $Id$
    $a = required_param('a', PARAM_INT);
    do_something_with($a);
?>
</code>


=== Variable names ===
==Coding style==
Variable names should always be easy-to-read, '''meaningful lowercase English''' words. If you really need more than one word then run them together, but keep them short as possible. Use plural names for arrays of objects.
 
  GOOD: $quiz
  GOOD: $errorstring
  GOOD: $assignments (for an array of objects)
  GOOD: $i (but only in little loops)
 
  BAD: $Quiz
  BAD: $aReallyLongVariableNameWithoutAGoodReason
  BAD: $error_string
 
=== Constants ===
Constants should always be in '''upper case''', and always start with the name of the module. They should have words separated by underscores.
 
<code php>
define('FORUM_MODE_FLATOLDEST', 1);
</code>
 
This might also be applied to PHP's build in constants TRUE, FALSE, and NULL.
 
=== Function names ===
Function names should be '''simple English lowercase words''', and start with the name of the module to avoid conflicts between modules. Words should be separated by underscores. Parameters should always have sensible defaults if possible. Note there is no space between the function name and the following (brackets).
 
<code php>
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;
        }
}
</code>


The same applies to naming '''classes''' and their '''methods'''. Use lowercase words separated by underscores.
Consistent coding style is important in any development project, and particularly so when many developers are involved. A standard style helps to ensure that the code is easier to read and understand, which helps overall quality.  


<code php>
Writing your code in this way will ensure your code is an important step to having your code accepted by the Moodle community.
class some_custom_class {
    function class_method() {
          ...
    }
}
</code>


Note there are some exceptions in the code using '''CamelCase''': class SomeCustomClass {function classMethod(){...}}, but these are usually there because of compatibility with thirds party libraries (e.g. formslib).
Our [[Coding_style|Moodle coding style]] document explains this standard.


=== Blocks ===
==Security==
Blocks must always be enclosed in '''curly braces''' (even if there is only one line). Moodle uses this style:


<code php>
Security is about protecting the interests and data of all our users.  Moodle may not be banking software, but it is still protecting a lot of sensitive and important data such as private discussions and grades from outside eyes (or student hackers!) as well as protecting our users from spammers and other internet predators.
if ($quiz->attempts) {
    if ($numattempts > $quiz->attempts) {
        error($strtoomanyattempts, "view.php?id=$cm->id");
    }
}
</code>


It's also a script running on people's servers, so Moodle needs to be a responsible Internet citizen and not introduce vulnerabilities that could allow crackers to gain unlawful access to the server it runs on.


=== Strings ===
Any single script (in Moodle core or a third party module) can introduce a vulnerability to thousands of sites, so it's important that all developers strictly follow our [[Security|Moodle security guidelines]].
Strings should be defined using '''single quotes''' where possible, so that [http://php.net/types.string less memory is used].


<code php>
==HTML==
$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";
</code>


=== Comments ===
Comments should be added as much as is practical, to explain the code flow and the purpose of functions and variables.


* Every function (and class) should use the popular [http://www.phpdoc.org/ phpDoc format]. This allows code documentation to be generated automatically.
==Javascript==
* Inline comments should use the // style, laid out neatly so that it fits among the code and lines up with it.


<code php>
See the Moodle [[JavaScript guidelines|Javascript guidelines]]
/**
* 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.
</code>


=== Use space ===
==Internationalisation==
Space should be used liberally - don't be afraid to spread things out a little to gain some clarity. Generally, there should be one space between brackets and normal statements, but no space between brackets and variables or functions:


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


=== Copying objects ===
==Usability==
When making a COPY of an object, always use the PHP5 '''clone()''' function (otherwise you may end up with just a reference to the first object).  Moodle will make sure this works consistently on PHP4 too.


    BAD:  $b = $a;
==Database==
    GOOD:  $b = clone($a);


If the thing you want to copy is not an object, but may contain objects (e.g. an array of objects) then use '''fullclone()''' instead.
===Defining database structures===


==Database structures==
===Accessing the database===


To help you create tables that meet these guidelines, we recommend you use the built in [[XMLDB_defining_an_XML_structure#The_XMLDB_editor|database definition (XMLDB) editor]].
==Unit tests==


# Every table must have an auto-incrementing id field (INT10) as primary index. (see [[IdColumnReasons]])
Unit testing is not simply a technique but a philosophy of software development.   
# The main table containing instances of each module must have the same name as the module (eg widget) and contain the following minimum fields:
#* id - as described above
#* course - the id of the course that each instance belongs to
#* name - the full name of each instance of the module
# Other tables associated with a module that contain information about 'things' should be named widget_things (note the plural).
# Table and column names should avoid using [[Database reserved words|reserved words in any database]]. Please check them before creation. Table names may be up to 28 characters long, and Column names up to 30 characters.
# Column names should be always lowercase, simple and short, following the same rules as for variable names.
# Where possible, columns that contain a reference to the id field of another table (eg widget) should be called widgetid. (Note that this convention is newish and not followed in some older tables)
# Boolean fields should be implemented as small integer fields (eg INT4) containing 0 or 1, to allow for later expansion of values if necessary.
# Most tables should have a timemodified field (INT10) which is updated with a current timestamp obtained with the PHP time() function.
# Always define a default value for each field (and make it sensible)
# Each table name should start with the database prefix ($CFG->prefix). In a lot of cases, this is taken care of for you automatically. Also, under Postgres, the name of every index must start with the prefix too.
# In order to guarantee [[XMLDB problems#Table and column aliases - the AS keyword|cross-db compatibility]] follow these simple rules about the use of the '''AS''' keyword (only if you need table/colum aliases, of course):
#* '''Don't use''' the '''AS''' keyword for '''table aliases'''.
#* '''Do use''' the '''AS''' keyword for '''column aliases'''.
# '''Never''' create UNIQUE KEYs (constraints) at all. Instead use UNIQUE INDEXes. In the future, if we decide to add referential integrity to Moodle and we need UNIQUE KEYs they will be used, but not now. Please note that the XMLDB editor allows you to specify both XMLDB-only UNIQUE and FOREIGN constraints (and that's good, in order to have the XML well defined) but only underlying INDEXes will be generated.
# Those XMLDB-only UNIQUE KEYs (read previous point) only must be defined if such field/fields '''are going to be the target''' for some (XMLDB-only too) FOREIGN KEY. Else, create them as simple UNIQUE INDEXes.
# Tables associated '''with one block''' must follow this convention with their names: '''$CFG->prefix + "block_" + name_of_the_block + anything_else'''. For example, assuming that $CFG->prefix is 'mdl_', all the tables for the block "rss_client" must start by 'mdl_block_rss_client' (being possible to add more words at the end, i.e. 'mdl_block_rss_client_anothertable'...). This rule will be 100% enforced with Moodle 2.0, giving time to developers until then. See [http://tracker.moodle.org/browse/MDL-6786 Task 6786] for more info about this.
# '''Never''' make database changes in the STABLE branchesIf we did, then users upgrading from one stable version to the next would have duplicate changes occurring, which may cause serious errors.
# When refering to integer variable in SQL queries, do not surround the value in quotes. For example, get_records_select('question', "category=$catid") is right. get_records_select('question', "category='$catid'") is wrong. It hides bugs where $catid is undefined. ([http://moodle.org/mod/forum/discuss.php?d=80629 This thread explains].)


==Security issues (and handling form and URL data)==
The idea is to create automatable tests for each bit of functionality that you are developing (WHILE you are developing it).  This not only helps everyone test that the software works, but helps the development as well, because it forces you to work in a modular way with very clearly defined structures and goals.


# Do not rely on 'register_globals'. Every variable must be properly initialised in every code file. It must be obvious where the variable came from.
Moodle uses a library called simpletest (not very extensively yet though!) that makes writing unit tests fairly simple.
# Initialise all arrays and objects, even if empty. $a = array() or $obj = new stdClass();.
# Do not use the optional_variable() function (this function is now deprecated). Use the optional_param() function instead. Pick the correct PARAM_XXXX value for the data type you expect.
# Do not use the require_variable() function (this function is now deprecated). Use the required_param() function instead. Pick the correct PARAM_XXXX value for the data type you expect.
# Use data_submitted(), with care. Data must still be cleaned before use. Use confirm_sesskey() together with data_dubmitted() in order to prevent CSRF attacks.
# Do not use $_GET, $_POST or $_REQUEST. Use the appropriate required_param() or optional_param() appropriate to your need.
# Do not check for an action using something like if (isset($_GET['something'])). Use, e.g., $something = optional_param( 'something',-1,PARAM_INT ) and then perform proper test for it being in its expected range of values e.g., if ($something>=0) {....
# Wherever possible group all your required_param(), optional_param() and other variables initialisation at the beginning of each file to make them easy to find.
# Use 'sesskey' mechanism to protect form handling routines from attack. Basic example of use: when form is generated, include <input type="hidden" name="sesskey" value="<?php echo sesskey(); ?>" />. When you process the form check with if (!confirm_sesskey()) { print_error('confirmsesskeybad');}.
# All filenames must be 'cleaned' using the clean_filename() function, if this has not been done already by appropriate use of required_param() or optional_param()
# Any data read from the database must have [[Developer:Slashes|addslashes()]] applied to it before it can be written back. A whole object of data can be hit at once with addslashes_object(). For Moodle 2.0 the database layer has changed and you MUST NOT use addslashes() as this is now automated.
# addslashes_js() must be used for escaping of javascript strings
# Wherever possible, data to be stored in the database must come from POST data (from a form with method="POST") as opposed to GET data (ie, data from the URL line).
# Do not use data from $_SERVER if you can avoid it. This has portability issues.
# If it hasn't been done somewhere else, make sure all data written to the database has been through the clean_param() function using the appropriate PARAM_XXXX for the datatype.
# If you write custom SQL code, make very sure it is correct. In particular watch out for missing quotes around values. Possible SQL 'injection' exploit.
# Check all data (particularly that written to the database) in every file it is used. Do not expect or rely on it being done somewhere else.
# Blocks of code to be included should contain a definite PHP structure (e.g, a class declaration, function definition(s) etc.) - straight blocks of code promote uninitialised variable usage.
# If you need to use shell_exec() (or any other shell invoking function), make sure you clean parameters first with escapeshellcmd()/escapeshellarg (otherwise, we open up for shell injection attacks).


== Use of JavaScript within Moodle ==
Full information about this is here:  [[https://docs.moodle.org/en/Development:Unit_tests|Unit tests]]


See [[JavaScript guidelines]].


== See also ==
== See also ==

Revision as of 09:28, 30 April 2009

This page is the top-level page describing Moodle's coding guidelines. It's the place to start if you want to know how to write code for Moodle.

WARNING: Under construction RIGHT NOW!


Moodle architecture

Moodle tries to run on the widest possible range of platforms, for the widest possible number of people, while remaining easy to install, use, upgrade and integrate with other systems.

For more about this, see: Moodle_architecture.

Plugins

Moodle has a general philosophy of modularity. There are over 25 different types of plugins, however many of these plugin types work the same way.

For more about the structure of plugins, see Moodle plugins.

Coding style

Consistent coding style is important in any development project, and particularly so when many developers are involved. A standard style helps to ensure that the code is easier to read and understand, which helps overall quality.

Writing your code in this way will ensure your code is an important step to having your code accepted by the Moodle community.

Our Moodle coding style document explains this standard.

Security

Security is about protecting the interests and data of all our users. Moodle may not be banking software, but it is still protecting a lot of sensitive and important data such as private discussions and grades from outside eyes (or student hackers!) as well as protecting our users from spammers and other internet predators.

It's also a script running on people's servers, so Moodle needs to be a responsible Internet citizen and not introduce vulnerabilities that could allow crackers to gain unlawful access to the server it runs on.

Any single script (in Moodle core or a third party module) can introduce a vulnerability to thousands of sites, so it's important that all developers strictly follow our Moodle security guidelines.

HTML

Javascript

See the Moodle Javascript guidelines

Internationalisation

Accessibility

Usability

Database

Defining database structures

Accessing the database

Unit tests

Unit testing is not simply a technique but a philosophy of software development.

The idea is to create automatable tests for each bit of functionality that you are developing (WHILE you are developing it). This not only helps everyone test that the software works, but helps the development as well, because it forces you to work in a modular way with very clearly defined structures and goals.

Moodle uses a library called simpletest (not very extensively yet though!) that makes writing unit tests fairly simple.

Full information about this is here: [tests]


See also

zh:代码指南 pl:Kodowanie pt:manual_de_codigo