diff --git a/.github/workflows/dokuwiki.yml b/.github/workflows/dokuwiki.yml
new file mode 100644
index 0000000..bb23bc1
--- /dev/null
+++ b/.github/workflows/dokuwiki.yml
@@ -0,0 +1,11 @@
+name: DokuWiki Default Tasks
+on:
+ push:
+ pull_request:
+ schedule:
+ - cron: '14 0 5 * *'
+
+
+jobs:
+ all:
+ uses: dokuwiki/github-action/.github/workflows/all.yml@main
diff --git a/.github/workflows/phpTestLinux.yml b/.github/workflows/phpTestLinux.yml
deleted file mode 100644
index 968c447..0000000
--- a/.github/workflows/phpTestLinux.yml
+++ /dev/null
@@ -1,52 +0,0 @@
-name: PHP Tests on Linux
-
-on: [push, pull_request]
-
-jobs:
- testLinux:
- name: PHP ${{ matrix.php-versions }} DokuWiki ${{ matrix.dokuwiki-branch }}
- runs-on: ubuntu-latest
- if: github.event_name == 'push' || github.event.pull_request.head.repo.full_name != github.repository
-
- strategy:
- matrix:
- php-versions: ['7.2', '7.3', '7.4', '8.0']
- dokuwiki-branch: [ 'master', 'stable']
- exclude:
- - dokuwiki-branch: 'stable'
- php-versions: '8.0'
- fail-fast: false
-
- steps:
- - name: Checkout
- uses: actions/checkout@v2
-
- - name: Setup PHP
- uses: shivammathur/setup-php@v2
- with:
- php-version: ${{ matrix.php-versions }}
- extensions: mbstring, intl, PDO, pdo_sqlite, bz2
-
- - name: Setup problem matchers
- run: |
- echo ::add-matcher::${{ runner.tool_cache }}/php.json
- echo ::add-matcher::${{ runner.tool_cache }}/phpunit.json
-
- - name: Download DokuWiki Test-setup
- run: wget https://raw.github.com/splitbrain/dokuwiki-travis/master/travis.sh
-
- - name: Run DokuWiki Test-setup
- env:
- CI_SERVER: 1
- DOKUWIKI: ${{ matrix.dokuwiki-branch }}
- run: sh travis.sh
-
- - name: Setup PHPUnit
- run: |
- php _test/fetchphpunit.php
- cd _test
-
- - name: Run PHPUnit
- run: |
- cd _test
- php phpunit.phar --verbose --stderr --group plugin_oauth
diff --git a/Adapter.php b/Adapter.php
index 814862a..de3969c 100644
--- a/Adapter.php
+++ b/Adapter.php
@@ -2,6 +2,8 @@
namespace dokuwiki\plugin\oauth;
+use dokuwiki\Extension\EventHandler;
+use dokuwiki\Extension\Event;
use dokuwiki\Extension\ActionPlugin;
use OAuth\Common\Consumer\Credentials;
use OAuth\Common\Http\Exception\TokenResponseException;
@@ -32,7 +34,7 @@ abstract class Adapter extends ActionPlugin
*
* @inheritDoc
*/
- public function register(\Doku_Event_Handler $controller)
+ public function register(EventHandler $controller)
{
$controller->register_hook('PLUGIN_OAUTH_BACKEND_REGISTER', 'AFTER', $this, 'handleRegister');
}
@@ -40,7 +42,7 @@ public function register(\Doku_Event_Handler $controller)
/**
* Auto register this plugin with the oAuth authentication plugin
*/
- public function handleRegister(\Doku_Event $event, $param)
+ public function handleRegister(Event $event, $param)
{
$event->data[$this->getServiceID()] = $this;
}
@@ -64,6 +66,7 @@ public function initOAuthService($storageId = '')
$serviceFactory = new ServiceFactory();
$serviceFactory->setHttpClient(new HTTPClient());
+
$servicename = $this->getServiceID();
$serviceclass = $this->registerServiceClass();
if ($serviceclass) {
@@ -143,8 +146,10 @@ public function refreshOutdatedToken()
}
$token = $oauth->getStorage()->retrieveAccessToken($oauth->service());
- if ($token->getEndOfLife() < 0 ||
- $token->getEndOfLife() - time() > 3600) {
+ if (
+ $token->getEndOfLife() < 0 ||
+ $token->getEndOfLife() - time() > 3600
+ ) {
// token is still good
return;
}
@@ -168,7 +173,7 @@ public function refreshOutdatedToken()
* but might need to be overwritten for specific services
*
* @throws TokenResponseException
- * @throws Exception
+ * @throws \Exception
*/
public function login()
{
@@ -182,7 +187,7 @@ public function login()
$parameters['state'] = urlencode(base64_encode(json_encode(
[
'animal' => $animal,
- 'state' => md5(rand()),
+ 'state' => md5(random_int(0, mt_getrandmax())),
]
)));
$oauth->getStorage()->storeAuthorizationState($oauth->service(), $parameters['state']);
@@ -221,12 +226,10 @@ public function checkToken()
$oauth = $this->getOAuthService();
if (is_a($oauth, Abstract2Service::class)) {
- /** @var Abstract2Service $oauth */
if (!$INPUT->get->has('code')) return false;
$state = $INPUT->get->str('state', null);
$accessToken = $oauth->requestAccessToken($INPUT->get->str('code'), $state);
} else {
- /** @var Abstract1Service $oauth */
if (!$INPUT->get->has('oauth_token')) return false;
/** @var TokenInterface $token */
$token = $oauth->getStorage()->retrieveAccessToken($this->getServiceID());
@@ -239,7 +242,8 @@ public function checkToken()
if (
$accessToken->getEndOfLife() !== $accessToken::EOL_NEVER_EXPIRES &&
- !$accessToken->getRefreshToken()) {
+ !$accessToken->getRefreshToken()
+ ) {
msg('Service did not provide a Refresh Token. You will be logged out when the session expires.');
}
@@ -256,7 +260,7 @@ public function loginButton()
global $ID;
$attr = buildAttributes([
- 'href' => wl($ID, array('oauthlogin' => $this->getServiceID()), false, '&'),
+ 'href' => wl($ID, ['oauthlogin' => $this->getServiceID()], false, '&'),
'class' => 'plugin_oauth_' . $this->getServiceID(),
'style' => 'background-color: ' . $this->getColor(),
]);
diff --git a/Exception.php b/Exception.php
index a77842e..efdba5b 100644
--- a/Exception.php
+++ b/Exception.php
@@ -43,5 +43,4 @@ public function setContext(array $context)
{
$this->context = $context;
}
-
}
diff --git a/HTTPClient.php b/HTTPClient.php
index 3dff1a2..8f18ea1 100644
--- a/HTTPClient.php
+++ b/HTTPClient.php
@@ -12,15 +12,14 @@
*/
class HTTPClient implements ClientInterface
{
-
/** @inheritDoc */
public function retrieveResponse(
UriInterface $endpoint,
$requestBody,
- array $extraHeaders = array(),
+ array $extraHeaders = [],
$method = 'POST'
) {
- $http = new DokuHTTPClient;
+ $http = new DokuHTTPClient();
$http->keep_alive = false;
$http->headers = array_merge($http->headers, $extraHeaders);
diff --git a/OAuthManager.php b/OAuthManager.php
index b00414f..b7f0f94 100644
--- a/OAuthManager.php
+++ b/OAuthManager.php
@@ -22,6 +22,7 @@ public function startFlow($servicename)
$session = Session::getInstance();
$session->setLoginData($servicename, $ID);
+
$service = $this->loadService($servicename);
$service->initOAuthService();
$service->login(); // redirects
@@ -36,9 +37,7 @@ public function startFlow($servicename)
*/
public function continueFlow()
{
- return $this->loginByService() or
- $this->loginBySession() or
- $this->loginByCookie();
+ return $this->loginByService() || $this->loginBySession() || $this->loginByCookie();
}
/**
@@ -62,6 +61,7 @@ protected function loginByService()
if (!$logindata) return false;
$service = $this->loadService($logindata['servicename']);
$service->initOAuthService();
+
$session->clearLoginData();
// oAuth login
@@ -196,14 +196,14 @@ protected function validateUserData($userdata, $servicename)
$hlp = plugin_load('helper', 'oauth');
if (!$hlp->checkMail($userdata['mail'])) {
- throw new Exception('rejectedEMail', [join(', ', $hlp->getValidDomains())]);
+ throw new Exception('rejectedEMail', [implode(', ', $hlp->getValidDomains())]);
}
// make username from mail if empty
if (!isset($userdata['user'])) $userdata['user'] = '';
$userdata['user'] = $auth->cleanUser((string)$userdata['user']);
if ($userdata['user'] === '') {
- list($userdata['user']) = explode('@', $userdata['mail']);
+ [$userdata['user']] = explode('@', $userdata['mail']);
}
// make full name from username if empty
@@ -238,7 +238,7 @@ protected function processUserData($userdata, $servicename)
if ($localUser) {
$localUserInfo = $auth->getUserData($localUser);
$localUserInfo['user'] = $localUser;
- if(isset($localUserInfo['pass'])) unset($localUserInfo['pass']);
+ if (isset($localUserInfo['pass'])) unset($localUserInfo['pass']);
// check if the user allowed access via this service
if (!in_array($auth->cleanGroup($servicename), $localUserInfo['grps'])) {
@@ -312,5 +312,4 @@ protected function loadService($servicename)
if ($srv === null) throw new Exception("No such service $servicename");
return $srv;
}
-
}
diff --git a/RedirectSetting.php b/RedirectSetting.php
index 7694207..545d3f4 100644
--- a/RedirectSetting.php
+++ b/RedirectSetting.php
@@ -7,10 +7,11 @@
/**
* Custom Setting to display the default redirect URL
*/
-class RedirectSetting extends Setting {
-
+class RedirectSetting extends Setting
+{
/** @inheritdoc */
- function update($input) {
+ public function update($input)
+ {
return true;
}
@@ -22,11 +23,10 @@ public function html(\admin_plugin_config $plugin, $echo = false)
$hlp = plugin_load('helper', 'oauth');
$key = htmlspecialchars($this->key);
- $value = ''.$hlp->redirectURI().'
';
+ $value = '' . $hlp->redirectURI() . '
';
- $label = '';
- $input = '
'.$value.'
';
- return array($label, $input);
+ $label = '';
+ $input = '' . $value . '
';
+ return [$label, $input];
}
-
}
diff --git a/Service/AbstractOAuth2Base.php b/Service/AbstractOAuth2Base.php
index 0d72fb0..5927984 100644
--- a/Service/AbstractOAuth2Base.php
+++ b/Service/AbstractOAuth2Base.php
@@ -12,7 +12,6 @@
*/
abstract class AbstractOAuth2Base extends AbstractService
{
-
/** @inheritdoc */
protected function parseAccessTokenResponse($responseBody)
{
@@ -55,5 +54,4 @@ public function isValidScope($scope)
{
return true;
}
-
}
diff --git a/Session.php b/Session.php
index 530cfff..3b63438 100644
--- a/Session.php
+++ b/Session.php
@@ -8,7 +8,7 @@
class Session
{
/** @var Session */
- protected static $instance = null;
+ protected static $instance;
/**
* hidden constructor
@@ -52,10 +52,7 @@ public function setLoginData($servicename, $id)
*/
public function getLoginData()
{
- if (isset($_SESSION[DOKU_COOKIE]['auth']['oauth'])) {
- return $_SESSION[DOKU_COOKIE]['auth']['oauth'];
- }
- return false;
+ return $_SESSION[DOKU_COOKIE]['auth']['oauth'] ?? false;
}
/**
@@ -83,10 +80,10 @@ public function setUser($userdata, $resettime = true)
global $USERINFO;
if (
- !isset($userdata['user']) or
- !isset($userdata['name']) or
- !isset($userdata['mail']) or
- !isset($userdata['grps']) or
+ !isset($userdata['user']) ||
+ !isset($userdata['name']) ||
+ !isset($userdata['mail']) ||
+ !isset($userdata['grps']) ||
!is_array($userdata['grps'])
) {
throw new Exception('Missing user data, cannot save to session');
@@ -111,10 +108,7 @@ public function setUser($userdata, $resettime = true)
*/
public function getUser()
{
- if (isset($_SESSION[DOKU_COOKIE]['auth']['info'])) {
- return $_SESSION[DOKU_COOKIE]['auth']['info'];
- }
- return false;
+ return $_SESSION[DOKU_COOKIE]['auth']['info'] ?? false;
}
/**
@@ -133,7 +127,17 @@ public function setCookie($servicename, $storageId)
$cookie = "$servicename|oauth|$storageId";
$cookieDir = empty($conf['cookiedir']) ? DOKU_REL : $conf['cookiedir'];
$time = time() + $validityPeriodInSeconds;
- setcookie(DOKU_COOKIE, $cookie, $time, $cookieDir, '', ($conf['securecookie'] && is_ssl()), true);
+ setcookie(
+ DOKU_COOKIE,
+ $cookie,
+ [
+ 'expires' => $time,
+ 'path' => $cookieDir,
+ 'domain' => '',
+ 'secure' => $conf['securecookie'] && is_ssl(),
+ 'httponly' => true
+ ]
+ );
}
/**
@@ -144,7 +148,7 @@ public function setCookie($servicename, $storageId)
public function getCookie()
{
if (!isset($_COOKIE[DOKU_COOKIE])) return false;
- list($servicename, $oauth, $storageId) = explode('|', $_COOKIE[DOKU_COOKIE]);
+ [$servicename, $oauth, $storageId] = explode('|', $_COOKIE[DOKU_COOKIE]);
if ($oauth !== 'oauth') return false;
return ['servicename' => $servicename, 'storageId' => $storageId];
}
@@ -173,6 +177,5 @@ public function clear()
{
//FIXME clear cookie?
$this->clearLoginData();
-
}
}
diff --git a/Storage.php b/Storage.php
index cf2cb3a..f2bf76b 100644
--- a/Storage.php
+++ b/Storage.php
@@ -45,7 +45,7 @@ protected function loadServiceFile($service)
if (file_exists($file)) {
return unserialize(io_readFile($file, false));
} else {
- return array();
+ return [];
}
}
diff --git a/action/login.php b/action/login.php
index dad62a8..8bb16f8 100644
--- a/action/login.php
+++ b/action/login.php
@@ -1,5 +1,8 @@
*/
-class action_plugin_oauth_login extends DokuWiki_Action_Plugin
+class action_plugin_oauth_login extends ActionPlugin
{
/** @var helper_plugin_oauth */
protected $hlp;
@@ -31,10 +34,10 @@ public function __construct()
/**
* Registers a callback function for a given event
*
- * @param Doku_Event_Handler $controller DokuWiki's event controller object
+ * @param EventHandler $controller DokuWiki's event controller object
* @return void
*/
- public function register(Doku_Event_Handler $controller)
+ public function register(EventHandler $controller)
{
global $conf;
if ($conf['authtype'] != 'oauth') return;
@@ -51,10 +54,10 @@ public function register(Doku_Event_Handler $controller)
/**
* Start an oAuth login or restore environment after successful login
*
- * @param Doku_Event $event
+ * @param Event $event
* @return void
*/
- public function handleStart(Doku_Event $event)
+ public function handleStart(Event $event)
{
global $INPUT;
@@ -65,7 +68,7 @@ public function handleStart(Doku_Event $event)
try {
$om = new OAuthManager();
$om->startFlow($servicename);
- } catch (TokenResponseException|Exception $e) {
+ } catch (TokenResponseException | Exception $e) {
$this->hlp->showException($e, 'login failed');
}
}
@@ -73,11 +76,11 @@ public function handleStart(Doku_Event $event)
/**
* Add the oAuth login links to login form
*
- * @param Doku_Event $event event object by reference
+ * @param Event $event event object by reference
* @return void
* @deprecated can be removed in the future
*/
- public function handleOldLoginForm(Doku_Event $event)
+ public function handleOldLoginForm(Event $event)
{
/** @var Doku_Form $form */
$form = $event->data;
@@ -103,11 +106,11 @@ public function handleOldLoginForm(Doku_Event $event)
/**
* Add the oAuth login links to login form
*
- * @param Doku_Event $event event object by reference
+ * @param Event $event event object by reference
* @return void
* @deprecated can be removed in the future
*/
- public function handleLoginForm(Doku_Event $event)
+ public function handleLoginForm(Event $event)
{
/** @var Form $form */
$form = $event->data;
@@ -140,9 +143,9 @@ protected function prepareLoginButtons()
if (count($validDomains) > 0) {
$html .= '' . sprintf(
- $this->getLang('eMailRestricted'),
- '' . join(', ', $validDomains) . ''
- ) . '
';
+ $this->getLang('eMailRestricted'),
+ '' . implode(', ', $validDomains) . ''
+ ) . '';
}
$html .= '';
@@ -157,10 +160,10 @@ protected function prepareLoginButtons()
/**
* When singleservice is wanted, do not show login, but execute login right away
*
- * @param Doku_Event $event
+ * @param Event $event
* @return bool
*/
- public function handleDoLogin(Doku_Event $event)
+ public function handleDoLogin(Event $event)
{
global $ID;
global $INPUT;
@@ -193,10 +196,10 @@ public function handleDoLogin(Doku_Event $event)
*
* This can happen when the user is already logged in, but still doesn't have enough permissions
*
- * @param Doku_Event $event
+ * @param Event $event
* @return void
*/
- public function handleDeniedForm(Doku_Event $event)
+ public function handleDeniedForm(Event $event)
{
if ($this->getConf('singleService')) {
$event->preventDefault();
diff --git a/action/user.php b/action/user.php
index 2c07c69..639abfe 100644
--- a/action/user.php
+++ b/action/user.php
@@ -1,5 +1,8 @@
*/
-class action_plugin_oauth_user extends DokuWiki_Action_Plugin
+class action_plugin_oauth_user extends ActionPlugin
{
/** @var helper_plugin_oauth */
protected $hlp;
@@ -29,18 +32,22 @@ public function __construct()
/**
* Registers a callback function for a given event
*
- * @param Doku_Event_Handler $controller DokuWiki's event controller object
+ * @param EventHandler $controller DokuWiki's event controller object
* @return void
*/
- public function register(Doku_Event_Handler $controller)
+ public function register(EventHandler $controller)
{
global $conf;
if ($conf['authtype'] != 'oauth') return;
$conf['profileconfirm'] = false; // password confirmation doesn't work with oauth only users
- $controller->register_hook('HTML_UPDATEPROFILEFORM_OUTPUT', 'BEFORE', $this,
- 'handleOldProfileform'); // deprecated
+ $controller->register_hook(
+ 'HTML_UPDATEPROFILEFORM_OUTPUT',
+ 'BEFORE',
+ $this,
+ 'handleOldProfileform'
+ ); // deprecated
$controller->register_hook('FORM_UPDATEPROFILE_OUTPUT', 'BEFORE', $this, 'handleProfileform');
$controller->register_hook('AUTH_USER_CHANGE', 'BEFORE', $this, 'handleUsermod');
}
@@ -48,10 +55,10 @@ public function register(Doku_Event_Handler $controller)
/**
* Save groups for all the services a user has enabled
*
- * @param Doku_Event $event event object by reference
+ * @param Event $event event object by reference
* @return void
*/
- public function handleUsermod(Doku_Event $event)
+ public function handleUsermod(Event $event)
{
global $ACT;
global $USERINFO;
@@ -91,11 +98,11 @@ public function handleUsermod(Doku_Event $event)
/**
* Add service selection to user profile
*
- * @param Doku_Event $event event object by reference
+ * @param Event $event event object by reference
* @return void
* @deprecated
*/
- public function handleOldProfileform(Doku_Event $event)
+ public function handleOldProfileform(Event $event)
{
global $USERINFO;
/** @var auth_plugin_authplain $auth */
@@ -117,7 +124,10 @@ public function handleOldProfileform(Doku_Event $event)
$group = $auth->cleanGroup($service->getServiceID());
$elem = form_makeCheckboxField(
'oauth_group[' . $group . ']',
- 1, $service->getLabel(), '', 'simple',
+ 1,
+ $service->getLabel(),
+ '',
+ 'simple',
[
'checked' => (in_array($group, $USERINFO['grps'])) ? 'checked' : '',
]
@@ -132,10 +142,10 @@ public function handleOldProfileform(Doku_Event $event)
/**
* Add service selection to user profile
*
- * @param Doku_Event $event event object by reference
+ * @param Event $event event object by reference
* @return void
*/
- public function handleProfileform(Doku_Event $event)
+ public function handleProfileform(Event $event)
{
global $USERINFO;
/** @var auth_plugin_authplain $auth */
diff --git a/auth.php b/auth.php
index f6d94a9..96a4d85 100644
--- a/auth.php
+++ b/auth.php
@@ -43,7 +43,7 @@ public function trustExternal($user, $pass, $sticky = false)
// either oauth or "normal" plain auth login via form
$this->om = new OAuthManager();
if ($this->om->continueFlow()) return true;
- if($this->getConf('singleService')) {
+ if ($this->getConf('singleService')) {
return false; // no normal login in singleService mode
}
return null; // triggers the normal auth_login()
@@ -132,7 +132,7 @@ public function registerOAuthUser(&$userinfo, $servicename)
$count = 1;
}
}
- $user = $user . $count;
+ $user .= $count;
$userinfo['user'] = $user;
$groups_on_creation = [];
$groups_on_creation[] = $conf['defaultgroup'];
@@ -175,7 +175,7 @@ public function getUserByEmail($mail)
$mail = strtolower($mail);
foreach ($this->users as $user => $userinfo) {
- if (strtolower($userinfo['mail']) == $mail) return $user;
+ if (strtolower($userinfo['mail']) === $mail) return $user;
}
return false;
diff --git a/conf/default.php b/conf/default.php
index e7365e1..044c41f 100644
--- a/conf/default.php
+++ b/conf/default.php
@@ -1,4 +1,5 @@
*/
-
$meta['info'] = array(\dokuwiki\plugin\oauth\RedirectSetting::class);
$meta['custom-redirectURI'] = array('string','_caution' => 'warning');
-$meta['mailRestriction'] = array('string','_pattern' => '!^(@[^,@]+(\.[^,@]+)+(,|$))*$!'); // https://regex101.com/r/mG4aL5/3
+// https://regex101.com/r/mG4aL5/3
+$meta['mailRestriction'] = array('string','_pattern' => '!^(@[^,@]+(\.[^,@]+)+(,|$))*$!');
$meta['singleService'] = array('onoff');
$meta['register-on-auth'] = array('onoff','_caution' => 'security');
$meta['overwrite-groups'] = array('onoff','_caution' => 'danger');
diff --git a/helper.php b/helper.php
index 887baf8..8cbd185 100644
--- a/helper.php
+++ b/helper.php
@@ -1,4 +1,7 @@
*/
+use dokuwiki\Extension\Plugin;
use dokuwiki\Extension\Event;
use dokuwiki\plugin\oauth\Adapter;
-require_once(__DIR__ . '/vendor/autoload.php');
+require_once(__DIR__ . '/vendor/autoload.php'); // @todo can be removed with next dw release
/**
* Basic helper methods for the oauth flow
*/
-class helper_plugin_oauth extends DokuWiki_Plugin
+class helper_plugin_oauth extends Plugin
{
-
/**
* Load the needed libraries and initialize the named oAuth service
*
@@ -62,10 +65,9 @@ public function listServices($enabledonly = true)
// filter out unconfigured services
if ($enabledonly) {
- $services = array_filter($services, function ($service) {
+ $services = array_filter($services, static fn($service) =>
/** @var Adapter $service */
- return (bool)$service->getKey();
- });
+ (bool)$service->getKey());
}
return $services;
@@ -77,11 +79,10 @@ public function listServices($enabledonly = true)
public function getValidDomains()
{
if ($this->getConf('mailRestriction') === '') {
- return array();
+ return [];
}
$validDomains = explode(',', trim($this->getConf('mailRestriction'), ','));
- $validDomains = array_map('trim', $validDomains);
- return $validDomains;
+ return array_map('trim', $validDomains);
}
/**
@@ -95,7 +96,7 @@ public function checkMail($mail)
if (empty($validDomains)) return true;
foreach ($validDomains as $validDomain) {
- if (substr($mail, -strlen($validDomain)) === $validDomain) {
+ if (str_ends_with($mail, $validDomain)) {
return true;
}
}
@@ -108,7 +109,7 @@ public function checkMail($mail)
* @param Exception $e
* @param string $friendly - user friendly explanation if available
*/
- public function showException(\Exception $e, $friendly = '')
+ public function showException(Exception $e, $friendly = '')
{
global $conf;
@@ -117,7 +118,7 @@ public function showException(\Exception $e, $friendly = '')
// translate the message if possible, using context if available
$trans = $this->getLang($msg);
if ($trans) {
- if (is_a($e, \dokuwiki\plugin\oauth\Exception::class)) {
+ if ($e instanceof \dokuwiki\plugin\oauth\Exception) {
$context = $e->getContext();
$trans = sprintf($trans, ...$context);
}