Coding Standards

Coding Standards

Due to the fact that the Elentra code base has been continually evolving, some of the existing source code does not necessarily adhere to the Elentra Platform Coding Standards defined below. If you encounter something that does not follow the coding standards, it is our hope that you (as a developer and contributor) will update and test the files accordingly.

Important Note If you do not like something about our coding standards, please don't be passively adoptive. We are certainly willing to listen and potentially adjust providing that:

  1. You are willing and able to clearly explain and defend your well thought out position.

  2. You are willing to do something to help implementing your ideas.

  3. You can convince the majority of community to agree with your position.

Thank you for helping to make the Elentra Platform development experience a good one.

PHP Standards

Our direction is to adopt the wildly accepted PSR standards by the PHP Framework Interop Group:

Source Code Documentation

All source code documentation blocks ("docblocks") must be compatible with the phpDocumentor format. Describing the phpDocumentor format is beyond the scope of this document, but for more information visit http://phpdoc.org.

All source code files written for Elentra or that operate within the platform must contain a "file-level" docblock at the top of each file, as well as a "class-level" docblock immediately above each class.

Below are examples of such docblocks.

Please Note The sharp, #, character should never be used to start source code comments, instead use: // or /* */ format.

Files

Every file that contains Elentra PHP code must have a "file-level" docblock at the top of the file that contains these phpDocumentor tags at a minimum:

/**
* Elentra ME [https://elentra.org]
*
* Copyright 2020 Queen's University or its assignee ("Queen's"). All Rights Reserved.
*
* This work is subject to Community Licenses ("CL(s)") between Queen's and its various licensee's,
* respectively, and may only be viewed, accessed, used, reproduced, compiled, modified, copied or
* exploited (together "Used") in accordance with a CL. Only Queen's or its licensees and their
* respective Authorized Developers may Use this work in accordance with a CL. If you are not an
* Authorized Developer, please contact Queen's University (at cla@elentra.org) or its applicable
* licensee to review the rights and obligations under the applicable CL and become an Authorized
* Developer before Using this work.
*
* General description of this file.
*
* @author Organization: Your Organization Here
* @author Developer: Developer Name Here <developer@emailaddress.here>
*
*/

Classes

Every class must have a "class-level" docblock that contains these phpDocumentor tags at a minimum:

/**
* Class Name or Title
*
* General description for this class.
*
* @author Organization: Your Organization Here
* @author Developer: Developer Name Here <developer@emailaddress.here>
*/

Functions

Every function, including object methods, must have a docblock that contains at a minimum:

  • A description of the function

  • All of the arguments

  • All of the possible return values

  • If a function/method may throw an exception, use "@throws"

    /**
    * This method does something interesting.
    *
    * @param Place $where Where something interesting takes place
    * @param int $repeat How many times something interesting should happen
    * @return bool
    */
    public function doSomethingInteresting(Place $where, $repeat = 1) {
    return true;
    }
    /**
    * This function (public static method) returns whatever it is passed.
    *
    * @param bool $state
    * @return bool
    */
    public static function another_interesting_thing($state = true) {
    return $state;
    }

Code Formatting and General Rules

General Formatting

  • All indenting is set to 4 spaces (no tabs).

  • Keep indenting at the level of the HTML indent when mixing PHP and HTML, and vice versa.

    <div>
    <?php
    if ($foo) {
    ...
    }
    ?>
    </div>
  • Do not increase or decrease indent for <?php or ?> tags.

  • Do not use PHP short tags (<? or <?=), instead use the full opening tag (<?php and <?php echo).

Variables and Constants

  • Constants should always be declared in upper case

    define("CLERKSHIP_TOP_CATEGORY_ID", 49);
  • Variables which are used between more than one file (what we call minor global variables) are also in all upper case

    $CLERKSHIP_REQUIRED_WEEKS = 14;
  • Variables which are used within only one file should be in all lower case

    $title_suffix = " All Faculty";
  • Variables and Constants with multi-word names should have each word separated with an underscore

    $clinical_presentations_list = false;
  • Always validate $_GET and $_POST variables and place them in a $PROCESSED array for creating or editing records in databases or in regular variables for program logic

    /**
    * Required field "course_name" / Course Name.
    */
    if (isset($_POST["course_name"]) && ($course_name = clean_input($_POST["course_name"], ["notags", "trim"]))) {
    $PROCESSED["course_name"] = $course_name;
    } else {
    add_error("The <strong>" . $module_singular_name . "Name</strong> field is required.");
    }

If, Foreach and Switch statements

  • For if, foreach, and switch statements, include a space after the initial statement and after the closing parenthesis.

  • For if statements with an else branch, include a space after the first closing brace bracket and after the else statement.

  • For if statements with an elseif branch, include a space after the first closing brace bracket and after the elseif statement, and after the parenthesis.

  • For if, foreach, and switch statements, include brace brackets, whether the code inside the statement is one line or more.

  • Use && and || in logic instead of AND and OR

  • Layout foreach and if statements on at least 3 lines:

    • The statement, parameters, and open brace-bracket

    • A new line with code to be executed

    • One more line with a closing brace bracket.

  • Layout switch statements with at least 5 lines:

    • same as above plus:

    • at least one case "parameter" : line before the code to be executed.

    • a break; line after the code to be executed.

  • For case and default lines, include a space before the colon.

  • End all case and default sections in switch statements with a break; line which is indented one tab less than the code to be executed.

  • Indent all code within brace brackets by one additional tab (four spaces).

  • Indent all code after a case or default line in a switch statement by one additional tab (four spaces).

    if ((($variable > 20) && ($variable < 50)) || $boolean) {
    echo "this code executed.";
    } elseif (($variable > 15) && ($variable < 60)) {
    echo "that code almost executed.";
    } else {
    echo "that code didn't execute.";
    }
    foreach ($names as $name) {
    echo $name;
    }
    switch ($status) {
    case "on" :
    turn_light_on();
    break;
    case "off" :
    turn_light_off();
    break;
    default :
    continue;
    break;
    }

Functions and Methods

  • Create new global functions as public static methods in core/library/Entrada/Utilities.php.

    • Historical global functions are declared in core/includes/functions.inc.php.

  • Separate multi-word function names with underscores.

  • Define functions primarily used only in one module as methods of that module's class (e.g., Entrada_Events::filter_events() in core/library/Entrada/Events.php).

  • Group like functions / methods together in the same file where possible.

  • Include a space after the closing parenthesis and before the opening brace bracket in function declarations.

    /**
    * Determines whether or not a PHP session is available.
    *
    * @return bool
    */
    public static function is_session_started() {
    if ( php_sapi_name() !== "cli" ) {
    if ( version_compare(phpversion(), "5.4.0", ">=") ) {
    return session_status() === PHP_SESSION_ACTIVE ? true : false;
    } else {
    return session_id() === "" ? false : true;
    }
    }
    return false;
    }

SQL Standards

  • If the query you are writing is over 120 characters long you should add line breaks and align the query so JOIN, WHERE, ON, AND, ORDER BY and GROUP BY keywords start a new line and are indented to line up with the first statement of the query.

  • All of the query except the field, table and database names should be in uppercase.

  • To prevent SQL injection vulnerabilities, use prepared statements whenever possible, otherwise use ADOdb's qstr() method ".$db->qstr($variable)." to add variables into queries.

  • Avoid writing your own INSERT and UPDATE queries. Instead, use ADOdb's AutoExecute() method.

  • Include SQL queries within models only, not controllers or views.

  • Include back-ticks around field names in queries to prevent possible naming collisions.

Using prepared statements

$query = "SELECT a.*, b.`group`, b.`role`
FROM `".AUTH_DATABASE."`.`user_data` AS a
LEFT JOIN `".AUTH_DATABASE."`.`user_access` AS b
ON b.`user_id` = a.`id`
WHERE b.`group` = ?
AND b.`role` = ?
ORDER BY a.`lastname`, a.`firstname` ASC";
$results = $db->GetAll($query, [$group, $role]);

Using ADOdb qstr()

$query = "SELECT a.*, b.`group`, b.`role`
FROM `" . AUTH_DATABASE . "`.`user_data` AS a
LEFT JOIN `" . AUTH_DATABASE . "`.`user_access` AS b
ON b.`user_id` = a.`id`
WHERE b.`group` = " . $db->qstr($group) . "
AND b.`role` = `" . $db->qstr($role) . "
ORDER BY a.`lastname`, a.`firstname` ASC";