Note:

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

Competency API: Difference between revisions

From MoodleDocs
(git commit -m 'Initial commit')
 
No edit summary
Line 35: Line 35:
The class <code>\core_competency\persistent</code> represents an object in the database. It is typically what is called a model in general. It contains the list of fields present in the database table, as well as their <code>PARAM_*</code> types. Basic validation of the param types is automatically performed prior to any database write operation. Additional validation can also be added by developers. In essence, the persistent knows everything about its data and when it is valid or not. Persistents are able to CRUD themselves in the database. They are also the right place to perform complex queries which join multiple persistents together.
The class <code>\core_competency\persistent</code> represents an object in the database. It is typically what is called a model in general. It contains the list of fields present in the database table, as well as their <code>PARAM_*</code> types. Basic validation of the param types is automatically performed prior to any database write operation. Additional validation can also be added by developers. In essence, the persistent knows everything about its data and when it is valid or not. Persistents are able to CRUD themselves in the database. They are also the right place to perform complex queries which join multiple persistents together.


There is never any access control performed within the persistent! However, the competency API is oriented towards model-based ACL, therefore some of the persistents contain helper ACL methods (<code>boolean function can_do_the_thing();</code>). The main benefit of adding ACL methods to the persistent is to avoid repeating the capability names all over the place, and thus reducing code complexity and human errors.
There is never any access control performed within the persistent! However, the competency API is oriented towards model-based Access Control List (ACL), therefore some of the persistents contain helper ACL methods (<code>boolean function can_do_the_thing();</code>). The main benefit of adding ACL methods to the persistent is to avoid repeating the capability names all over the place, and thus reducing code complexity and human errors.


Here is a non-exaustive list of the persistents:
Here is a non-exaustive list of the persistents:

Revision as of 08:31, 19 April 2016

The competency API lives in the subsystem competency, namespaced \core_competency\ and located in the root folder competency.

Public API

The public API class contains all the methods which are publicly available to any code taking action on competency related objects and data. No code should ever directly call the database, or persistent (models) methods, unless they are within an API method. All public API methods MUST perform the capability checks relevant to the actions that they are representing. The API methods can be seen as the controllers, they are a mandatory step to accessing the data, even within the competency API itself.

External API

External functions are all located in \core_competency\external, mostly as a proxy to the public API.

Frontend

The competency API comes without any frontend, though Moodle core ships with the admin tool tool_lp which is acting as the default frontend for competencies. It includes templates, javascript (AMD modules) and some additional external functions. It was built split from the backend to easily allow the support for other frontends.

URL resolver

As some of the core APIs require to know the URL to a resource, we introduced the concept of a URL resolver. The URL resolver is used to determine the location of a resource from core, without forcing the default frontend to be used.

When referring to a resource from core, use the corresponding \core_competency\url::my_ressource_name() method. Note that it is acceptable for a plugin to directly link to resource frontends within itself without using the resolver.

Defining new URLs

Create a class and implement each routing method defined in \core_competency\url, though they should not be static, take \tool_lp\url_resolver as a base or an example.

Then indicate to core what class to use by defining the config variable $CFG->core_competency_url_resolver.

$CFG->core_competency_url_resolver = '\\your_namespace\\your_class';

Internal API

Persistents, or Models

The class \core_competency\persistent represents an object in the database. It is typically what is called a model in general. It contains the list of fields present in the database table, as well as their PARAM_* types. Basic validation of the param types is automatically performed prior to any database write operation. Additional validation can also be added by developers. In essence, the persistent knows everything about its data and when it is valid or not. Persistents are able to CRUD themselves in the database. They are also the right place to perform complex queries which join multiple persistents together.

There is never any access control performed within the persistent! However, the competency API is oriented towards model-based Access Control List (ACL), therefore some of the persistents contain helper ACL methods (boolean function can_do_the_thing();). The main benefit of adding ACL methods to the persistent is to avoid repeating the capability names all over the place, and thus reducing code complexity and human errors.

Here is a non-exaustive list of the persistents:

competency A single competency
competency_framework A framework of competencies
course_competency A relationship table (many-to-many) linking courses and competencies
course_competency_settings The settings related to competencies in a course
course_module_competency A relationship table (many-to-many) linking course modules and competencies
evidence A piece of evidence relating the proficiency of a user towards a competency
plan A group of competencies for a user to achieve, often referred to as learning plans
plan_competency A relationship table (many-to-many) linking plans and competencies
related_competency A relationship table (many-to-many) linking competencies to other competencies (within the same framework)
template A template for a plan
template_competency A relationship table (many-to-many) linking templates and competencies
template_cohort The cohorts attached to a template, from which we will create plans.
user_competency The record of the proficiency and rating of a user towards a competency
user_competency_course The record of the rating of a user towards a competency but limited to the scope of a course
user_competency_plan The record of the proficiency and rating of a user within a plan that was archived/completed, understand frozen.
user_evidence A piece of evidence of prior learning
user_evidence_competency Many-to-many relationship between evidence of prior learning and competencies

Exporters

When writing external functions and templates we often needed to explicitly specify all the properties of the persistents. For instance, when returning a competency from an external function, when creating a competency from an external function, when preparing the context of a template, when getting the context for a template from an external function, etc... As persistents already define their properties we decided to create exporters (they are sometimes referred to as serialisers), and persistent-based exporters.

Exporters are classes which convert objects to stdClasses. They may add more properties to the objects as they export them (E.g. generating a timeago property from the date property of the object). Therefore exporters are aware of and define all the properties that can be read from an object, and all the properties that are saved in an object.

They mainly serve two purposes:

  1. They export an object consistently wherever they are used, i.e. all properties will always be present
  2. They generate the external function parameters and returns structure automatically
    • The parameters will be the update structure, which contains the real fields
    • The returns structure will be the read structure, which contains everything.

Exporters can also define related objects. When specified those must be set prior to exporting the data, mainly to improve performance. At this stage they may be a bit weak and difficult to work with as adding related objects to an existing exporter will require all usage of this exporter to be updated. We have raised an issue to try to improve their design: MDL-53052.

Exporters have come very handy when we had to add new properties to persistents, or to export new properties from an existing object. They greatly simplify the maintainability of external functions and templatable::export_for_template().