Module 5: Core APIs & Database

Data Manipulation and Forms

1. Data Manipulation API (DML)

Never write raw SQL queries unless absolutely necessary. Use the global $DB object.

global $DB;

// Get a single record
$user = $DB->get_record('user', ['id' => 1]);

// Get records
$courses = $DB->get_records('course', ['visible' => 1]);

// Insert
$record = new stdClass();
$record->name = 'New Thing';
$id = $DB->insert_record('my_table', $record);

// Update
$record->id = $id;
$record->name = 'Updated Thing';
$DB->update_record('my_table', $record);

2. Moodle Forms API

Moodle uses a wrapper around PEAR HTML_QuickForm.

require_once($CFG->libdir.'/formslib.php');

class simplehtml_form extends moodleform {
    public function definition() {
        $mform = $this->_form;

        $mform->addElement('text', 'email', get_string('email'));
        $mform->setType('email', PARAM_NOTAGS);
        $mform->addRule('email', null, 'required', null, 'client');

        $this->add_action_buttons();
    }
}

3. Events API

Moodle uses an event-driven architecture. You can trigger events or listen for them (Observers).

Triggering an Event

$event = \local_myplugin\event\something_happened::create([
    'context' => $context,
    'objectid' => $record->id
]);
$event->trigger();

Listening (Observer)

Define the observer in db/events.php:

$observers = [
    [
        'eventname' => '\core\event\course_completed',
        'callback'  => 'local_myplugin\observer::course_completed',
    ],
];

4. File API

Handling files in Moodle is complex because of the secure storage system (files are hashed and stored in moodledata/filedir).

// Saving a file from a form
$mform->save_stored_file('attachment', $context->id, 'local_myplugin', 'attachment', $itemid);

// Serving a file (pluginfile.php)
function local_myplugin_pluginfile($course, $cm, $context, $filearea, $args, $forcedownload, array $options=array()) {
    // Check permissions...
    send_stored_file($file, 0, 0, $forcedownload, $options);
}

5. Navigation API

You can inject links into the primary navigation, user menu, or course settings menu using hooks in lib.php.

// lib.php
function local_myplugin_extend_navigation(global_navigation $nav) {
    $mainnode = $nav->add(get_string('pluginname', 'local_myplugin'));
    $mainnode->add('My Dashboard', new moodle_url('/local/myplugin/index.php'));
}

function local_myplugin_extend_settings_navigation(settings_navigation $nav, context $context) {
    if ($context->contextlevel == CONTEXT_COURSE) {
        $coursenode = $nav->get('courseadmin');
        $coursenode->add('My Plugin Settings', new moodle_url('/local/myplugin/settings.php'));
    }
}

6. Web Services API (Server)

To expose your plugin's functionality to external apps (like the Mobile App), define functions in classes/external.php and register them in db/services.php.

// classes/external.php
use external_api;
use external_function_parameters;
use external_single_structure;
use external_value;

class local_myplugin_external extends external_api {
    
    public static function get_data_parameters() {
        return new external_function_parameters([
            'id' => new external_value(PARAM_INT, 'The ID')
        ]);
    }

    public static function get_data($id) {
        // Validate parameters
        $params = self::validate_parameters(self::get_data_parameters(), ['id' => $id]);
        
        // Logic...
        return ['result' => 'Success'];
    }

    public static function get_data_returns() {
        return new external_single_structure([
            'result' => new external_value(PARAM_TEXT, 'Result status')
        ]);
    }
}

6. Output Components (Templatable)

Modern Moodle development separates logic from presentation using the templatable interface.

// 1. Create a class that holds the data for the template
class my_widget implements \renderable, \templatable {
    public function export_for_template(\renderer_base $output) {
        return [
            'title' => 'My Widget',
            'items' => ['A', 'B', 'C']
        ];
    }
}

// 2. Render it in your script
$widget = new my_widget();
echo $OUTPUT->render($widget);

// 3. Create the template (templates/my_widget.mustache)
// <div class="widget">
//   <h3>{{title}}</h3>
//   <ul>{{#items}}<li>{{.}}</li>{{/items}}</ul>
// </div>