Skip to content

Commit

Permalink
Merge pull request #868 from andrewnicols/mdl80005
Browse files Browse the repository at this point in the history
Changes for MDL-80677
  • Loading branch information
junpataleta authored Mar 13, 2024
2 parents 4374cb7 + bcec4ae commit 598bd1c
Show file tree
Hide file tree
Showing 3 changed files with 262 additions and 4 deletions.
113 changes: 113 additions & 0 deletions docs/apis/core/deprecation/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
---
title: Deprecation API
tags:
- deprecation
---

<!-- markdownlint-disable no-inline-html -->

import { Since } from '@site/src/components';

<Since version="4.4" issueNumbers="MDL-80005" />

When deprecating a code feature, it is often desirable to include a reasonable amount of information, and to provide a consistent deprecation message.

In some cases it is also desirable to check if a called class, or method, has been marked as deprecated.

One way to simplify this is through use of the `\core\attribute\deprecated` PHP attribute, which can be used in conjunction with the `\core\deprecation` class.

:::note

Please note that the attribute does _not_ replace the `@deprecated` phpdoc annotation. They serve slightly different purposes.

:::

The attribute can be used to specify information including:

- the replacement for that feature
- the version that the feature was deprecated in
- the relevant MDL
- the reason for deprecation
- whether the deprecation is final

## The `deprecated` attribute

The attribute is a Moodle PHP Attribute and can be applied to:

- classes, traits, interfaces, and enums
- enum cases
- global functions
- class constants, properties, and methods

```php title="Example attribute usage"
// On a global function:
#[\core\attribute\deprecated('random_bytes', since: '4.3')]
function random_bytes_emulate($length) {
// Replaced by random_bytes since Moodle 4.3.
}

// On a class:
#[\core\attribute\deprecated(replacement: null, since: '4.4', reason: 'This functionality has been removed.')]
class example {
#[\core\attribute\deprecated(
replacement: '\core\example::do_something',
since: '4.3',
reason: 'No longer required',
mdl: 'MDL-12345',
)]
public function do_something(): void {}
}

// On an enum case:
enum example {
#[\core\attribute\deprecated('example::OPTION', since: '4.4', final: true)]
case OPTION;
}
```

## Inspecting the attribute

The `\core\deprecation` class contains helper methods to inspect for use of the deprecated attribute and allows usage including:

- checking if a feature is deprecated
- emitting a deprecation notice if a feature is deprecated
- fetching an instance of the attribute to query further

```php title="Examples of usage"
// A method which has been initially deprecated, and replaced by 'random_bytes'. It should show debugging.
/** @deprecated since 4.3 */
#[\core\attribute\deprecated('random_bytes', since: '4.3')]
function random_bytes_emulate($length) {
\core\deprecation::emit_deprecation_if_present(__FUNCTION__);
return random_bytes($length);
}

// A method which has been finally deprecated and should throw an exception.
/** @deprecated since 2.7 */
#[\core\attribute\deprecated(replacement: 'Events API', since: '2.3', final: true)]
function add_to_log() {
\core\deprecation::emit_deprecation_if_present(__FUNCTION__);
}

// Checking when an enum case is deprecated:
\core\deprecation::is_deprecated(\core\param::RAW); // Returns false.
\core\deprecation::is_deprecated(\core\param::INTEGER); // Returns true.

// On an collection of items.
foreach ($values as $value) {
\core\deprecation::emit_deprecation_if_present($value);
$value->do_things();
}

// Checking if a class is deprecated:
\core\deprecation::is_deprecated(\core\task\manager::class); // Returns false.

// Checking if an instantiated class is deprecated:
\core\deprecation::is_deprecated(new \moodle_url('/example/'));

// Checking if a class method is deprecated:
\core\deprecation::is_deprecated([\moodle_url::class, 'out']);
\core\deprecation::is_deprecated([new \moodle_url('/example/'), 'out']);
```

This functionality is intended to simplify deprecation of features such as constants, enums, and related items which are called from centralised APIs and difficult to detect as deprecated.
104 changes: 104 additions & 0 deletions docs/devupdate.md
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,110 @@ $formatter->format_text(

:::

## Parameters

### API Change

<Since version="4.4" issueNumber="MDL-80005" />

Parameter constants, and the cleaning of values using these parameters, has been moved to a new enum in `\core\param`.

The enum contains relevant associated methods for fetching, validating, and cleaning the content of values, for example:

```php title="Examples of enum-based parameters"
// Clean an existing variable.
$value = \core\param::ALPHANUMEXT->clean($value);
$value = \core\param::ALPHANUMEXT->validate_param($value);
$value = \core\param::ALPHANUMEXT->clean_param_array($value);

// Require a param (replaced required_param).
$value = \core\param::ALPHANUMEXT->required_param('someparamname');
$value = \core\param::ALPHANUMEXT->optional_param('someparamname', 'defaultvalue');
$value = \core\param::ALPHANUMEXT->required_param_array('someparamname');
$value = \core\param::ALPHANUMEXT->optional_param_array('someparamname', []);
```

:::note

The existing `PARAM_*` constants, and related methods (`required_param`, `optional_param()`, `clean_param()`, and so on) remain in place, and are _not currently deprecated_. At this time _you do_ not need to migrate to the APIs.

:::

### Deprecations

<Since version="4.4" issueNumber="MDL-80005" />

A number of deprecated parameter types have been deprecated, these include:

- `PARAM_CLEAN`
- `PARAM_INTEGER`
- `PARAM_NUMBER`
- `PARAM_ACTION`
- `PARAM_FORMAT`
- `PARAM_MULTILANG`
- `PARAM_CLEANFILE`

These param types have all been deprecated since Moodle 2.0.

## Introduction of `deprecated` attribute

A new `\core\attribute\deprecated` attribute, and related `\core\deprecation` class have been introduced to provide a standardised way to emit deprecation notices.

The attribute can be applied to:

- classes, traits, interfaces, and enums
- enum cases
- global functions
- class constants, properties, and methods

The attribute can be used to specify information including:

- the version that a feature was deprecated
- the relevant MDL
- the reason for deprecation
- any replacement
- whether the deprecation is final

The `\core\deprecation` class contains helper methods to inspect for use of the deprecated attribute and allows usage including:

- checking if a feature is deprecated
- emitting a deprecation notice if a feature is deprecated

```php title="Examples of usage"
// A method which has been initially deprecated and should show debugging.
/** @deprecated since 4.3 */
#[\core\attribute\deprecated(replacement: 'random_bytes', since: '4.3')]
function random_bytes_emulate($length) {
\core\deprecation::emit_deprecation_if_present(__FUNCTION__);
return random_bytes($length);
}

// A method which has been finally deprecated and should throw an exception.
/** @deprecated since 2.7 */
#[\core\attribute\deprecated(replacement: 'Events API', since: '2.3', final: true)]
function add_to_log() {
\core\deprecation::emit_deprecation_if_present(__FUNCTION__);
}

// Checking when an enum case is deprecated:
\core\deprecation::is_deprecated(\core\param::RAW); // Returns false.
\core\deprecation::is_deprecated(\core\param::INTEGER); // Returns true.

// Checking if a class is deprecated:
\core\deprecation::is_deprecated(\core\task\manager::class); // Returns false.

// Checking if an instantiated class is deprecated:
\core\deprecation::is_deprecated(new \moodle_url('/example/'));

// Checking if a class method is deprecated:
\core\deprecation::is_deprecated([\moodle_url::class, 'out']);
\core\deprecation::is_deprecated([new \moodle_url('/example/'), 'out']);
```

This functionality is intended to simplify deprecation of features such as constants, enums, and related items which are called from centralised APIs and difficult to detect as deprecated.

This functionality does not replace the phpdoc `@deprecated` docblock.

## Enrolment

### Support for multiple instances in csv course upload
Expand Down
49 changes: 45 additions & 4 deletions general/development/policies/deprecation/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,28 @@ Deprecation affects only the current master version, in other words, the depreca
- Besides, if the entire class is being moved (for example, moving multiple class definitions from a monolithic file in to individual files), follow the process for [renaming classes](/docs/apis/commonfiles#dbrenamedclassesphp).
- A debugging message should be added to the function so that, when [developer debugging mode](https://docs.moodle.org/en/Debugging) is on, attention is drawn to the deprecation. The message should state that the function being called has been deprecated. The message should help a developer whose code currently calls the function that has gone. Tell them what they should do instead.

<Tabs>

<TabItem value="debugging" label="Deprecations using debugging">

```php
debugging('foobar() is deprecated. Please use foobar::blah() instead.', DEBUG_DEVELOPER);
```
debugging('foobar() is deprecated. Please use foobar::blah() instead.', DEBUG_DEVELOPER);
```

</TabItem>

<TabItem value="core_deprecation" label="Using the \core\deprecation API from Moodle 4.4">

```php
#[\core\deprecated('foobar::blahv()', since: '4.4', mdl: 'MDL-XXXXX')]
public function foobar(): void {
\core\deprecation::emit_deprecation_if_present([self, __FUNCTION__]);
}
```

</TabItem>

</Tabs>

- Unit tests that call the function should have `assertDebuggingCalled()` added to allow them to continue running.
- If the deprecated function has been replaced with a new function, ideally the new function should be called from the deprecated function, so that the new functionality is used. This will make maintenance easier moving forward.
Expand Down Expand Up @@ -84,9 +103,30 @@ Longer deprecation periods can be considered for functions that are widely used.
- If a function has been marked as deprecated for `3.[x]` (eg. 3.1) and set for removal at `3.[x + 4]` (eg. 3.5), soon after the release of `3.[x + 3].1` (eg. 3.4.1), the `3.[x + 4]` deprecation META will be processed. This means that the deprecated function will undergo final deprecation before `3.[x + 4]`, but only in the master version. This allows any potential regressions caused by the final deprecation of the function to be exposed as soon as possible.
- When a function undergoes final deprecation, all content of the function should be removed. In the skeleton that remains, an error statement should be included that indicates that the function cannot be used anymore. You can also direct developers to the new function(s) in this message.

<Tabs>

<TabItem value="debugging" label="Deprecations using debugging">

```php
throw new coding_exception(
'foobar() can not be used any more, please use foobar::blah'
);
```
throw new coding_exception('check_potential_filename() can not be used any more, please use new file API');
```

</TabItem>

<TabItem value="core_deprecation" label="Using the \core\deprecation API from Moodle 4.4">

```php
#[\core\deprecated('foobar::blah()', since: '4.4', mdl: 'MDL-XXXXX', final: true)]
public function foobar(): void {
\core\deprecation::emit_deprecation_if_present([self, __FUNCTION__]);
}
```

</TabItem>

</Tabs>

- All function parameters should be removed.
- Deprecated classes must be completely removed.
Expand Down Expand Up @@ -231,6 +271,7 @@ Named parameter arguments are available from PHP 8.0 onwards.
## See also

- [String deprecation](../../../projects/api/string-deprecation.md)
- [Deprecation attributes](/docs/apis/core/deprecation/)
- [External functions deprecation](/docs/apis/subsystems/external/writing-a-service#deprecation)
- [Capabilities deprecation](/docs/apis/subsystems/access#deprecating-a-capability)
- [SCSS deprecation](./scss-deprecation.md)
Expand Down

0 comments on commit 598bd1c

Please sign in to comment.