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
m (Text replacement - "<code php>" to "<syntaxhighlight lang="php">")
 
(8 intermediate revisions by 3 users not shown)
Line 1: Line 1:
{{Moodle 3.1}}
{{Moodle 3.1}}
The competency API lives in the subsystem ''competency'', namespaced <code>\core_competency\</code> and located in the root folder ''competency''.
The competency API lives in the subsystem ''competency'', namespaced <syntaxhighlight lang="php">\core_competency\</syntaxhighlight> and located in the root folder ''competency''.
 
==Mental Models==
These are not diagrams of the database tables exactly - but do show the relation ships between the major components of the competencies API.
 
[[Image:Competencies and learning plan templates.png|frame|center|Competencies and learning plan templates]]
 
[[Image:Competencies and courses.png|frame|center|Competencies and courses]]
 
[[Image:Competencies and unlinked plans.png|frame|center|Competencies and unlinked plans]]


==Public API==
==Public API==
Line 8: Line 17:
==External API==
==External API==


[https://git.moodle.org/gw?p=moodle.git;a=blob;f=competency/classes/external.php External functions] are all located in <code>\core_competency\external</code>, mostly as a proxy to the public API.
[https://git.moodle.org/gw?p=moodle.git;a=blob;f=competency/classes/external.php External functions] are all located in <syntaxhighlight lang="php">\core_competency\external</syntaxhighlight>, mostly as a proxy to the public API.
 
==Evidence==
 
A piece of evidence is used as a record of an action that may affect the competency rating of a student. For instance, when a teacher rates a student in a course, a piece of evidence will be created to record who, what, where, when the rating had been done, in this case it would contain as much as: "The teacher Bob rated the competency 'Demonstrates understanding of French' of the student Ann in the course 'Introduction to French' with the rating 'Met' on the 3rd of January at 1pm".
 
===Custom evidence===
 
Developers wanting to record evidence for actions that are not covered by the standard API must use <syntaxhighlight lang="php">\core_competency\api::add_evidence()</syntaxhighlight>. Note that this method does not perform any capability checks as it is expected to be called as the result of another action which has been authorised. Evidence must not be recorded directly, they always are the result of something else. For that reason there is not any external function to add a piece of evidence.


==Frontend==
==Frontend==


The competency API comes without any frontend, though Moodle core ships with the admin tool <code>tool_lp</code> 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.
The competency API comes without any frontend, though Moodle core ships with the admin tool <syntaxhighlight lang="php">tool_lp</syntaxhighlight> 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===
===URL resolver===
Line 18: Line 35:
As some of the core APIs require a knowledge of the resource URLs, 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.
As some of the core APIs require a knowledge of the resource URLs, 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 <code>\core_competency\url::my_ressource_name()</code> method. Note that it is acceptable for a plugin to directly link to resource frontends within itself without using the resolver.
When referring to a resource from ''core'', use the corresponding <syntaxhighlight lang="php">\core_competency\url::my_ressource_name()</syntaxhighlight> method. Note that it is acceptable for a plugin to directly link to resource frontends within itself without using the resolver.


====Defining new URLs====
====Defining new URLs====
Line 24: Line 41:
Create a class and implement each routing method defined in [https://git.moodle.org/gw?p=moodle.git;a=blob;f=competency/classes/url.php \core_competency\url], though they should not be static, take [https://git.moodle.org/gw?p=moodle.git;a=blob;f=admin/tool/lp/classes/url_resolver.php \tool_lp\url_resolver] as a base or an example.
Create a class and implement each routing method defined in [https://git.moodle.org/gw?p=moodle.git;a=blob;f=competency/classes/url.php \core_competency\url], though they should not be static, take [https://git.moodle.org/gw?p=moodle.git;a=blob;f=admin/tool/lp/classes/url_resolver.php \tool_lp\url_resolver] as a base or an example.


Then indicate to core what class to use by defining the config variable <code>$CFG->core_competency_url_resolver</code>.
Then indicate to core what class to use by defining the config variable <syntaxhighlight lang="php">$CFG->core_competency_url_resolver</syntaxhighlight>.


<code php>
<syntaxhighlight lang="php">
$CFG->core_competency_url_resolver = '\\your_namespace\\your_class';
$CFG->core_competency_url_resolver = '\\your_namespace\\your_class';
</code>
</syntaxhighlight>


==Internal API==
==Internal API==
Line 34: Line 51:
===Persistents, or Models===
===Persistents, or Models===


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 <syntaxhighlight lang="php">\core_competency\persistent</syntaxhighlight> 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 <syntaxhighlight lang="php">PARAM_*</syntaxhighlight> 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 (<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 (<syntaxhighlight lang="php">boolean function can_do_the_thing();</syntaxhighlight>). 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:


{| class="nicetable"
{| class="wikitable"
|-
|-
| competency
| competency
Line 109: Line 126:
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 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 in 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 <code>templatable::export_for_template()</code>.
Exporters have come in 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 <syntaxhighlight lang="php">templatable::export_for_template()</syntaxhighlight>.
 
====Formatting, filters, context, etc...====
 
During export, the exporters will take care of formatting the text fields to be ready for output. This means that you do not need to worry about <syntaxhighlight lang="php">format_string()</syntaxhighlight> and <syntaxhighlight lang="php">format_text()</syntaxhighlight>. The filters, sanitization rules, etc... will automatically be applied. The exporter will use the related object <syntaxhighlight lang="php">context</syntaxhighlight> to determine the context of the strings.
 
The function <syntaxhighlight lang="php">format_text()</syntaxhighlight> is applied to properties of type <syntaxhighlight lang="php">PARAM_RAW</syntaxhighlight> when another property with the same name ending with ''format'' is also present. For instance, a <syntaxhighlight lang="php">PARAM_RAW</syntaxhighlight> property named ''description'' will be formatted when another property named ''descriptionformat'' is present. The function <syntaxhighlight lang="php">format_string()</syntaxhighlight> is applied to properties of type <syntaxhighlight lang="php">PARAM_TEXT</syntaxhighlight>.
 
It is important to note that after formatting the values can contain HTML and will therefore have to be treated as <syntaxhighlight lang="php">PARAM_RAW</syntaxhighlight>.

Latest revision as of 13:39, 14 July 2021

Moodle 3.1

The competency API lives in the subsystem competency, namespaced

\core_competency\

and located in the root folder competency.

Mental Models

These are not diagrams of the database tables exactly - but do show the relation ships between the major components of the competencies API.

Competencies and learning plan templates
Competencies and courses
Competencies and unlinked plans

Public API

The public API is defined by the API class which contains all the methods 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.

Evidence

A piece of evidence is used as a record of an action that may affect the competency rating of a student. For instance, when a teacher rates a student in a course, a piece of evidence will be created to record who, what, where, when the rating had been done, in this case it would contain as much as: "The teacher Bob rated the competency 'Demonstrates understanding of French' of the student Ann in the course 'Introduction to French' with the rating 'Met' on the 3rd of January at 1pm".

Custom evidence

Developers wanting to record evidence for actions that are not covered by the standard API must use

\core_competency\api::add_evidence()

. Note that this method does not perform any capability checks as it is expected to be called as the result of another action which has been authorised. Evidence must not be recorded directly, they always are the result of something else. For that reason there is not any external function to add a piece of evidence.

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 a knowledge of the resource URLs, 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 in 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()

.

Formatting, filters, context, etc...

During export, the exporters will take care of formatting the text fields to be ready for output. This means that you do not need to worry about

format_string()

and

format_text()

. The filters, sanitization rules, etc... will automatically be applied. The exporter will use the related object

context

to determine the context of the strings. The function

format_text()

is applied to properties of type

PARAM_RAW

when another property with the same name ending with format is also present. For instance, a

PARAM_RAW

property named description will be formatted when another property named descriptionformat is present. The function

format_string()

is applied to properties of type

PARAM_TEXT

. It is important to note that after formatting the values can contain HTML and will therefore have to be treated as

PARAM_RAW

.