Gibbon Documentation
v17.0.00

The following documents should be useful to anyone hoping to develop with Gibbon. Questions can be emailed to support@gibbonedu.org.



Getting Setup

  1. Fork the GibbonEdu/core repository on GitHub and clone a copy on your local machine.
  2. Write some code and push your changes to your repo using the command line or your favourite Git GUI.
  3. Create a new pull request and fill in the template provided to tell us about your change.
  4. Be sure you’re submitting your pull request to the development branch (and not master).
  5. Submissions should have a changelog entry noting what was added, changed or fixed.

If you’re unsure where to begin with GitHub feel free to reach out on the Support forum or check out these great guides: makeapullrequest.com and opensource.guide

Release Schedule

We aim to release a new version every 6 months, usually every January and June. There is a string freeze one month before each release, where all interface strings fixed and shared with translators via POEditor.

Each version, stable or development, is denoted with a major semantic version (e.g., v16.0.0). Updates to a stable version are only released in the case of a security concern, and are tagged as a patch version (e.g., v16.0.1).

Branching Strategy

Gibbon uses a simple branching strategy. The current stable version is released and tagged on the Master branch. Development branches are setup after each release and increment to the next major version (e.g., v16.0.00 to v17.0.00). The dev branch does not currently track semantic versioning, and a built-in updater handles database changes for cutting edge code.

Development Philosophy

Our general philosophy is to make incremental, testable changes to an ongoing development branch. To keep things running smoothly—especially as we refactor the codebase—it helps to keep each new change small and self-contained.

There are a few schools running cutting edge code in production which helps to continuously test new changes before release. With this in mind, we aim to keep the development branch as stable as possible.

Pull Request & Code Review

Each pull request should contain only one new feature or improvement. Ideally, split any larger change sets into multiple PRs if they involve more than a handful of files. Long running branches with breaking changes are unlikely to be merged into the core.

Pull requests can be submitted to the current development branch and not to Master (which is our stable release). Please take some time to describe your changes, there’s a PR template on GitHub to get you started.

Our CI robots will automatically built & test any pull requests. Our code coverage isn’t extensive yet, so a green checkmark on GitHub isn’t necessarily a green light to merge: there’ll always be a human review too.

Each pull request is reviewed by at least one Gibbon Maintainer. Complex changes may require more than one set of eyes and some hearty discussion. Focus on code readability and bite-size commits and your PRs will be in good shape to merge.


Shown below are some upcoming key dates in the Gibbon Development Road Map. To request new features, please use the Feature Requests category in our support forums.

A record of all Gibbon releases since v7.0.00 can be found on the GitHub Repository.


General

  1. Avoid PHP Shortcodes - as of v8.0.00 Gibbon is moving away from <? in favour of <?php.

Security

  1. When using isActionAccessible(), always hard code the address, rather than relying on session, get, post or server variables.
  2. For database connections, use the PDO class (instead of the more common mysql one), and parameterise any user-generated inputs. With PDO’s parameters, you do not need to escape your input.

Code Style

Borrowed from Symfony: http://symfony.com/doc/current/contributing/code/standards.html

Gibbon follows the standards defined in the PSR-0, PSR-1, PSR-2 and PSR-4 documents.

Since a picture - or some code - is worth a thousand words, here’s a short example containing most features described below:

<?php
/*
Gibbon, Flexible & Open School System
Copyright (C) 2010, Ross Parker

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

namespace Acme;

/**
 * Coding standards demonstration.
 */
class FooBar
{
    const SOME_CONST = 42;

    /**
     * @var string
     */
    private $fooBar;

    /**
     * @param string $dummy Some argument description
     */
    public function __construct($dummy)
    {
        $this->fooBar = $this->transformText($dummy);
    }

    /**
     * @return string
     *
     * @deprecated
     */
    public function someDeprecatedMethod()
    {
        @trigger_error(sprintf('The %s() method is deprecated since version 2.8 and will be removed in 3.0. Use Acme\Baz::someMethod() instead.', __METHOD__), E_USER_DEPRECATED);

        return Baz::someMethod();
    }

    /**
     * Transforms the input given as first argument.
     *
     * @param bool|string $dummy   Some argument description
     * @param array       $options An options collection to be used within the transformation
     *
     * @return string|null The transformed input
     *
     * @throws \RuntimeException When an invalid option is provided
     */
    private function transformText($dummy, array $options = array())
    {
        $defaultOptions = array(
            'some_default' => 'values',
            'another_default' => 'more values',
        );

        foreach ($options as $option) {
            if (!in_array($option, $defaultOptions)) {
                throw new \RuntimeException(sprintf('Unrecognized option "%s"', $option));
            }
        }

        $mergedOptions = array_merge(
            $defaultOptions,
            $options
        );

        if (true === $dummy) {
            return null;
        }

        if ('string' === $dummy) {
            if ('values' === $mergedOptions['some_default']) {
                return substr($dummy, 0, 5);
            }

            return ucwords($dummy);
        }
    }

    /**
     * Performs some basic check for a given value.
     *
     * @param mixed $value     Some value to check against
     * @param bool  $theSwitch Some switch to control the method's flow
     *
     * @return bool|void The resultant check if $theSwitch isn't false, void otherwise
     */
    private function reverseBoolean($value = null, $theSwitch = false)
    {
        if (!$theSwitch) {
            return;
        }

        return !$value;
    }
}

Structure

  • Add a single space after each comma delimiter;
  • Add a single space around binary operators (==, &&, …), with the exception of the concatenation (.) operator;
  • Place unary operators (!, –, …) adjacent to the affected variable;
  • Always use identical comparison unless you need type juggling;
  • Use Yoda conditions when checking a variable against an expression to avoid an accidental assignment inside the condition statement (this applies to ==, !=, ===, and !==);
  • Add a comma after each array item in a multi-line array, even after the last one;
  • Add a blank line before return statements, unless the return is alone inside a statement-group (like an if statement);
  • Use return null; when a function explicitly returns null values and use return; when the function returns void values;
  • Use braces to indicate control structure body regardless of the number of statements it contains;
  • Define one class per file - this does not apply to private helper classes that are not intended to be instantiated from the outside and thus are not concerned by the PSR-0 and PSR-4 autoload standards;
  • Declare the class inheritance and all the implemented interfaces on the same line as the class name;
  • Declare class properties before methods;
  • Declare public methods first, then protected ones and finally private ones. The exceptions to this rule are the class constructor and the setUp and tearDown methods of PHPUnit tests, which must always be the first methods to increase readability;
  • Declare all the arguments on the same line as the method/function name, no matter how many arguments there are;
  • Use parentheses when instantiating classes regardless of the number of arguments the constructor has;
  • Exception and error message strings must be concatenated using sprintf;
  • Calls to trigger_error with type E_USER_DEPRECATED must be switched to opt-in via @ operator. Read more at Deprecations;
  • Do not use else, elseif, break after if and case conditions which return or throw something;
  • Do not use spaces around [ offset accessor and before ] offset accessor.

Naming Conventions

  • Use camelCase, not underscores, for variable, function and method names, arguments;
  • Use underscores for option names and parameter names;
  • Use namespaces for all classes;
  • Prefix abstract classes with Abstract;
  • Suffix interfaces with Interface;
  • Suffix traits with Trait;
  • Suffix exceptions with Exception;
  • Use alphanumeric characters and underscores for file names;
  • For type-hinting in PHPDocs and casting, use bool (instead of boolean or Boolean), int (instead of integer), float (instead of double or real);
  • Don’t forget to look at the more verbose Conventions document for more subjective naming considerations.

Service Naming Conventions

  • A service name contains groups, separated by dots;
  • The DI alias of the bundle is the first group (e.g. fos_user);
  • Use lowercase letters for service and parameter names;
  • A group name uses the underscore notation.

Documentation

  • Add PHPDoc blocks for all classes, methods, and functions;
  • Group annotations together so that annotations of the same type immediately follow each other, and annotations of a different type are separated by a single blank line;
  • Omit the @return tag if the method does not return anything;
  • The @package and @subpackage annotations are not used.

License

  • Gibbon is released under the GNU General Public License, and the license block has to be present at the top of every PHP file, before the namespace.

If you are interested in developing a module for Gibbon, use the instructions below. Contact support@gibbonedu.org if you are stuck.

Module Basics

Modules are the easiest way to extend Gibbon without having to hack the core, and risk losing your changes on upgrade. Each module provides one or more actions, and each action can be assigned to user roles through a system of permissions. Modules can be installed, updated and uninstalled.

Starter Module

Download the starter module and use it to begin coding up a module. Remove or replace the GNU GPL statement depending on your needs. The starter module consists of:

  • CHANGEDB.php - stores database changes for each version of the module, used in upgrades.
  • CHANGELOG.txt - list of changes per version
  • css/module.css - CSS file loaded up by the core for the module, allowing for per-module styling
  • img - a space to store any images for the module
  • index.php - a sample landing page. Replace isModuleAvailable() with isActionAvailable() if you want to test for access to a specific action rather than the whole system.
  • js/module.js - JavaScript file loaded up by the core for the module, allowing for per-module scripting
  • manifest.php - used to install the software, creates all actions, permissions, tables, settings, etc
  • moduleFunctions.php - a place for any module-specific PHP functions
  • version.php - the version number for the code (as opposed to the database version number, the difference between is used in the upgrade progress).

Module Translation

As of Gibbon v13 (released on January 20th 2016), additional modules are translatable. v4.5.00 of the Free Learning module is available as a model to demonstrate how module translation works (it is not yet translated, but can be). To prepare a module for translation:

  • Add a/i18n folder into the module root, and include sub folders for each language, as follows:
    • /i18n
      • es_ES
        • LC_MESSAGES
  • The LC_MESSAGES subfolder for each language should contain a PO and an MO file (using the GNU GetText system), each named with the module name (e.g. Free Learning.po and Free Learning.mo)
  • The manifest.php file should have a Translatables section, with one entry for each string from the database that is not in module’s (such as action descriptions), marking them for translation:
    • e.g. __($guid, 'Allows a user to browse all active units.');
  • For any translatable text in the module’s code, wrap it for translation as:
    • e.g. __($guid, $row['nameDisplay'], 'Free Learning'); where the third argument is the module name and sets the domain for translation.
    • This process is not yet 100% complete on the Free Learning module.
  • In order to generate your PO file, use a variant of this xgettextGenerationCommands.sh shell script
    • This script could be improved by filtering on the domain in __(), so as to ignore any strings that already exist in gibbon.PO, and so need not be retranslated. Any takers?

The PO file can now be translated, and the resulting MO file produced. Installing and using such a module should lead to the relevant strings being translated.

Module Hooks

The Gibbon Core provides three hooks, which allow additional modules to insert data into the interface of the Core modules. These hooks are for Public Home Page, Student Profile and Unit. To use one of the hooks, your module’s manifest file must write an entry to the core database table gibbonHook, specifying:

  1. name - The name of the hook will be displayed in the interface: for example, a Unit hook called “IB MYP” will result in such units being labelled as “IB MYP Unit” through the system.
  2. type- The system currently provides the following hook types
    1. Parent Dashboard
    2. Student Dashboard
    3. Staff Dashboard
    4. Public Homepage
    5. Student Profile
  3. options- This field consists of a serialized array of options for the hook. The exact options depend on the hook, as described below:
    1. Parent/Student/Staff Dashboard
      1. sourceModuleName - the name of the source module that data is being drawn from (e.g. IB Diploma)
      2. sourceModuleAction - the name of the action in the source module that the user needs to have access to in order to see this data
      3. sourceModuleInclude - the php file to include, which spits out the data into the Parental Dashboard
    2. Public Home Page
      1. toggleSettingName - the name of the gibbonSetting setting which allows this home page element to be turned on or off
      2. toggleSettingScope - the scope of the gibbonSetting setting which allows this home page element to be turned on or off
      3. toggleSettingValue - the “on” value of the gibbonSetting setting which allows this home page element to be turned on or off
      4. title - the title of the section to be displayed on the public home page
      5. text - the text of the section to be displayed on the public home page
    3. Student Profile
      1. sourceModuleName - the name of the source module that data is being drawn from (e.g. IB Diploma)
      2. sourceModuleAction - the name of the action in the source module that the user needs to have access to in order to see this data
      3. sourceModuleInclude - the php file to include, which spits out the data into the Student Profile page
  4. gibbonModuleID - This is needed to remove hooks when a module is uninstalled.
    1. Because the module ID is generated on install, you cannot hard code it into your module. You can use the following sql as a subquery when you create your hook insertion query: SELECT gibbonModuleID FROM gibbonModule WHERE name='$name'

As an example, if you want to use the Units hook, you could use the following code in your manifest, setting your own array values according to your database table design:

$array['unitTable'] = 'test';
$array['unitIDField'] = 'gibbonUnitID';
$array['unitCourseIDField'] = 'gibbonCourseID';
$array['unitNameField'] = 'name';
$array['unitDescriptionField'] = 'description';
$array['classLinkTable'] = 'testClass';
$array['classLinkJoinField'] = 'gibbonUnitID';
$array['classLinkIDField'] = 'gibbonCourseClassID';
$array['classLinkStartDateField'] = 'date';
print_r($array);


As of v18 Gibbon uses Webpack configured with Tailwind CSS via the Laravel Mix tool. More info about Tailwind in Gibbon here.

For the most part developers won’t need to re-build the css files too often, as the utility classes in Tailwind provide lots of functionality out of the box. However during refactoring while we’re creating some initial components, developers can use the build process to update css and js files for Gibbon core.

Using the build tools

If you don’t have npm, be sure to install it first. On Mac OS, if you have Homebrew you can install npm with brew install node.

In the command line, browse to the resources/build directory from your Gibbon install location, then run npm install to setup the build tools.

Once this is done, you can run npm run build to build the files, or npm run watch to automatically build files anytime they’re changed.


Gibbon tracks database migrations through the CHANGEDB.php file.

The SQL lines in the CHANGEDB.php file are run automatically by the Update process in System Admin > Update. For standard installs, these changes are run once per version. For cutting edge installs, the updater tracks which lines have been already run, and only runs new lines. Internally this is saved in the gibbonSetting table under cuttingEdgeCodeLine;

Database migrations are one-way only. Always be sure to backup your database before running updates.

Making Database Changes

Each version’s changes are held in a separate string in file, denoted by the version number. Each SQL statement is a separate line in the string, and must end with ;end

If you’re submitting database changes in a PR, please be sure to add them to the bottom of CHANGEDB, inside the string for the current development version.

Database changes to fix something in a previous line need to be submitted as a new SQL statement at the bottom of the CHANGEDB. Once a change is committed to the core, it may have already been run by other developers, so we aim to avoid making edits to any previous lines.


Gibbon uses PHPUnit and Codeception for automated testing, introduced in v14.0.00. Both testing frameworks can be installed and configured to run in your localhost.

Note: Our refactoring efforts are ongoing, and the code coverage for automated tests is not all-encompassing. A passing test does not guarantee a working codebase: please always test manually too.

PHPUnit

PHPUnit tests can be run with the phpunit . command in the /tests folder

Codeception

Codeception tests can be run with the codecept run command in the /tests folder

Codeception involves integration testing and makes use of a database connection; it will not run unless explicitly enabled. To enable Codeception testing in Gibbon, add the following to your config.php file:

$testEnvironment = 'codeception';

Travis CI

Pull requests and commits to the development branch are automatically built & tested using Travis CI.


At this point, API is probably too strong a term, but the items below allow you to interact with the core system using built in functions. There are many other undocumented functions (all in /functions.php), which will someday hopefully make it into these documents.


As of Gibbon v10.0.00, there are two custom code loaders that will take a script of your own writing and load it into a specific spot on the system. The contents loaded are cached into a session variable, and so are not refreshed until the following login (or until you force them). To use these code loaders, create files as shown below:

  • index_custom.php - this content will be loaded into the top of the main panel on the logged in home page.
  • index_customSidebar.php - this content will be loaded into the top of the sidebar on the logged in home page.

The aim of these custom code loaders is to allow flexibility to alter the way a system works, in such a way that is not destroyed on a system upgrade.


As of v10.0.00, Gibbon has a new system for system-wide logs. This will allow you to create or replace a log system to keep track of certain events or create reports or statistics using the logs. Any module, or indeed the core itself, can set or get logs using the following system-wide function call:

setLog($connection2, $gibbonSchoolYearID, $gibbonModuleID, $gibbonPersonID, $title, $array);
  • $gibbonSchoolYearID - The current school year ID.
  • $gibbonModuleID - Your module’s ID.
  • $gibbonPersonID - The user ID of the person doing the action that will be logged.
  • $title - The title of the action.
  • $array (Optional) - Any other information that needs to be stored with the log.

This function will return the ID of the log.

getLog($connection2, $gibbonSchoolYearID, $gibbonModuleID, $gibbonPersonID, $title, $startDate, $endDate);
  • $gibbonSchoolYearID - The ID of the year that the log was submitted in.
  • $gibbonModuleID (Optional) - The ID of the module that submitted the log.
  • $gibbonPersonID (Optional) - The ID of the person who caused the log to be submitted.
  • $title (Optional) - The title of the log.
  • $startDate (Optional) - The start of a date range to search in (if no end date is set it will search all until today).
  • $endDate (Optional) - The end of a date range to search in (if no start date is set it will search all until the first log).

This function will return a PDO result of the query.

getLogByID($connection2, $gibbonLogID);
  • $gibbonLogID - The ID of the log you are looking for.

This function will return a PDO result of the query.


As of v8.2.00, Gibbon has a new system for system-wide notifications. This replaces the old-fashioned (and very limited) approach of hard coding notifications into the sidebar. Any module, or indeed the core itself, can set a notification using the following system-wide function call:

setNotification($connection2, $guid, $gibbonPersonID, $text, $moduleName, $actionLink);
  • $gibbonPersonID - the user to be targetted by the notification.
  • $text - the notification text to be shown to the user. If the same module sets multiple notifications with the same text to the same person, they will not be duplicated, but rather will have a counter incremented. This aims to prevent notification flooding.
  • $moduleName - the name of the module setting the notification, or NULL or empty string for the system itself.
  • $actionLink - when the user clicks on Action & Delete in the Notifications page, this is where they will be taken. e.g. /index.php?q=/modules/Planner/planner_view_full.php&gibbonPlannerEntryID=$gibbonPlannerEntryID

Looking to contribute to Gibbon? Awesome, you’re in the right place. Gibbon is a work of volunteer labour, built with love and passion by people just like you.

You can contribute your time and expertise many ways. For example, you might:

A huge thank you 💜 to our growing team of volunteer developers and translators for their ongoing work to make Gibbon better for all of us.

How to report a bug

Before submitting a bug, please do the following:

  1. Make sure you’re on the latest version, your problem may have been solved already!
  2. Perform basic troubleshooting steps and note the steps required to reproduce the bug.
  3. Check the bug/issue tracker and planning board to make sure it’s not a known issue.
Submit the bug by creating an issue and follow the template provided for what to put in your bug report.

:exclamation: If you find a security vulnerability, do NOT open an issue. Please email support@gibbonedu.org instead.

How to suggest a feature

To request new features, please use the Feature Requests category in our support forums. You can find more info about planned features and upcoming releases on the Gibbon Development Road Map.

How to help translate

Thanks to some amazing volunteers, Gibbon is available in several different languages. If you would like to help translate Gibbon, please email support@gibbonedu.org. Your help would be most appreciated!

How to submit a pull request

The Gibbon philosophy is to perform small, easily tested changes to an ongoing development branch. An ideal pull request adds one feature or fixes one bug at a time. If you’re unsure where to begin with GitHub feel free to reach out on the Support forum or check out these great guides: makeapullrequest.com and opensource.guide

  1. Fork the GibbonEdu/core repository on GitHub and clone a copy on your local machine.
  2. Write some code and push your changes to your repo using the command line or your favourite Git GUI.
  3. Create a new pull request and fill in the template provided to tell us about your change.
  4. Be sure you’re submitting your pull request to the development branch (and not master).
  5. Submissions should have a changelog entry noting what was added, changed or fixed.

Thanks for reading!

Following these guidelines helps to communicate that you respect the time of the developers managing and developing this open source project. In return, they’ll reciprocate that respect in addressing your issue, assessing changes, and helping you finalize your pull requests.