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
(Add link to manual testing instruction guidelines.)
(142 intermediate revisions by 31 users not shown)
Line 1: Line 1:
Any collaborative project needs consistency and stability to stay strong.
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.


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==
==Moodle architecture==


# All code files should use the .php extension.
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.
# 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).
For more about this, see [[Moodle architecture]].
# 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.
==Plugins==
# Each file should include the main config.php file.
 
# Each file should check that the user is authenticated correctly, using require_login() and isadmin(), isteacher(), iscreator() or isstudent().
Moodle has a general philosophy of modularity. There are nearly 30 different standard types of plugins and even more sub-plugin types, however all of these plugin types work the same way. Blocks and activities are the only small exceptions.
# All access to databases should use the functions in ''lib/datalib.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 or use global variables except for the standard $CFG, $SESSION, $THEME and $USER.
See [[Plugins|Moodle plugins]] and [[Subplugins|Moodle sub-plugins]] for more information.
# 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" files with concise English lowercase names and retrieve them from your code using get_string() or print_string().
# All help files should be translatable - create new texts in the "en/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.
# IMPORTANT: All texts within Moodle, especially those that have come from users, should be printed using the format_text() function. This ensures that text is filtered and cleaned correctly.
# User actions should be logged using the [[add_to_log|add_to_log()]] function. These logs are used for [[Settings#Show_activity_reports|activity reports]] and [[Logs]].


==Coding style==
==Coding style==


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.
Consistent [[Coding style|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 is an important step to having your code accepted by the Moodle community.
 
Our [[Coding_style|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 [[Security|Moodle security guidelines]].
 
==XHTML and CSS==
 
It's important that Moodle produces strict, well-formed [http://en.wikipedia.org/wiki/HTML5 HTML 5] code (preferably backwards compatible with [[XHTML|XHTML 1.1]] if possible), compliant with all common accessibility guidelines (such as [http://www.w3.org/TR/WCAG20/ W3C WAG 2.0], [http://www.w3.org/TR/wai-aria-practices/ ARIA]).
 
CSS should be used for layout. Moodle comes with several themes installed. Beginning with version 2.7, only the 'Clean' theme comes in the base Moodle code. The 'standard' theme, which should be a plain theme suitable to act as a building block for other themes. That should contain the minimal styling to make Moodle look OK and be functional. Then Moodle comes with several other default themes that look good and demonstrate various techniques for building themes.
 
This helps consistency across browsers in a nicely-degrading way (especially those using non-visual or mobile browsers), as well as improving life for theme designers.
 
==JavaScript==
 
In general, everything in Moodle should work with JavaScript turned off in your browser. This is important for accessibility, and in line with the principles of unobtrusive JavaScript and progressive enhancement.
 
Features that are not available without JavaScript must be compliant with all accessibility standards.
 
See the [[JavaScript guidelines|Moodle JavaScript guidelines]] for more information.
 
==Internationalisation==
 
Moodle works in over 84 languages because we pay great attention to keeping the language strings and locale information separate from the code, in language packs.
 
The default language for all code, comments and documentation, however, is English (AU).
 
Full details:  [[String API]]
 
==Accessibility==
 
Moodle should work well for the widest possible range of people.
 
See [[Accessibility|Moodle Accessibility]] for more information.
 
==Usability==
 
See [[Interface_guidelines| Interface Guidelines]] (under construction)


1. Indenting should be consistently 4 spaces. Don't use tabs AT ALL.
==Performance==


2. 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.
The load any Moodle site can cope with will, of course, depend on the server and network hardware that it is running on. However there are some features (intended especially for developers) that are discouraged on production sites for performance reasons.


      GOOD: $quiz
The most important property is scalability, so a small increase in the number of users, courses, activities in a course, and so on, only causes a correspondingly small increase in server load.
      GOOD: $errorstring
      GOOD: $assignments (for an array of objects)
      GOOD: $i (but only in little loops)


      BAD: $Quiz
For more information and advice, see [[Performance and scalability|Performance and scalability]].
      BAD: $aReallyLongVariableNameWithoutAGoodReason
      BAD: $error_string


3. Constants should always be in upper case, and always start with the name of the module. They should have words separated by underscores.
==Database==


      define("FORUM_MODE_FLATOLDEST", 1);
Moodle has a powerful database abstraction layer that we wrote ourselves, called [[XMLDB_Documentation|XMLDB]]. This lets the same Moodle code work on MySQL/MariaDB, PostgreSQL, MS SQL Server and Oracle. There are know issues when using Oracle, it is not fully supported and is not recommended for production sites.
4. 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).


      function forum_set_display_mode($mode=0) {
We have tools and API for [[DDL functions|defining and modifying tables]] as well as [[Data manipulation API|methods for getting data in and out]] of the database.
          global $USER, $CFG;


          if ($mode) {
Overview: [[Database|Moodle Database]] guidelines
              $USER->mode = $mode;
          } else if (empty($USER->mode)) {
              $USER->mode = $CFG->forum_displaymode;
          }
      }


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


      if ($quiz->attempts) {
Moodle allows inter-module communication via '''events'''.  Modules can '''trigger''' specific events and other modules can choose to '''handle/observe''' those events.
          if ($numattempts > $quiz->attempts) {
              error($strtoomanyattempts, "view.php?id=$cm->id");
          }
      }


6. Strings should be defined using single quotes where possible, for increased speed.
See:
* [[Events_API|Events API]] - Moodle 2.0 - 2.5
* [[Event_2|New Events API]] - Moodle 2.6 and later


      $var = 'some text without any variables';
==Manual testing==
      $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. Comments should be added as much as is practical, to explain the code flow and the purpose of functions and variables.
All issues integrated into the core codebase are tested both during Integration, and subsequently by our testing team. While much of this testing is automated, there are many parts which cannot be automated, and manual testing is required.


* Every function (and class) should use the popular [http://www.phpdoc.org/ phpDoc format]. This allows code documentation to be generated automatically.
Moodle has guidelines on [[Testing_instructions_guide|how to write clear testing instructions]] which we recommend you read and follow.
* Inline comments should use the // style, laid out neatly so that it fits among the code and lines up with it.


      /**
==Unit testing==
      * 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. 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:
[http://en.wikipedia.org/wiki/Unit_testing Unit testing] is not simply a technique but a philosophy of software development.


      foreach ($objects as $key => $thing) {
The idea is to create automatable tests for each bit of functionality that you are developing (at the same time you are developing it).  This not only helps everyone later test that the software works, but helps the development itself, because it forces you to work in a modular way with very clearly defined structures and goals.
          process($thing);
      }


      if ($x == $y) {
Moodle uses a framework called [https://github.com/sebastianbergmann/phpunit/ PHPUnit] that makes writing unit tests fairly simple.
          $a = $b;
      } else if ($x == $z) {
          $a = $c;
      } else {
          $a = $d;
      }


==Database structures==
See [[PHPUnit]] for more information.


# Every table must have an auto-incrementing id field (INT10) as primary index. (see [[IdColumnReasons]])
==Acceptance testing==
# 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).
# Column names should be 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)


==Security issues (and handling form and URL data)==
PHPUnit covers mostly the internal implementation of functions and classes, the user interaction testing can be automated using the [http://behat.org Behat framework].


# 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
See [[Acceptance testing]] for more information.
# 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.
# 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()) {error('Bad Session Key');}.
# 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 addslashes() applied to it before it can be written back. A whole object of data can be hit at once with addslashes_object().
# 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.


==Third Party Libraries==
Moodle has a standard way to include third party libraries in your code. See https://docs.moodle.org/dev/Third_Party_Libraries


== Other standards ==


[[es:Manual de Estilo de Código]]
Please note that Moodle coding style and design is pretty unique, it is not compatible with [http://pear.php.net/manual/en/standards.php PEAR coding standards] or any other common PHP standards.

Revision as of 01:23, 1 August 2018

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.


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 nearly 30 different standard types of plugins and even more sub-plugin types, however all of these plugin types work the same way. Blocks and activities are the only small exceptions.

See Moodle plugins and Moodle sub-plugins for more information.

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 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.

XHTML and CSS

It's important that Moodle produces strict, well-formed HTML 5 code (preferably backwards compatible with XHTML 1.1 if possible), compliant with all common accessibility guidelines (such as W3C WAG 2.0, ARIA).

CSS should be used for layout. Moodle comes with several themes installed. Beginning with version 2.7, only the 'Clean' theme comes in the base Moodle code. The 'standard' theme, which should be a plain theme suitable to act as a building block for other themes. That should contain the minimal styling to make Moodle look OK and be functional. Then Moodle comes with several other default themes that look good and demonstrate various techniques for building themes.

This helps consistency across browsers in a nicely-degrading way (especially those using non-visual or mobile browsers), as well as improving life for theme designers.

JavaScript

In general, everything in Moodle should work with JavaScript turned off in your browser. This is important for accessibility, and in line with the principles of unobtrusive JavaScript and progressive enhancement.

Features that are not available without JavaScript must be compliant with all accessibility standards.

See the Moodle JavaScript guidelines for more information.

Internationalisation

Moodle works in over 84 languages because we pay great attention to keeping the language strings and locale information separate from the code, in language packs.

The default language for all code, comments and documentation, however, is English (AU).

Full details: String API

Accessibility

Moodle should work well for the widest possible range of people.

See Moodle Accessibility for more information.

Usability

See Interface Guidelines (under construction)

Performance

The load any Moodle site can cope with will, of course, depend on the server and network hardware that it is running on. However there are some features (intended especially for developers) that are discouraged on production sites for performance reasons.

The most important property is scalability, so a small increase in the number of users, courses, activities in a course, and so on, only causes a correspondingly small increase in server load.

For more information and advice, see Performance and scalability.

Database

Moodle has a powerful database abstraction layer that we wrote ourselves, called XMLDB. This lets the same Moodle code work on MySQL/MariaDB, PostgreSQL, MS SQL Server and Oracle. There are know issues when using Oracle, it is not fully supported and is not recommended for production sites.

We have tools and API for defining and modifying tables as well as methods for getting data in and out of the database.

Overview: Moodle Database guidelines

Events

Moodle allows inter-module communication via events. Modules can trigger specific events and other modules can choose to handle/observe those events.

See:

Manual testing

All issues integrated into the core codebase are tested both during Integration, and subsequently by our testing team. While much of this testing is automated, there are many parts which cannot be automated, and manual testing is required.

Moodle has guidelines on how to write clear testing instructions which we recommend you read and follow.

Unit testing

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 (at the same time you are developing it). This not only helps everyone later test that the software works, but helps the development itself, because it forces you to work in a modular way with very clearly defined structures and goals.

Moodle uses a framework called PHPUnit that makes writing unit tests fairly simple.

See PHPUnit for more information.

Acceptance testing

PHPUnit covers mostly the internal implementation of functions and classes, the user interaction testing can be automated using the Behat framework.

See Acceptance testing for more information.

Third Party Libraries

Moodle has a standard way to include third party libraries in your code. See https://docs.moodle.org/dev/Third_Party_Libraries

Other standards

Please note that Moodle coding style and design is pretty unique, it is not compatible with PEAR coding standards or any other common PHP standards.