# Upgrading to ME v28.0

{% hint style="warning" %}

#### Important Upgrade Notes

Release 1.28 contains version changes that are important to note:

* Laravel Update from 9.x -> 11.x
* beyondcode/laravel-websockets -> Laravel/Reverb
* Laminas Replacements
* Node.js version update from 14.18.3 -> 18.x and higher
* Moment.js -> day.js
* ADODB 5.21.\* -> 5.22.\*

Please review the [Important Changes](#important-changes) section before proceeding.
{% endhint %}

### Upgrading to v28.0

For traditonal upgrading see: [Part 1: Source Code Update](/technical/upgrade-guides/upgrading-to-me-1.27.md#part-1-source-code-update)

#### Incremental upgrading

Elentra ME v28.0 has been tagged continuously during development process which allows the ability to upgrade incrementally instead of all at once.&#x20;

There are 48 patches releases that contain the pattern of `v28.0-rc.X` . Upgrading incrementally allows to upgrade patch by patch or to upgrade by multiple patches.&#x20;

There are two types of patch releases, Technical and Product patch releases. Product patch releases contains a title of module worked on:

`v28.0-rc.44 Exam Improvements`

Each important upgrades will contain a patch release number to identify when the change has been merged in.&#x20;

## Important Changes - Library Upgrades

{% hint style="warning" %}
This release contains significant changes, and you will need to regression test all of your customisation in case these updates break them.
{% endhint %}

### Laravel 9.x -> 11.x

#### Laravel 9.x → 10.x: [Elentra ME v28.0-rc.3](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.3)

{% hint style="warning" %}
Laravel 10.x upgrade requires change to DB::raw\
See: <https://github.com/ElentraProject/elentra-1x-api/pull/1079>
{% endhint %}

#### Laravel 10.x → 11.x: [Elentra ME v28.0-rc.43](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.43)

#### Laravel Future Support:

| Version | PHP (\*)  | Release             | Bug Fixes Until     | Security Fixes Until |
| ------- | --------- | ------------------- | ------------------- | -------------------- |
| 9       | 8.0 - 8.2 | February 8th, 2022  | August 8th, 2023    | February 6th, 2024   |
| 10      | 8.1 - 8.3 | February 14th, 2023 | August 6th, 2024    | February 4th, 2025   |
| 11      | 8.2 - 8.4 | March 12th, 2024    | September 3rd, 2025 | March 12th, 2026     |
| 12      | 8.2 - 8.4 | Q1 2025             | Q3 2026             | Q1 2027              |

### **Laravel Web-sockets**

Changes were made to remove the web-socket library `beyondcode/laravel-websockets` which has been abandoned by the maintainers.\
Please See: <https://github.com/beyondcode/laravel-websockets>

To resolve this issue, `beyondcode/laravel-websockets` has been replaced with [Laravel Reverb ](https://github.com/laravel/reverb)which has been released March 12th 2024.

#### This change requires update across all Elentra repositories.

ME: [Elentra ME v28.0-rc.17](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.17)\
API: [v11.0-rc.6](https://github.com/ElentraProject/elentra-1x-api/releases/tag/v11.0-rc.6)\
EJS2: [v2.7.4](https://github.com/ElentraProject/elentra-2x-js/releases/tag/v2.7.4)\
DEV: [v5.0.3](https://github.com/ElentraProject/elentra-developer/releases/tag/v5.0.3)

**Configuration notes**

In general, the configuration should be managed exclusively through the `www-root/core/config/settings.inc.php` file. This means you don't need to worry about the `.env` files in `elentra-1x-api` and `elentra-2x-js`. The values in the `.env` files will be ignored if corresponding values are set in `settings.inc.php`.

```php
// Public websocket settings
define("WEBSOCKETS_AUTH_ENDPOINT", "/api/v2/broadcasting/auth"); // Endpoint for authenticating websocket connections
define("WEBSOCKETS_SERVER", "localhost");                        // Hostname or address of the websocket server  e.g.: elentra.med.university.edu                                                      
define("WEBSOCKETS_PORT", 6001);                                 // Port number for websocket connections Note: Default port is usually 443 for HTTPS
// Server websocket settings: specify the host and port on which to run the websockets server (reverb by default) itself, (usually 0.0.0.0:6001)
define("WEBSOCKETS_SERVER_HOST", "0.0.0.0");                    
define("WEBSOCKETS_SERVER_PORT", 6001);
define("WEBSOCKETS_SCHEME", "http");                            // Scheme used for websocket connections Note: Consider using 'https' for secure websocket connections
define("WEBSOCKETS_CLUSTER", "");                                      
// Websocket's app credentials (you may leave them as they are for development mode)
define("WEBSOCKETS_APP_ID", AUTH_APP_ID);
define("WEBSOCKETS_APP_KEY", "elentra-pusher-key");
define("WEBSOCKETS_APP_SECRET", "elentra-app-secret");
```

{% hint style="info" %}
**Note:** Do not confuse `WEBSOCKETS_SERVER` and `WEBSOCKETS_PORT` with `WEBSOCKETS_SERVER_HOST` and `WEBSOCKETS_PORT`. The former (`WEBSOCKETS_SERVER` and `WEBSOCKETS_PORT`) are for broadcasting the WebSocket, while the latter (`WEBSOCKETS_SERVER_HOST` and `WEBSOCKETS_PORT`) are used for serving the Reverb server, which is triggered by the `php artisan reverb:start` command.
{% endhint %}

**Setup Instructions**

Before running the `php artisan reverb:start` command, ensure you execute the following commands, assuming you have an up-to-date branch:

```bash
cd /var/www/vhosts/elentra-1x-me
composer install
composer update
cd /var/www/vhosts/elentra-1x-me/www-root/core/library/vendor/elentrapackages/elentra-1x-api
composer install
composer update
php artisan cache:clear
php artisan optimize:clear
php artisan reverb:start
```

{% hint style="info" %}
Production mode notes:

* Ensure `WEBSOCKETS_SERVER` is set to the appropriate server. For example, if your site is `http://www.example.com`, change `localhost` to `example.com`.
* Set `WEBSOCKETS_PORT` to `443` if you are using HTTPS.
* Change `WEBSOCKETS_SCHEME` to `https` if you are using HTTPS.
  {% endhint %}

### Laminas <a href="#laminas" id="laminas"></a>

Elentra ME has been using Laminas/Zend for a very long time that offers the same features that Laravel also supports. There was no need to have two frameworks that offer the same features, therefore v28.0 has removed Laminas libraries that can be replaced.

**Replace Laminas Cache**

Patch: [Elentra ME v28.0-rc.4](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.4)

Laminas cache was replaced with Laravel Cache by creating a wrapper around the Laminas Cache methods to ensure that no invasive changes are needed

#### **Replace Laminas Feed and Laminas HTTP**

Patch: [Elentra ME v28.0-rc.4](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.4)

Laminas Feed and Laminas HTTP were being used for RSS feeds that are rendered on the dashboard. This was replaced with `vedmant/laravel-feed-reader` on Elentra-1x-api.

#### **Remove Laminas JSON and Laminas MATH**

Laminas JSON was being used decode JSON which was replace with PHP native method of `json_decode.`

Laminas MATH was not being used within the application and can be removed

### **Node.js**

Patch: [Elentra ME v28.0-rc.1](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.1)

Elentra EJS2 now supports Node.js version 18 and higher. Ensure that custom added libraries are compatible with Node.js version 18 and higher

### Moment.js <a href="#moment.js" id="moment.js"></a>

Patch: [Elentra ME v28.0-rc.8](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.8)

Moment.js has been deprecated and was replace by days.js. The change requires to replace `moment()` with `dayjs()`

```javascript
- var start_date = moment(state.min_date).unix();
- var end_date = moment(state.max_date).subtract(1, 'second').unix();
+ var start_date = dayjs(state.min_date).unix();
+ var end_date = dayjs(state.max_date).subtract(1, 'second').unix();
```

Ensure that any uses of momont.js is replaced with dayjs

### ADODB <a href="#adodb" id="adodb"></a>

Paches: [Elentra ME v28.0-rc.40](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.40), [Elentra ME v28.0-rc.43](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.43)

There are significant changes with the ADODB upgrade from 5.21.\* to 5.22.\* that contains error handing and data integrity checks within the base class. These changes require a large amount of attention to ensure that current functionality is not impacted. There is a new setting called “STRICT\_MODE” which allows developers to turn on some checks, it is highly recommended to turn this off in production mode.

#### Invalid Constraints  <a href="#invalid-constraints" id="invalid-constraints"></a>

A new data integrity check is to ensure that all constraint columns must have an associated class attribute with same name.\
\
Code Snippet of Check:

```php
if (!in_array($constraint_key, $class_vars)) { 
    throw new Exception("Invalid constraint key ". $constraint_key ." for ". __FUNCTION__ ." in ". get_called_class(). " model."); 
}
```

**Example Error**

Example Class:

```php
class myModel extends Models_Base { 
    private $id, $name; 
}
```

Example Table:

```
id | name | deleted_date
```

Example call:

```php
return $self->fetchRow(array(
    array("key" => "id", "value" => $id, "method" => "="),
    array("key" => "name", "value" => $name, "method" => "="),
    array("key" => "deleted_date", "value" => null, "method" => "IS")
));
```

Since `delete_date` is not a class attribute of myModel class, an error is rendered.

Example of resolving the error:

```php
class myModel extends Models_Base {
   private $id,
           $name,
           $delete_date;
}
```

#### No Constraints <a href="#no-constraints" id="no-constraints"></a>

This check is to ensure that `fetchAll` and `fetchRow` have constraints passed as a non-empty array or as an empty value. `fetchAll` without a constraint should use getAll ADODB method instead.

Code Snippet of Check:

```php
if (!is_array($constraints) || empty($constraints)) {
    throw new Exception("No constraints provided for ". __FUNCTION__ ." in ". get_called_class(). " model.");
}
```

Example Error:

```php
return $self->fetchRow();
```

#### Failed Query <a href="#failed-query" id="failed-query"></a>

Query failure check has been implemented that will throw an error if the query fails and the exception returns the database error message back for logging. Query failures originally would return false then pass the boolean up the stack which cause an ambiguous datatype between no results and query fail.

Code Snippet of Check:

```php
if ($result === false && $db->ErrorMsg()) {
    throw new Exception("Error fetching row ". get_called_class(). " record: " . $db->ErrorMsg());
}
```

{% hint style="warning" %}
This might uncover previously unknown failing queries as a widely used pattern in Elentra is to pass false for no results but also pass false to failing queries.
{% endhint %}

#### Constraint and Value EQ Check <a href="#constraint-and-value-eq-check" id="constraint-and-value-eq-check"></a>

A query integrity check was added to ensure that no queries is executed with an `=` constraint using value of `null`. The reason for this is that any query that runs with an `=` constraint with `null` value will always return an empty results therefore should use `IS NULL` or `IS NOT NULL` instead.

&#x20;

Code Snippet of Check:

```php
if (is_null($value)) {
    Models_Base::triggerStrict("Value cannot be null, use `IS` or `IS NOT` instead.");
}
```

#### Example Error:

```php
$name = null;
return $self->fetchRow(array(
    array("key" => "id", "value" => $id, "method" => "="),
    array("key" => "name", "value" => $name, "method" => "=")
));
```

#### Example of resolving the error:

Resolving this error is more difficult and requires investigations since a condition of the query doesn’t contain a value.

```php
// Example of the most common issue:
$results = $self->fetchRow(array(
     array("key" => "deleted_date", "value" => null, "method" => "=")
));
// Should be:
$results = $self->fetchRow(array(
     array("key" => "deleted_date", "value" => null, "method" => "IS")
));
// Results will be an empty result
```

#### Failed Query Throws an Exception <a href="#failed-query-throws-an-exception" id="failed-query-throws-an-exception"></a>

With Strict Mode on, any ADODB query failure will throw an exception that will render an error message to the end user.

```php
if (defined("STRICT_MODE") && STRICT_MODE) {
    require_once(ENTRADA_ABSOLUTE . "/core/includes/database-exception-handler.inc.php");
    $db->raiseErrorFn = 'database_exception_handler';
}
```

Consortium Members can edit the exception behaviour by editing `database-exception-handler.inc.php`

```php
<?php
/*
    This method is used to handle database exceptions. It is called by the database class when an exception is thrown.
    The method will throw a new exception with the error message and error number.
*/
function database_exception_handler(
    string $dbms, 
    string $fn,
    int $errno,
    string $errmsg,
    string $p1, 
    array|bool $p2, 
    object &$thisConnection
) {
    // Falls back to the default error handler
    throw new Exception(
        "Database Exception: " . $dbms . " error in " . $fn . "(): " . $errmsg . " (" . $errno . ")",
        $errno
    );
}
```

#### Strict Mode <a href="#strict-mode" id="strict-mode"></a>

Strict mode was introduced to prevent an overwhelming amount of fatal errors during production. If a developer determines that an exception should under a strict mode can call the method `triggerStrict` in order to prevent the exception.

```php
private static function triggerStrict($message) {
    application_log("error", $message);
    if (defined("STRICT_MODE") && STRICT_MODE) {
        throw new Exception($message);
    }
}
```

## Important Changes - Architectural Changes

### Replacing Prototype with JQuery

Patches: [Elentra ME v28.0-rc.1](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.1), [Elentra ME v28.0-rc.2](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.2), [Elentra ME v28.0-rc.3](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.3)

Prototype is a JS library that has been part of the Elentra application since the first release. The library has not been updated since Sept. 2015 which the library scriptaculous is dependant on also hasn’t been updated from Dec. 2010.

Prototype will override JS event listeners of “show” and “hide” that bootstrap relies on. For this reason, a effort was made forward to remove prototype and scriptaculous from Elentra ME. Since Prototype is used throughout the application, additional logic was added on spa.head.php file:

```php
<?php
    $url = $_SERVER['REQUEST_URI'];
    // Admin Events Page has removed Prototype therefore DO NOT include it
    $include_scripts = true;
    $excluded_pages = ['/events', '/admin/events', '/dashboard', '/communities'];
    foreach ($excluded_pages as $page) {
        if (strncmp($url, $page, strlen($page)) === 0) {
            $include_scripts = false; // Don't include the scripts if the current page matches any excluded page
            break;
        }
    }
    // Include the scripts if the flag is still
    if ($include_scripts) {
        ?>
            <!-- Legacy Prototype -->
            <script src="<?php echo script(ENTRADA_RELATIVE . '/javascript/scriptaculous/prototype.js'); ?>"></script>
            <script src="<?php echo script(ENTRADA_RELATIVE . '/javascript/scriptaculous/scriptaculous.js'); ?>"></script>
            <script src="<?php echo script(ENTRADA_RELATIVE . '/javascript/livepipe/livepipe.js'); ?>"></script>
            <script src="<?php echo script(ENTRADA_RELATIVE . '/javascript/livepipe/window.js'); ?>"></script>
        <?php
    }
?>
```

When a page does not have prototype, it’s url is added to the list of excluded pages so that prototype can be slowly removed from Elentra.&#x20;

### Remove unused JS Files

Patches: [Elentra ME v28.0-rc.11](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.11), [Elentra ME v28.0-rc.12](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.12), [Elentra ME v28.0-rc.15](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.15), [Elentra ME v28.0-rc.16](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.16), [Elentra ME v28.0-rc.19](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.19)

List of removed files:

1. [www-root/javascript/assessments/rubrics/add-element.js](https://github.com/ElentraProject/elentra-1x-me/pull/4938/files#diff-5f70dcc4724ee2ef229deea126479ff2621e79777d12cca702fa6274c14a1351) \[[Elentra ME v28.0-rc.11](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.11)]
2. [www-root/javascript/exams/groups/add-element.js](https://github.com/ElentraProject/elentra-1x-me/pull/4941/files#diff-650b511ab5a755decc2cc0451841bf910931e38f6b1152176e15dacb1f99a4c4) \[[Elentra ME v28.0-rc.12](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.12)]
3. [www-root/javascript/assessments/assessment-external.js](https://github.com/ElentraProject/elentra-1x-me/pull/4949/files#diff-5555dadcf178ecb491e0af55fbe3b166c7231b2f193f6420a073f15ef2cd239e) \[[Elentra ME v28.0-rc.12](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.12)]
4. [www-root/javascript/assessments/reports/msf-report.es6.js](https://github.com/ElentraProject/elentra-1x-me/pull/4949/files#diff-50bf0e513ec31ba5982d4bf23d08d692cc2a26d1d047b4706501830b549dc26c) \[[Elentra ME v28.0-rc.12](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.12)]
5. [www-root/javascript/sandbox/sandbox.js](https://github.com/ElentraProject/elentra-1x-me/pull/4960/files#diff-2f24608b2b13cf1bb414222dfd5253780fc2bdd69babfa371b86f16ed8a965fa) \[[Elentra ME v28.0-rc.15](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.15)]
6. [www-root/javascript/settings/yearlevels.js](https://github.com/ElentraProject/elentra-1x-me/pull/4962/files#diff-3447c4b6a7e71a5bce8d5dfe6626e108fa8949c645e592a96eaa996fb2bb399e) \[[Elentra ME v28.0-rc.15](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.15)]
7. [www-root/javascript/windows/debug.js](https://github.com/ElentraProject/elentra-1x-me/pull/4963/files#diff-544185fea268ebe2aa77acd027a227da2382d28f59ed3dd0af365ac213690b56) \[[Elentra ME v28.0-rc.15](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.15)]
8. [www-root/javascript/windows/effects.js](https://github.com/ElentraProject/elentra-1x-me/pull/4963/files#diff-0e2829122383e478bde4d04ed21772743de57467f2befeb7b77986f5a4f0bffe) \[[Elentra ME v28.0-rc.15](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.15)]
9. [www-root/javascript/windows/extended\_debug.js](https://github.com/ElentraProject/elentra-1x-me/pull/4963/files#diff-1b238b6dc7c2758c22921afc2805bceadd50928537880a72215c5228a3bbf8bc) \[[Elentra ME v28.0-rc.15](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.15)]
10. [ww-root/javascript/windows/tooltip.js](https://github.com/ElentraProject/elentra-1x-me/pull/4963/files#diff-dbf0d4ef1e50bbbc9aa52b910d062c8dc05b911545ff364158344f6b9bbd9e0b) \[[Elentra ME v28.0-rc.15](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.15)]
11. [www-root/javascript/windows/window\_effects.js](https://github.com/ElentraProject/elentra-1x-me/pull/4963/files#diff-8b0aca6b3d593a14002c8c5a66fbb13bf6e1d67b05b00ddf9a66008afcee8481) \[[Elentra ME v28.0-rc.15](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.15)]
12. [www-root/javascript/windows/window\_ext.js](https://github.com/ElentraProject/elentra-1x-me/pull/4963/files#diff-d3eabbf8fe157a271f33b7a76d0533b0897dd5c5dec3bc21474858c0a72f4ae1) \[[Elentra ME v28.0-rc.15](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.15)]
13. [www-root/javascript/courses/course-version-select.js](https://github.com/ElentraProject/elentra-1x-me/pull/4953/files#diff-e0a9a92cc90595811d6f9e343bddc5e4c5aa7baf404823d9948b142d1c9584ee) \[[Elentra ME v28.0-rc.16](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.16)]
14. [www-root/javascript/notices.js](https://github.com/ElentraProject/elentra-1x-me/pull/4964/files#diff-da07a7d721531852e8388a387cb7fd73355303138a9db397437277f510315cc9) \[[Elentra ME v28.0-rc.16](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.16)]
15. [www-root/javascript/objectives\_assessment.js](https://github.com/ElentraProject/elentra-1x-me/pull/4964/files#diff-67d13def932f05b93e126fb078c50e8b2255eac7ebf16ebcc5dfae42e1b01df5) \[[Elentra ME v28.0-rc.16](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.16)]
16. [www-root/javascript/exams/exam-index.js](https://github.com/ElentraProject/elentra-1x-me/pull/4954/files#diff-9016f896cadaeca98447a042720499bd378b43feacd7dfd3709ef3c82745197b) \[[Elentra ME v28.0-rc.19](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.19)]
17. [www-root/javascript/exams/exams.js](https://github.com/ElentraProject/elentra-1x-me/pull/4954/files#diff-d92436e19c6137e3fc039ac0884dd7aa5afc6c32156907d77443da6c127fe8e6) \[[Elentra ME v28.0-rc.19](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.19)]
18. [www-root/javascript/exams/exams/exams-add-group-question.js](https://github.com/ElentraProject/elentra-1x-me/pull/4954/files#diff-b38331a6db5ab92cf8491e023b4bd8dbd011de4349edf29ef16d78f8a1e0131e) \[[Elentra ME v28.0-rc.19](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.19)]
19. [www-root/javascript/exams/exams/post.js](https://github.com/ElentraProject/elentra-1x-me/pull/4954/files#diff-ae310defb241cd701397230465a393e0e19d494cd7cca752302e80a12bf1b284) \[[Elentra ME v28.0-rc.19](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.19)]

### Remove unused API ednpoints <a href="#remove-unused-api-ednpoints" id="remove-unused-api-ednpoints"></a>

Patches: [Elentra ME v28.0-rc.14](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.14), [Elentra ME v28.0-rc.16](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.16)

List of files removed:

1. [www-root/api/learner-year-levels.api.php](https://github.com/ElentraProject/elentra-1x-me/pull/4974/files#diff-9b15ebd219ac083305ae42c47290cabf3c19009019f4601a35de46d0b55f118b) \[[Elentra ME v28.0-rc.14](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.14)]
2. [www-root/core/modules/admin/assessments/forms/api-list.inc.php](https://github.com/ElentraProject/elentra-1x-me/pull/4983/files#diff-2c6ad6e0973d7d09413c6bb206a80f57fc3c9640af6ca8af08e247273b76b80d) \[[Elentra ME v28.0-rc.16](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.16)]
3. [www-root/core/modules/admin/assessments/rubrics/items/api-list.inc.php](https://github.com/ElentraProject/elentra-1x-me/pull/4981/files#diff-d119db6e6de9b9ef980d489f4cf4829fb4ac7785065f6af71776d2020aba33c0) \[[Elentra ME v28.0-rc.16](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.16)]
4. [www-root/core/modules/admin/assessments/rubrics/items/api-rubric-add-item.inc.php](https://github.com/ElentraProject/elentra-1x-me/pull/4980/files#diff-1eaec727a2e50effb6c99f5bfb6235a7d9bcd59f2fc6818316168d0aaf2bd5dc) \[[Elentra ME v28.0-rc.16](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.16)]
5. [www-root/core/modules/admin/assessments/rubrics/api-list.inc.php](https://github.com/ElentraProject/elentra-1x-me/pull/4979/files#diff-57bb3d707afa52a525ccf79b79aaf7ca6caefbafa294bdfea52ac7c54903ae78) \[[Elentra ME v28.0-rc.16](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.16)]
6. [www-root/api/file-stats.api.php](https://github.com/ElentraProject/elentra-1x-me/pull/4978/files#diff-4971710c7711a17aeaa138e438ed128a9fb0af0a7230196b442a1d4df20b31d0) \[[Elentra ME v28.0-rc.16](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.16)]

### API Consolidation <a href="#api-consolidation" id="api-consolidation"></a>

Patches: [Elentra ME v28.0-rc.11](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.11), [Elentra ME v28.0-rc.12](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.12), [Elentra ME v28.0-rc.19](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.19), [Elentra Me v28.0-rc.23](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.23), [Elentra ME v28.0-rc.26](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.26)

List of files moved:

1. `www-root/core/modules/admin/assessments/blueprints/api-blueprints.inc.php -> www-root/api/blueprints.php` \[[Elentra ME v28.0-rc.11](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.11)]
2. `www-root/core/modules/admin/assessments/cbmeforms/api-forms.inc.php → www-root/api/assessments/cbmeforms/forms.php` \[[Elentra ME v28.0-rc.12](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.12)]
3. `www-root/core/modules/admin/assessments/cbmeforms/api-list.inc.php → www-root/api/assessments/cbmeforms/list.php` \[[Elentra ME v28.0-rc.12](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.12)]
4. `www-root/core/modules/admin/assessments/distributions/api-distributions.inc.php → www-root/api/assessments/distributions/distributions.php` \[[Elentra ME v28.0-rc.19](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.19)]
5. `www-root/core/modules/admin/assessments/forms/api-forms.inc.php → www-root/api/assessments/forms/forms.php` \[[Elentra Me v28.0-rc.23](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.23)]
6. `www-root/core/modules/admin/assessments/items/api-items.inc.php → www-root/api/assessments/items/items.php` \[[Elentra Me v28.0-rc.23](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.23)]
7. `www-root/core/modules/admin/assessments/scales/api-scales.inc.php → www-root/api/assessments/scales/scales.php` \[[Elentra Me v28.0-rc.23](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.23)]
8. `www-root/core/modules/admin/assessments/rubrics/api-rubric.inc.php → www-root/api/assessments/rubrics/rubrics.php` \[[Elentra ME v28.0-rc.26](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.26)]
9. `www-root/core/modules/admin/assessments/portfolios/api-portfolios.inc.php → www-root/api/assessments/portfolios/portfolios.php` \[[Elentra ME v28.0-rc.26](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.26)]
10. `www-root/core/modules/admin/assessments/api-assessment-reports.inc.php → www-root/api/assessments/assessment-reports.php` \[[Elentra ME v28.0-rc.43](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.43)]
11. `www-root/core/modules/admin/assessments/api-dashboard.inc.php → www-root/api/assessments/dashboard.php` \[[Elentra ME v28.0-rc.43](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.43)]
12. `www-root/core/modules/admin/assessments/api-evaluation-reports.inc.php → www-root/api/assessments/evaluation-reports.php` \[[Elentra ME v28.0-rc.43](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.43)]
13. `www-root/core/modules/admin/assessments/api-tools-feedbacks-reports.inc.php → www-root/api/assessments/tools-feedbacks-reports.php` \[[Elentra ME v28.0-rc.43](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.43)]
14. `www-root/core/modules/admin/assessments/api-user-photo-upload.inc.php → www-root/api/assessments/user-photo-upload.php` \[[Elentra ME v28.0-rc.43](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.43)]
15. `www-root/core/modules/admin/courses/api-courses.inc.php → www-root/api/courses/courses.php` \[[Elentra ME v28.0-rc.43](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.43)]
16. `www-root/core/modules/admin/courses/api-image.inc.php → www-root/api/courses/image.php` \[[Elentra ME v28.0-rc.43](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.43)]
17. `www-root/core/modules/admin/awards/api-awards.inc.php -> www-root/api/awards/awards.php` \[[Elentra ME v28.0-rc.43](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.43)]
18. `www-root/core/modules/admin/courses/cbme/api-cbme.inc.php → www-root/api/courses/cbme/cbme.php` \[[Elentra ME v28.0-rc.43](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.43)]
19. `www-root/core/modules/admin/courses/cbme/api-curriculumtags.inc.php → www-root/api/courses/cbme/curriculumtags.php` \[[Elentra ME v28.0-rc.43](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.43)]

### Remove functions.inc.php methods <a href="#remove-functions.inc.php-methods" id="remove-functions.inc.php-methods"></a>

Patches: [Elentra ME v28.0-rc.12](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.12), [Elentra ME v28.0-rc.30](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.30)<br>

List of methods removed:

1. check\_body \[[Elentra ME v28.0-rc.12](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.12)]
2. fetch\_curriculum\_objectives\_children \[[Elentra ME v28.0-rc.30](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.30)]
3. fetch\_objective\_child\_mapped\_course \[[Elentra ME v28.0-rc.30](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.30)]
4. clerkship\_categories\_inselect \[[Elentra ME v28.0-rc.30](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.30)]
5. clerkship\_generate\_included\_categories \[[Elentra ME v28.0-rc.30](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.30)]
6. clerkship\_categories\_inarray \[[Elentra ME v28.0-rc.30](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.30)]
7. clerkship\_categories\_name \[[Elentra ME v28.0-rc.30](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.30)]
8. permissions\_fetch \[[Elentra ME v28.0-rc.30](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.30)]
9. permissions\_by\_module \[[Elentra ME v28.0-rc.30](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.30)]
10. count\_notice\_reads \[[Elentra ME v28.0-rc.30](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.30)]
11. xml\_encode \[[Elentra ME v28.0-rc.30](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.30)]
12. xml\_decode \[[Elentra ME v28.0-rc.30](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.30)]
13. generate\_organisation\_select \[[Elentra ME v28.0-rc.30](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.30)]
14. nl2br\_replace \[[Elentra ME v28.0-rc.30](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.30)]
15. br2nl\_replace \[[Elentra ME v28.0-rc.30](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.30)]
16. NotifyFn \[[Elentra ME v28.0-rc.30](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.30)]
17. communities\_generate\_url \[[Elentra ME v28.0-rc.30](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.30)]
18. communities\_regenerate\_url \[[Elentra ME v28.0-rc.30](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.30)]
19. communities\_module\_title \[[Elentra ME v28.0-rc.30](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.30)]
20. communities\_module\_details \[[Elentra ME v28.0-rc.30](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.30)]
21. communities\_module\_deactivate \[[Elentra ME v28.0-rc.30](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.30)]
22. folder\_select\_view \[[Elentra ME v28.0-rc.30](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.30)]
23. communities\_pages\_fetch\_parent\_id \[[Elentra ME v28.0-rc.30](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.30)]
24. communities\_pages\_count \[[Elentra ME v28.0-rc.30](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.30)]
25. communities\_pages\_move \[[Elentra ME v28.0-rc.30](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.30)]
26. recursive\_delete\_file \[[Elentra ME v28.0-rc.30](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.30)]
27. fetch\_mime\_type \[[Elentra ME v28.0-rc.30](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.30)]
28. quiz\_completed\_attempts \[[Elentra ME v28.0-rc.30](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.30)]
29. quiz\_count\_questions \[[Elentra ME v28.0-rc.30](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.30)]
30. clerkship\_get\_agerange \[[Elentra ME v28.0-rc.30](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.30)]
31. courses\_fetch\_objectives\_cperiod \[[Elentra ME v28.0-rc.30](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.30)]
32. course\_fetch\_course\_audience \[[Elentra ME v28.0-rc.30](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.30)]
33. tracking\_output\_calendar\_controls \[[Elentra ME v28.0-rc.30](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.30)]
34. isUserInEventAttandance \[[Elentra ME v28.0-rc.30](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.30)]
35. events\_fetch\_event\_audience\_for\_user \[[Elentra ME v28.0-rc.30](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.30)]
36. assessment\_objectives\_display\_leafs \[[Elentra ME v28.0-rc.30](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.30)]
37. assessment\_objectives\_bottom\_leaves \[[Elentra ME v28.0-rc.30](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.30)]
38. assessment\_objective\_decendant\_mapped\_course \[[Elentra ME v28.0-rc.30](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.30)]
39. event\_objectives\_display\_leafs \[[Elentra ME v28.0-rc.30](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.30)]
40. event\_objectives\_bottom\_leaves \[[Elentra ME v28.0-rc.30](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.30)]
41. event\_objectives\_display\_leaf \[[Elentra ME v28.0-rc.30](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.30)]
42. event\_objective\_decendant\_mapped\_course \[[Elentra ME v28.0-rc.30](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.30)]
43. event\_objectives\_in\_list \[[Elentra ME v28.0-rc.30](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.30)]
44. events\_all\_active\_objectives \[[Elentra ME v28.0-rc.30](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.30)]
45. course\_objectives\_multiple\_select\_options\_checked \[[Elentra ME v28.0-rc.30](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.30)]
46. course\_objectives\_multiple\_select\_table \[[Elentra ME v28.0-rc.30](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.30)]
47. number\_suffix \[[Elentra ME v28.0-rc.30](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.30)]
48. getDefaultEnrollment \[[Elentra ME v28.0-rc.30](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.30)]
49. display\_default\_enrollment \[[Elentra ME v28.0-rc.30](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.30)]
50. objectives\_inlists \[[Elentra ME v28.0-rc.30](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.30)]
51. objectives\_inlists\_conf \[[Elentra ME v28.0-rc.30](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.30)]
52. objectives\_inselect \[[Elentra ME v28.0-rc.30](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.30)]
53. objectives\_delete \[[Elentra ME v28.0-rc.30](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.30)]
54. objectives\_delete\_for\_org \[[Elentra ME v28.0-rc.30](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.30)]
55. objectives\_intable \[[Elentra ME v28.0-rc.30](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.30)]
56. build\_option \[[Elentra ME v28.0-rc.30](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.30)]
57. display\_status\_messages \[[Elentra ME v28.0-rc.30](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.30)]
58. display\_mspr\_details \[[Elentra ME v28.0-rc.30](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.30)]
59. objectives\_competency\_courses \[[Elentra ME v28.0-rc.30](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.30)]
60. objectives\_output\_calendar\_controls \[[Elentra ME v28.0-rc.30](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.30)]
61. clear\_error \[[Elentra ME v28.0-rc.30](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.30)]
62. clear\_success \[[Elentra ME v28.0-rc.30](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.30)]
63. notice\_redirect \[[Elentra ME v28.0-rc.30](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.30)]
64. evaluations\_fetch\_attempts \[[Elentra ME v28.0-rc.30](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.30)]
65. substitute\_vars \[[Elentra ME v28.0-rc.30](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.30)]
66. validate\_in\_array \[[Elentra ME v28.0-rc.30](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.30)]
67. validate\_user\_ids \[[Elentra ME v28.0-rc.30](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.30)]
68. validate\_course\_id \[[Elentra ME v28.0-rc.30](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.30)]
69. validate\_organisation\_id \[[Elentra ME v28.0-rc.30](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.30)]
70. or\_bin \[[Elentra ME v28.0-rc.30](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.30)]
71. allowed\_tags \[[Elentra ME v28.0-rc.30](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.30)]
72. display\_person \[[Elentra ME v28.0-rc.30](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.30)]
73. display\_person\_email \[[Elentra ME v28.0-rc.30](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.30)]
74. display\_photo \[[Elentra ME v28.0-rc.30](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.30)]
75. display\_photo\_link \[[Elentra ME v28.0-rc.30](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.30)]
76. display\_photo\_placeholder \[[Elentra ME v28.0-rc.30](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.30)]
77. display\_zoom\_controls \[[Elentra ME v28.0-rc.30](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.30)]
78. validate\_integer\_field \[[Elentra ME v28.0-rc.30](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.30)]
79. groups\_get\_explicitly\_enrolled\_course\_ids \[[Elentra ME v28.0-rc.30](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.30)]
80. groups\_get\_all\_course\_lists \[[Elentra ME v28.0-rc.30](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.30)]
81. filtered\_words \[[Elentra ME v28.0-rc.30](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.30)]
82. clean\_empty\_values \[[Elentra ME v28.0-rc.30](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.30)]
83. prepare\_filter\_string \[[Elentra ME v28.0-rc.30](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.30)]
84. event\_text\_change \[[Elentra ME v28.0-rc.30](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.30)]
85. fetch\_objective\_parents \[[Elentra ME v28.0-rc.30](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.30)]
86. count\_objective\_child\_events \[[Elentra ME v28.0-rc.30](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.30)]
87. count\_objective\_child\_courses \[[Elentra ME v28.0-rc.30](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.30)]
88. cmp\_last\_first \[[Elentra ME v28.0-rc.30](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.30)]
89. cmp\_group\_name \[[Elentra ME v28.0-rc.30](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.30)]
90. cmp\_names\_ASC \[[Elentra ME v28.0-rc.30](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.30)]
91. cmp\_names\_DESC \[[Elentra ME v28.0-rc.30](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.30)]
92. cmp\_views\_ASC \[[Elentra ME v28.0-rc.30](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.30)]
93. cmp\_views\_DESC \[[Elentra ME v28.0-rc.30](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.30)]
94. cmp\_first\_view\_ASC \[[Elentra ME v28.0-rc.30](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.30)]
95. cmp\_first\_view\_DESC \[[Elentra ME v28.0-rc.30](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.30)]
96. cmp\_last\_view\_ASC \[[Elentra ME v28.0-rc.30](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.30)]
97. cmp\_last\_view\_DESC \[[Elentra ME v28.0-rc.30](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.30)]
98. cmp\_number \[[Elentra ME v28.0-rc.30](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.30)]
99. unixStringtoDate \[[Elentra ME v28.0-rc.30](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.30)]
100. assessments\_items\_subnavigation \[[Elentra ME v28.0-rc.30](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.30)]
101. removeElementsByTagName \[[Elentra ME v28.0-rc.30](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.30)]
102. hidden\_params \[[Elentra ME v28.0-rc.30](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.30)]
103. isUsingSecureBrowser \[[Elentra ME v28.0-rc.30](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.30)]

### Notifications <a href="#notifications" id="notifications"></a>

&#x20;Patches: [Elentra ME v28.0-rc.33](https://github.com/ElentraProject/elentra-1x-me/releases/tag/v28.0-rc.33)

The notifications was refactored to increase readability and maintainability by removing the switch statement and replacing it with a match statement.

#### New Directory Tree:

```
↪ Notifications
  ↪ templates
    ↪ ...  
  ↪ BaseNotification.class.php
  ↪ INotificationGenerator.class.php
  ↪ Notification.class.php
```

#### Match Statement

```php
$notification_body_generator = match($notification_user->getContentType()){
    "assessment" => new AssessmentNotification($notification_user, $params),
    "assessment_approver" => new AssessmentApproverNotification($params["proxy_id"], $params),
    "assessment_complete_now_drafted" => new AssessmentCompleteNowNotification($params["record_id"], "drafted"),
    "assessment_complete_now_submitted" => new AssessmentCompleteNowNotification($params["record_id"], "submitted"),
    "assessment_delegation" => new AssessmentDelegationNotification($params["record_id"], $params["proxy_id"], $params["subcontent_id"], $params["nuser_id"]),
    "assessment_delegation_assignment_removed" => new AssessmentDelegationAssignmentRemovedNotification($notification_user, $params["proxy_id"], $params["subcontent_id"]),
    "assessment_delegation_general" => new AssessmentDelegationGeneralNotification($params["record_id"], $params["proxy_id"], $params["subcontent_id"]),
    "assessment_delegation_required_target_assessor" => new AssessmentDelegationRequiredTargetAssessorNotification($params["record_id"], $params["proxy_id"], $params),
    "assessment_feedback" => new AssessmentFeedbackNotificaiton($params["record_id"], $params["proxy_id"]),
    "assessment_flagged_response" => new AssessmentFlaggedNotification($params["record_id"], $params["proxy_id"]),
    "assessment_expiry_warning" => new AssessmentExpiryWarningNotification($notification_user, $params["record_id"], $params["proxy_id"]),
    "assessment_general" => new AssessmentGeneralNotification($params["proxy_id"], $params["record_id"], $notification_user),
    "assessment_removal" => new AssessmentRemovalNotification($notification_user, $params["record_id"], $params["proxy_id"]),
    "assessment_submitted" => new AssessmentSubmittedNotification($params["record_id"], $params["proxy_id"], $params),
    "assessment_submitted_notify_approver" => new AssessmentSubmittedNotifyApproverNotification($params["record_id"], $params["proxy_id"]),
    "assessment_submitted_notify_learner" => new AssessmentSubmittedNotifyLearnerNotification($params["record_id"]),
    "assessment_task_deleted" => new AssessmentTaskDeletedNotification($params["record_id"], $params["subcontent_id"]),
    "assessment_task_deleted_forwarded" => new AssessmentTaskDeletedForwardedNotification($params["record_id"], $params["subcontent_id"]),
    "assessment_task_forwarded" => new AssessmentTaskForwardedNotification($notification_user, $params["proxy_id"], $params["record_id"]),
    "assessment_task_reopened" => new AssessmentTaskReopenedNotification($params["record_id"], $params["subcontent_id"]),
    "delegated_assessment_task_deleted" => new DelegatedAssessmentTaskDeletedNotification($notification_user, $params["record_id"]),
    "delegation_task_deleted" => new DelegationTaskDeletedNotification($notification_user, $params["record_id"]),
    "distribution_assessment_summary" => new DistributionAssessmentSummaryNotification($notification_user, $params["record_id"], $params["proxy_id"], $params["subcontent_id"]),
    "evaluation" => new EvaluationNotification($notification_user, $params["record_id"], $params["subcontent_id"]),
    "evaluation_overdue" => new EvaluationNotification($notification_user, $params["record_id"], $params["subcontent_id"]),
    "evaluation_request" => new EvaluationRequestNotification($notification_user, $params["proxy_id"], $params["record_id"]),
    "evaluation_threshold" => new EvaluationThresholdNotification($notification_user, $params["proxy_id"], $params["record_id"]),
    "logbook_rotation" => new LogbookRotationNotification($notification_user, $params["proxy_id"], $params["record_id"]),
    "notification-assessment-embargoed-submitted" => new NotificationAssessmentEmbargoedSubmittedNotification($params["record_id"]),
    "preceptor_access_request" => new PreceptorAccessRequestNotification($params["record_id"], $params["proxy_id"]),
    "preceptor_inactive_access_request" => new PreceptorInactiveAccessNotification($params["record_id"], $params["proxy_id"]),
    "reminder_distribution_assessment_summary" => new DistributionAssessmentSummaryNotification($notification_user, $params["record_id"], $params["proxy_id"], $params["subcontent_id"]),
    "submit_assessment_on_behalf" => new SubmitAssessmentOnBehalfNotification($notification_user, $params["record_id"], $params["proxy_id"]),
    default => $notification_body_generator = new DefaultNotification($notification_user, $params["record_id"], $params["proxy_id"], $params["nuser_id"])
};
```

<br>


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.elentra.org/technical/upgrade-guides/upgrading-to-me-v28.0.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
