diff --git a/administrator/components/com_scheduler/src/Traits/TaskPluginTrait.php b/administrator/components/com_scheduler/src/Traits/TaskPluginTrait.php index cebb7b65f992e..16f3ac1481542 100644 --- a/administrator/components/com_scheduler/src/Traits/TaskPluginTrait.php +++ b/administrator/components/com_scheduler/src/Traits/TaskPluginTrait.php @@ -215,7 +215,7 @@ protected function getRoutineId(Form $form, $data): string // If we're unable to find a routineId, it might be in the form input. if (empty($routineId)) { - $app = $this->app ?? Factory::getApplication(); + $app = $this->getApplication() ?? ($this->app ?? Factory::getApplication()); $form = $app->getInput()->get('jform', []); $routineId = ArrayHelper::getValue($form, 'type', '', 'STRING'); } @@ -248,7 +248,7 @@ protected function logTask(string $message, string $priority = 'info'): void if (!$langLoaded) { - $app = $this->app ?? Factory::getApplication(); + $app = $this->getApplication() ?? ($this->app ?? Factory::getApplication()); $app->getLanguage()->load('com_scheduler', JPATH_ADMINISTRATOR); $langLoaded = true; } diff --git a/libraries/src/Plugin/CMSPlugin.php b/libraries/src/Plugin/CMSPlugin.php index c639b1440402f..2a544990c6cdd 100644 --- a/libraries/src/Plugin/CMSPlugin.php +++ b/libraries/src/Plugin/CMSPlugin.php @@ -10,6 +10,7 @@ \defined('JPATH_PLATFORM') or die; +use Joomla\CMS\Application\CMSApplicationInterface; use Joomla\CMS\Extension\PluginInterface; use Joomla\CMS\Factory; use Joomla\Event\AbstractEvent; @@ -75,6 +76,15 @@ abstract class CMSPlugin implements DispatcherAwareInterface, PluginInterface */ protected $allowLegacyListeners = true; + /** + * The application object + * + * @var CMSApplicationInterface + * + * @since __DEPLOY_VERSION__ + */ + private $application; + /** * Constructor * @@ -120,6 +130,7 @@ public function __construct(&$subject, $config = array()) if (property_exists($this, 'app')) { + @trigger_error('The application should be injected through setApplication() and requested through getApplication().', E_USER_DEPRECATED); $reflection = new \ReflectionClass($this); $appProperty = $reflection->getProperty('app'); @@ -131,6 +142,7 @@ public function __construct(&$subject, $config = array()) if (property_exists($this, 'db')) { + @trigger_error('The database should be injected through the DatabaseAwareInterface and trait.', E_USER_DEPRECATED); $reflection = new \ReflectionClass($this); $dbProperty = $reflection->getProperty('db'); @@ -162,7 +174,7 @@ public function loadLanguage($extension = '', $basePath = JPATH_ADMINISTRATOR) } $extension = strtolower($extension); - $lang = Factory::getLanguage(); + $lang = $this->getApplication() ? $this->getApplication()->getLanguage() : Factory::getLanguage(); // If language already loaded, don't load it again. if ($lang->getPaths($extension)) @@ -174,6 +186,35 @@ public function loadLanguage($extension = '', $basePath = JPATH_ADMINISTRATOR) || $lang->load($extension, JPATH_PLUGINS . '/' . $this->_type . '/' . $this->_name); } + /** + * Translates the given key with the local applications language. If arguments are available, then + * injects them into the translated string. + * + * @param string $key The key to translate + * @param mixed[] $arguments The arguments + * + * @return string The translated string + * + * @since __DEPLOY_VERSION__ + * + * @see sprintf + */ + protected function translate(string $key): string + { + $language = $this->getApplication()->getLanguage(); + + $arguments = \func_get_args(); + + if (count($arguments) > 1) + { + $arguments[0] = $language->_($key); + + return \call_user_func_array('sprintf', $arguments); + } + + return $language->_($key); + } + /** * Registers legacy Listeners to the Dispatcher, emulating how plugins worked under Joomla! 3.x and below. * @@ -359,4 +400,30 @@ private function parameterImplementsEventInterface(\ReflectionParameter $paramet return false; } + + /** + * Returns the internal application or null when not set. + * + * @return CMSApplicationInterface|null + * + * @since __DEPLOY_VERSION__ + */ + protected function getApplication(): ?CMSApplicationInterface + { + return $this->application; + } + + /** + * Sets the application to use. + * + * @param CMSApplicationInterface $application The application + * + * @return void + * + * @since __DEPLOY_VERSION__ + */ + public function setApplication(CMSApplicationInterface $application): void + { + $this->application = $application; + } } diff --git a/plugins/actionlog/joomla/services/provider.php b/plugins/actionlog/joomla/services/provider.php index c1b3b716b15ff..231349af8eff1 100644 --- a/plugins/actionlog/joomla/services/provider.php +++ b/plugins/actionlog/joomla/services/provider.php @@ -10,6 +10,7 @@ defined('_JEXEC') or die; use Joomla\CMS\Extension\PluginInterface; +use Joomla\CMS\Factory; use Joomla\CMS\Plugin\PluginHelper; use Joomla\Database\DatabaseInterface; use Joomla\DI\Container; @@ -38,6 +39,7 @@ function (Container $container) $container->get(DispatcherInterface::class), (array) PluginHelper::getPlugin('actionlog', 'joomla') ); + $plugin->setApplication(Factory::getApplication()); $plugin->setDatabase($container->get(DatabaseInterface::class)); return $plugin; diff --git a/plugins/actionlog/joomla/src/Extension/Joomla.php b/plugins/actionlog/joomla/src/Extension/Joomla.php index 5545949c5aba5..8aadceee4825b 100644 --- a/plugins/actionlog/joomla/src/Extension/Joomla.php +++ b/plugins/actionlog/joomla/src/Extension/Joomla.php @@ -11,7 +11,6 @@ defined('_JEXEC') or die; -use Joomla\CMS\Application\CMSApplicationInterface; use Joomla\CMS\Component\ComponentHelper; use Joomla\CMS\Factory; use Joomla\CMS\Installer\Installer; @@ -36,14 +35,6 @@ final class Joomla extends ActionLogPlugin { use DatabaseAwareTrait; - /** - * Application object. - * - * @var CMSApplicationInterface - * @since 4.2.0 - */ - protected $app; - /** * Array of loggable extensions. * @@ -144,7 +135,7 @@ public function onContentAfterSave($context, $article, $isNew): void } // If the content type doesn't have its own language key, use default language key - if (!$this->app->getLanguage()->hasKey($messageLanguageKey)) + if (!$this->getApplication()->getLanguage()->hasKey($messageLanguageKey)) { $messageLanguageKey = $defaultLanguageKey; } @@ -176,7 +167,7 @@ public function onContentAfterSave($context, $article, $isNew): void */ public function onContentAfterDelete($context, $article): void { - $option = $this->app->input->get('option'); + $option = $this->getApplication()->input->get('option'); if (!$this->checkLoggable($option)) { @@ -192,7 +183,7 @@ public function onContentAfterDelete($context, $article): void } // If the content type has its own language key, use it, otherwise, use default language key - if ($this->app->getLanguage()->hasKey(strtoupper($params->text_prefix . '_' . $params->type_title . '_DELETED'))) + if ($this->getApplication()->getLanguage()->hasKey(strtoupper($params->text_prefix . '_' . $params->type_title . '_DELETED'))) { $messageLanguageKey = $params->text_prefix . '_' . $params->type_title . '_DELETED'; } @@ -228,7 +219,7 @@ public function onContentAfterDelete($context, $article): void */ public function onContentChangeState($context, $pks, $value) { - $option = $this->app->input->getCmd('option'); + $option = $this->getApplication()->input->getCmd('option'); if (!$this->checkLoggable($option)) { @@ -275,7 +266,7 @@ public function onContentChangeState($context, $pks, $value) } // If the content type doesn't have its own language key, use default language key - if (!$this->app->getLanguage()->hasKey($messageLanguageKey)) + if (!$this->getApplication()->getLanguage()->hasKey($messageLanguageKey)) { $messageLanguageKey = $defaultLanguageKey; } @@ -326,7 +317,7 @@ public function onContentChangeState($context, $pks, $value) */ public function onApplicationAfterSave($config): void { - $option = $this->app->input->getCmd('option'); + $option = $this->getApplication()->input->getCmd('option'); if (!$this->checkLoggable($option)) { @@ -360,7 +351,7 @@ public function onApplicationAfterSave($config): void */ public function onExtensionAfterInstall($installer, $eid) { - $context = $this->app->input->get('option'); + $context = $this->getApplication()->input->get('option'); if (!$this->checkLoggable($context)) { @@ -377,7 +368,7 @@ public function onExtensionAfterInstall($installer, $eid) $extensionType = $manifest->attributes()->type; // If the extension type has its own language key, use it, otherwise, use default language key - if ($this->app->getLanguage()->hasKey(strtoupper('PLG_ACTIONLOG_JOOMLA_' . $extensionType . '_INSTALLED'))) + if ($this->getApplication()->getLanguage()->hasKey(strtoupper('PLG_ACTIONLOG_JOOMLA_' . $extensionType . '_INSTALLED'))) { $messageLanguageKey = 'PLG_ACTIONLOG_JOOMLA_' . $extensionType . '_INSTALLED'; } @@ -412,7 +403,7 @@ public function onExtensionAfterInstall($installer, $eid) */ public function onExtensionAfterUninstall($installer, $eid, $result) { - $context = $this->app->input->get('option'); + $context = $this->getApplication()->input->get('option'); if (!$this->checkLoggable($context)) { @@ -435,7 +426,7 @@ public function onExtensionAfterUninstall($installer, $eid, $result) $extensionType = $manifest->attributes()->type; // If the extension type has its own language key, use it, otherwise, use default language key - if ($this->app->getLanguage()->hasKey(strtoupper('PLG_ACTIONLOG_JOOMLA_' . $extensionType . '_UNINSTALLED'))) + if ($this->getApplication()->getLanguage()->hasKey(strtoupper('PLG_ACTIONLOG_JOOMLA_' . $extensionType . '_UNINSTALLED'))) { $messageLanguageKey = 'PLG_ACTIONLOG_JOOMLA_' . $extensionType . '_UNINSTALLED'; } @@ -469,7 +460,7 @@ public function onExtensionAfterUninstall($installer, $eid, $result) */ public function onExtensionAfterUpdate($installer, $eid) { - $context = $this->app->input->get('option'); + $context = $this->getApplication()->input->get('option'); if (!$this->checkLoggable($context)) { @@ -486,7 +477,7 @@ public function onExtensionAfterUpdate($installer, $eid) $extensionType = $manifest->attributes()->type; // If the extension type has its own language key, use it, otherwise, use default language key - if ($this->app->getLanguage()->hasKey('PLG_ACTIONLOG_JOOMLA_' . $extensionType . '_UPDATED')) + if ($this->getApplication()->getLanguage()->hasKey('PLG_ACTIONLOG_JOOMLA_' . $extensionType . '_UPDATED')) { $messageLanguageKey = 'PLG_ACTIONLOG_JOOMLA_' . $extensionType . '_UPDATED'; } @@ -520,7 +511,7 @@ public function onExtensionAfterUpdate($installer, $eid) */ public function onExtensionAfterSave($context, $table, $isNew): void { - $option = $this->app->input->getCmd('option'); + $option = $this->getApplication()->input->getCmd('option'); if ($table->get('module') != null) { @@ -554,7 +545,7 @@ public function onExtensionAfterSave($context, $table, $isNew): void } // If the extension type doesn't have it own language key, use default language key - if (!$this->app->getLanguage()->hasKey($messageLanguageKey)) + if (!$this->getApplication()->getLanguage()->hasKey($messageLanguageKey)) { $messageLanguageKey = $defaultLanguageKey; } @@ -584,7 +575,7 @@ public function onExtensionAfterSave($context, $table, $isNew): void */ public function onExtensionAfterDelete($context, $table): void { - if (!$this->checkLoggable($this->app->input->get('option'))) + if (!$this->checkLoggable($this->getApplication()->input->get('option'))) { return; } @@ -625,8 +616,8 @@ public function onExtensionAfterDelete($context, $table): void */ public function onUserAfterSave($user, $isnew, $success, $msg): void { - $context = $this->app->input->get('option'); - $task = $this->app->input->post->get('task'); + $context = $this->getApplication()->input->get('option'); + $task = $this->getApplication()->input->post->get('task'); if (!$this->checkLoggable($context)) { @@ -704,7 +695,7 @@ public function onUserAfterSave($user, $isnew, $success, $msg): void */ public function onUserAfterDelete($user, $success, $msg): void { - $context = $this->app->input->get('option'); + $context = $this->getApplication()->input->get('option'); if (!$this->checkLoggable($context)) { @@ -739,7 +730,7 @@ public function onUserAfterDelete($user, $success, $msg): void public function onUserAfterSaveGroup($context, $table, $isNew): void { // Override context (com_users.group) with the component context (com_users) to pass the checkLoggable - $context = $this->app->input->get('option'); + $context = $this->getApplication()->input->get('option'); if (!$this->checkLoggable($context)) { @@ -783,7 +774,7 @@ public function onUserAfterSaveGroup($context, $table, $isNew): void */ public function onUserAfterDeleteGroup($group, $success, $msg): void { - $context = $this->app->input->get('option'); + $context = $this->getApplication()->input->get('option'); if (!$this->checkLoggable($context)) { @@ -833,7 +824,7 @@ public function onUserAfterLogin($options) 'userid' => $loggedInUser->id, 'username' => $loggedInUser->username, 'accountlink' => 'index.php?option=com_users&task=user.edit&id=' . $loggedInUser->id, - 'app' => 'PLG_ACTIONLOG_JOOMLA_APPLICATION_' . $this->app->getName(), + 'app' => 'PLG_ACTIONLOG_JOOMLA_APPLICATION_' . $this->getApplication()->getName(), ); $this->addLog(array($message), $messageLanguageKey, $context, $loggedInUser->id); @@ -889,7 +880,7 @@ public function onUserLoginFailure($response) 'userid' => $loggedInUser->id, 'username' => $loggedInUser->username, 'accountlink' => 'index.php?option=com_users&task=user.edit&id=' . $loggedInUser->id, - 'app' => 'PLG_ACTIONLOG_JOOMLA_APPLICATION_' . $this->app->getName(), + 'app' => 'PLG_ACTIONLOG_JOOMLA_APPLICATION_' . $this->getApplication()->getName(), ); $this->addLog(array($message), $messageLanguageKey, $context, $loggedInUser->id); @@ -929,7 +920,7 @@ public function onUserLogout($user, $options = array()) 'userid' => $loggedOutUser->id, 'username' => $loggedOutUser->username, 'accountlink' => 'index.php?option=com_users&task=user.edit&id=' . $loggedOutUser->id, - 'app' => 'PLG_ACTIONLOG_JOOMLA_APPLICATION_' . $this->app->getName(), + 'app' => 'PLG_ACTIONLOG_JOOMLA_APPLICATION_' . $this->getApplication()->getName(), ); $this->addLog(array($message), $messageLanguageKey, $context); @@ -962,7 +953,7 @@ protected function checkLoggable($extension) */ public function onUserAfterRemind($user) { - $context = $this->app->input->get('option'); + $context = $this->getApplication()->input->get('option'); if (!$this->checkLoggable($context)) { @@ -1032,7 +1023,7 @@ public function onAfterCheckin($table) */ public function onAfterLogPurge($group = '') { - $context = $this->app->input->get('option'); + $context = $this->getApplication()->input->get('option'); $user = Factory::getUser(); $message = array( 'action' => 'actionlogs', @@ -1060,7 +1051,7 @@ public function onAfterLogPurge($group = '') */ public function onAfterLogExport($group = '') { - $context = $this->app->input->get('option'); + $context = $this->getApplication()->input->get('option'); $user = Factory::getUser(); $message = array( 'action' => 'actionlogs', @@ -1088,7 +1079,7 @@ public function onAfterLogExport($group = '') */ public function onAfterPurge($group = 'all') { - $context = $this->app->input->get('option'); + $context = $this->getApplication()->input->get('option'); $user = Factory::getUser(); if (!$this->checkLoggable($context)) @@ -1121,7 +1112,7 @@ public function onAfterPurge($group = 'all') */ public function onAfterDispatch() { - if (!$this->app->isClient('api')) + if (!$this->getApplication()->isClient('api')) { return; } @@ -1131,27 +1122,27 @@ public function onAfterDispatch() return; } - $verb = $this->app->input->getMethod(); + $verb = $this->getApplication()->input->getMethod(); if (!in_array($verb, $this->loggableVerbs)) { return; } - $context = $this->app->input->get('option'); + $context = $this->getApplication()->input->get('option'); if (!$this->checkLoggable($context)) { return; } - $user = $this->app->getIdentity(); + $user = $this->getApplication()->getIdentity(); $message = array( 'action' => 'API', 'verb' => $verb, 'username' => $user->username, 'accountlink' => 'index.php?option=com_users&task=user.edit&id=' . $user->id, - 'url' => htmlspecialchars(urldecode($this->app->get('uri.route')), ENT_QUOTES, 'UTF-8'), + 'url' => htmlspecialchars(urldecode($this->getApplication()->get('uri.route')), ENT_QUOTES, 'UTF-8'), ); $this->addLog(array($message), 'PLG_ACTIONLOG_JOOMLA_API', $context, $user->id); } @@ -1169,12 +1160,12 @@ public function onAfterDispatch() */ public function onJoomlaAfterUpdate($oldVersion = null) { - $context = $this->app->input->get('option'); + $context = $this->getApplication()->input->get('option'); $user = Factory::getUser(); if (empty($oldVersion)) { - $oldVersion = $this->app->getLanguage()->_('JLIB_UNKNOWN'); + $oldVersion = $this->getApplication()->getLanguage()->_('JLIB_UNKNOWN'); } $message = array( @@ -1203,7 +1194,7 @@ public function onJoomlaAfterUpdate($oldVersion = null) */ private function getActionLogParams($context): ?stdClass { - $component = $this->app->bootComponent('actionlogs'); + $component = $this->getApplication()->bootComponent('actionlogs'); if (!$component instanceof MVCFactoryServiceInterface) { diff --git a/plugins/api-authentication/basic/services/provider.php b/plugins/api-authentication/basic/services/provider.php index 93551f1ecfc70..750203eb57e4d 100644 --- a/plugins/api-authentication/basic/services/provider.php +++ b/plugins/api-authentication/basic/services/provider.php @@ -10,6 +10,7 @@ defined('_JEXEC') or die; use Joomla\CMS\Extension\PluginInterface; +use Joomla\CMS\Factory; use Joomla\CMS\Plugin\PluginHelper; use Joomla\CMS\User\UserFactoryInterface; use Joomla\Database\DatabaseInterface; @@ -40,6 +41,7 @@ function (Container $container) (array) PluginHelper::getPlugin('api-authentication', 'basic'), $container->get(UserFactoryInterface::class) ); + $plugin->setApplication(Factory::getApplication()); $plugin->setDatabase($container->get(DatabaseInterface::class)); return $plugin; diff --git a/plugins/api-authentication/basic/src/Extension/Basic.php b/plugins/api-authentication/basic/src/Extension/Basic.php index afed7bd380c7a..96cfc74ebdc53 100644 --- a/plugins/api-authentication/basic/src/Extension/Basic.php +++ b/plugins/api-authentication/basic/src/Extension/Basic.php @@ -11,7 +11,6 @@ defined('_JEXEC') or die; -use Joomla\CMS\Application\CMSApplicationInterface; use Joomla\CMS\Authentication\Authentication; use Joomla\CMS\Plugin\CMSPlugin; use Joomla\CMS\User\UserFactoryInterface; @@ -28,14 +27,6 @@ final class Basic extends CMSPlugin { use DatabaseAwareTrait; - /** - * The application object - * - * @var CMSApplicationInterface - * @since 4.0.0 - */ - protected $app; - /** * The user factory * @@ -75,13 +66,13 @@ public function onUserAuthenticate($credentials, $options, &$response) { $response->type = 'Basic'; - $username = $this->app->input->server->get('PHP_AUTH_USER', '', 'USERNAME'); - $password = $this->app->input->server->get('PHP_AUTH_PW', '', 'RAW'); + $username = $this->getApplication()->input->server->get('PHP_AUTH_USER', '', 'USERNAME'); + $password = $this->getApplication()->input->server->get('PHP_AUTH_PW', '', 'RAW'); if ($password === '') { $response->status = Authentication::STATUS_FAILURE; - $response->error_message = $this->app->getLanguage()->_('JGLOBAL_AUTH_EMPTY_PASS_NOT_ALLOWED'); + $response->error_message = $this->translate('JGLOBAL_AUTH_EMPTY_PASS_NOT_ALLOWED'); return; } @@ -108,7 +99,7 @@ public function onUserAuthenticate($credentials, $options, &$response) $response->fullname = $user->name; $response->username = $username; - if ($this->app->isClient('administrator')) + if ($this->getApplication()->isClient('administrator')) { $response->language = $user->getParam('admin_language'); } @@ -125,7 +116,7 @@ public function onUserAuthenticate($credentials, $options, &$response) { // Invalid password $response->status = Authentication::STATUS_FAILURE; - $response->error_message = $this->app->getLanguage()->_('JGLOBAL_AUTH_INVALID_PASS'); + $response->error_message = $this->translate('JGLOBAL_AUTH_INVALID_PASS'); } } else @@ -136,7 +127,7 @@ public function onUserAuthenticate($credentials, $options, &$response) // Invalid user $response->status = Authentication::STATUS_FAILURE; - $response->error_message = $this->app->getLanguage()->_('JGLOBAL_AUTH_NO_USER'); + $response->error_message = $this->translate('JGLOBAL_AUTH_NO_USER'); } } } diff --git a/plugins/api-authentication/token/services/provider.php b/plugins/api-authentication/token/services/provider.php index 11efa5d5f29d3..6826d305b65f8 100644 --- a/plugins/api-authentication/token/services/provider.php +++ b/plugins/api-authentication/token/services/provider.php @@ -10,6 +10,7 @@ defined('_JEXEC') or die; use Joomla\CMS\Extension\PluginInterface; +use Joomla\CMS\Factory; use Joomla\CMS\Plugin\PluginHelper; use Joomla\CMS\User\UserFactoryInterface; use Joomla\Database\DatabaseInterface; @@ -42,6 +43,7 @@ function (Container $container) $container->get(UserFactoryInterface::class), new InputFilter ); + $plugin->setApplication(Factory::getApplication()); $plugin->setDatabase($container->get(DatabaseInterface::class)); return $plugin; diff --git a/plugins/api-authentication/token/src/Extension/Token.php b/plugins/api-authentication/token/src/Extension/Token.php index 63ab2c8203b4d..e268e2eb21ed7 100644 --- a/plugins/api-authentication/token/src/Extension/Token.php +++ b/plugins/api-authentication/token/src/Extension/Token.php @@ -11,7 +11,6 @@ defined('_JEXEC') or die; -use Joomla\CMS\Application\ApiApplication; use Joomla\CMS\Authentication\Authentication; use Joomla\CMS\Crypt\Crypt; use Joomla\CMS\Plugin\CMSPlugin; @@ -31,14 +30,6 @@ final class Token extends CMSPlugin { use DatabaseAwareTrait; - /** - * The application object - * - * @var CMSApplicationInterface - * @since 4.0.0 - */ - protected $app; - /** * The prefix of the user profile keys, without the dot. * @@ -105,7 +96,7 @@ public function onUserAuthenticate($credentials, $options, &$response): void // Default response is authentication failure. $response->type = 'Token'; $response->status = Authentication::STATUS_FAILURE; - $response->error_message = $this->app->getLanguage()->_('JGLOBAL_AUTH_FAIL'); + $response->error_message = $this->translate('JGLOBAL_AUTH_FAIL'); /** * First look for an HTTP Authorization header with the following format: @@ -113,7 +104,7 @@ public function onUserAuthenticate($credentials, $options, &$response): void * Do keep in mind that Bearer is **case-sensitive**. Whitespace between Bearer and the * token, as well as any whitespace following the token is discarded. */ - $authHeader = $this->app->input->server->get('HTTP_AUTHORIZATION', '', 'string'); + $authHeader = $this->getApplication()->input->server->get('HTTP_AUTHORIZATION', '', 'string'); $tokenString = ''; // Apache specific fixes. See https://github.com/symfony/symfony/issues/19693 @@ -137,7 +128,7 @@ public function onUserAuthenticate($credentials, $options, &$response): void if (empty($tokenString)) { - $tokenString = $this->app->input->server->get('HTTP_X_JOOMLA_TOKEN', '', 'string'); + $tokenString = $this->getApplication()->input->server->get('HTTP_X_JOOMLA_TOKEN', '', 'string'); } // No token: authentication failure @@ -182,7 +173,7 @@ public function onUserAuthenticate($credentials, $options, &$response): void */ try { - $siteSecret = $this->app->get('secret'); + $siteSecret = $this->getApplication()->get('secret'); } catch (\Exception $e) { @@ -343,7 +334,8 @@ private function isTokenEnabledForUser(int $userId): bool private function getPluginParameter(string $folder, string $plugin, string $param, $default = null) { /** @var PluginModel $model */ - $model = $this->app->bootComponent('plugins')->getMVCFactory()->createModel('Plugin', 'Administrator', ['ignore_request' => true]); + $model = $this->getApplication()->bootComponent('plugins') + ->getMVCFactory()->createModel('Plugin', 'Administrator', ['ignore_request' => true]); $pluginObject = $model->getItem(['folder' => $folder, 'element' => $plugin]); diff --git a/plugins/behaviour/versionable/services/provider.php b/plugins/behaviour/versionable/services/provider.php index 621d7650b4591..36a84b8ae7902 100644 --- a/plugins/behaviour/versionable/services/provider.php +++ b/plugins/behaviour/versionable/services/provider.php @@ -10,6 +10,7 @@ defined('_JEXEC') or die; use Joomla\CMS\Extension\PluginInterface; +use Joomla\CMS\Factory; use Joomla\CMS\Helper\CMSHelper; use Joomla\CMS\Plugin\PluginHelper; use Joomla\DI\Container; @@ -42,6 +43,7 @@ function (Container $container) new InputFilter, new CMSHelper ); + $plugin->setApplication(Factory::getApplication()); return $plugin; } diff --git a/plugins/behaviour/versionable/src/Extension/Versionable.php b/plugins/behaviour/versionable/src/Extension/Versionable.php index 990d96bbae401..7cb6d41d5312e 100644 --- a/plugins/behaviour/versionable/src/Extension/Versionable.php +++ b/plugins/behaviour/versionable/src/Extension/Versionable.php @@ -11,7 +11,6 @@ defined('_JEXEC') or die; -use Joomla\CMS\Application\CMSApplicationInterface; use Joomla\CMS\Component\ComponentHelper; use Joomla\CMS\Event\Table\AfterStoreEvent; use Joomla\CMS\Event\Table\BeforeDeleteEvent; @@ -47,14 +46,6 @@ public static function getSubscribedEvents(): array ]; } - /** - * The application object - * - * @var CMSApplicationInterface - * @since __DEPLOY_VERSION__ - */ - protected $app; - /** * The input filter * @@ -126,7 +117,7 @@ public function onTableAfterStore(AfterStoreEvent $event) $id = $table->getId(); $data = $this->helper->getDataObject($table); - $input = $this->app->input; + $input = $this->getApplication()->input; $jform = $input->get('jform', array(), 'array'); $versionNote = ''; diff --git a/plugins/multifactorauth/email/services/provider.php b/plugins/multifactorauth/email/services/provider.php index a4417d8122f7b..480381df74d63 100644 --- a/plugins/multifactorauth/email/services/provider.php +++ b/plugins/multifactorauth/email/services/provider.php @@ -10,6 +10,7 @@ defined('_JEXEC') || die; use Joomla\CMS\Extension\PluginInterface; +use Joomla\CMS\Factory; use Joomla\CMS\Plugin\PluginHelper; use Joomla\DI\Container; use Joomla\DI\ServiceProviderInterface; @@ -35,7 +36,10 @@ function (Container $container) { $config = (array) PluginHelper::getPlugin('multifactorauth', 'email'); $subject = $container->get(DispatcherInterface::class); - return new Email($subject, $config); + $plugin = new Email($subject, $config); + $plugin->setApplication(Factory::getApplication()); + + return $plugin; } ); } diff --git a/plugins/multifactorauth/email/src/Extension/Email.php b/plugins/multifactorauth/email/src/Extension/Email.php index 95e3cc3d561e7..61dba2373b0c1 100644 --- a/plugins/multifactorauth/email/src/Extension/Email.php +++ b/plugins/multifactorauth/email/src/Extension/Email.php @@ -10,7 +10,6 @@ namespace Joomla\Plugin\Multifactorauth\Email\Extension; use Exception; -use Joomla\CMS\Application\CMSApplication; use Joomla\CMS\Encrypt\Totp; use Joomla\CMS\Event\MultiFactor\BeforeDisplayMethods; use Joomla\CMS\Event\MultiFactor\Captive; @@ -63,14 +62,6 @@ class Email extends CMSPlugin implements SubscriberInterface */ private const SECRET_KEY_LENGTH = 20; - /** - * The CMS application we are running under - * - * @var CMSApplication - * @since 4.2.0 - */ - protected $app; - /** * Forbid registration of legacy (Joomla 3) event listeners. * @@ -235,7 +226,7 @@ public function onUserMultifactorGetSetup(GetSetup $event): void $isKeyAlreadySetup = !empty($key); // If there's a key in the session use that instead. - $session = $this->app->getSession(); + $session = $this->getApplication()->getSession(); $session->get('plg_multifactorauth_email.emailcode.key', $key); // Initialize objects @@ -320,7 +311,7 @@ public function onUserMultifactorSaveSetup(SaveSetup $event): void $options = $this->decodeRecordOptions($record); $key = $options['key'] ?? ''; $isKeyAlreadySetup = !empty($key); - $session = $this->app->getSession(); + $session = $this->getApplication()->getSession(); // If there is no key in the options fetch one from the session if (empty($key)) @@ -479,7 +470,7 @@ function (MfaTable $record) try { /** @var MVCFactoryInterface $factory */ - $factory = $this->app->bootComponent('com_users')->getMVCFactory(); + $factory = $this->getApplication()->bootComponent('com_users')->getMVCFactory(); /** @var MfaTable $record */ $record = $factory->createTable('Mfa', 'Administrator'); $record->reset(); @@ -546,7 +537,7 @@ private function sendCode(string $key, ?User $user = null) // Make sure we have a user if (!is_object($user) || !($user instanceof User)) { - $user = $this->app->getIdentity() + $user = $this->getApplication()->getIdentity() ?: Factory::getContainer()->get(UserFactoryInterface::class)->loadUserById(0); } @@ -566,7 +557,7 @@ private function sendCode(string $key, ?User $user = null) $replacements = [ 'code' => $code, - 'sitename' => $this->app->get('sitename'), + 'sitename' => $this->getApplication()->get('sitename'), 'siteurl' => Uri::base(), 'username' => $user->username, 'email' => $user->email, @@ -575,7 +566,7 @@ private function sendCode(string $key, ?User $user = null) try { - $jLanguage = $this->app->getLanguage(); + $jLanguage = $this->getApplication()->getLanguage(); $mailer = new MailTemplate('plg_multifactorauth_email.mail', $jLanguage->getTag()); $mailer->addRecipient($user->email, $user->name); $mailer->addTemplateData($replacements); @@ -590,7 +581,7 @@ private function sendCode(string $key, ?User $user = null) } catch (RuntimeException $exception) { - $this->app->enqueueMessage(Text::_($exception->errorMessage()), 'warning'); + $this->getApplication()->enqueueMessage(Text::_($exception->errorMessage()), 'warning'); } } @@ -624,7 +615,7 @@ private function sendCode(string $key, ?User $user = null) } catch (RuntimeException $exception) { - $this->app->enqueueMessage(Text::_($exception->errorMessage()), 'warning'); + $this->getApplication()->enqueueMessage(Text::_($exception->errorMessage()), 'warning'); } } } diff --git a/plugins/multifactorauth/fixed/src/Extension/Fixed.php b/plugins/multifactorauth/fixed/src/Extension/Fixed.php index 0d9b9953dafb4..51e88928743bf 100644 --- a/plugins/multifactorauth/fixed/src/Extension/Fixed.php +++ b/plugins/multifactorauth/fixed/src/Extension/Fixed.php @@ -9,7 +9,6 @@ namespace Joomla\Plugin\Multifactorauth\Fixed\Extension; -use Joomla\CMS\Application\CMSApplication; use Joomla\CMS\Event\MultiFactor\Captive; use Joomla\CMS\Event\MultiFactor\GetMethod; use Joomla\CMS\Event\MultiFactor\GetSetup; @@ -39,14 +38,6 @@ */ class Fixed extends CMSPlugin implements SubscriberInterface { - /** - * The application we are running under. - * - * @var CMSApplication - * @since 4.2.0 - */ - protected $app; - /** * Affects constructor behavior. If true, language files will be loaded automatically. * diff --git a/plugins/multifactorauth/totp/services/provider.php b/plugins/multifactorauth/totp/services/provider.php index 5c681609f05d2..4c74f9f94cf41 100644 --- a/plugins/multifactorauth/totp/services/provider.php +++ b/plugins/multifactorauth/totp/services/provider.php @@ -10,6 +10,7 @@ defined('_JEXEC') || die; use Joomla\CMS\Extension\PluginInterface; +use Joomla\CMS\Factory; use Joomla\CMS\Plugin\PluginHelper; use Joomla\DI\Container; use Joomla\DI\ServiceProviderInterface; @@ -35,7 +36,10 @@ function (Container $container) { $config = (array) PluginHelper::getPlugin('multifactorauth', 'totp'); $subject = $container->get(DispatcherInterface::class); - return new Totp($subject, $config); + $plugin = new Totp($subject, $config); + $plugin->setApplication(Factory::getApplication()); + + return $plugin; } ); } diff --git a/plugins/multifactorauth/totp/src/Extension/Totp.php b/plugins/multifactorauth/totp/src/Extension/Totp.php index 4706a8ee3489e..1b08901e71c6a 100644 --- a/plugins/multifactorauth/totp/src/Extension/Totp.php +++ b/plugins/multifactorauth/totp/src/Extension/Totp.php @@ -9,7 +9,6 @@ namespace Joomla\Plugin\Multifactorauth\Totp\Extension; -use Joomla\CMS\Application\CMSApplication; use Joomla\CMS\Encrypt\Totp as TotpHelper; use Joomla\CMS\Event\MultiFactor\Captive; use Joomla\CMS\Event\MultiFactor\GetMethod; @@ -37,14 +36,6 @@ */ class Totp extends CMSPlugin implements SubscriberInterface { - /** - * The application we are running under. - * - * @var CMSApplication - * @since 4.2.0 - */ - protected $app; - /** * Affects constructor behavior. If true, language files will be loaded automatically. * @@ -187,7 +178,7 @@ public function onUserMultifactorGetSetup(GetSetup $event): void // Load the options from the record (if any) $options = $this->decodeRecordOptions($record); $key = $options['key'] ?? ''; - $session = $this->app->getSession(); + $session = $this->getApplication()->getSession(); $isConfigured = !empty($key); // If there's a key in the session use that instead. @@ -210,7 +201,7 @@ public function onUserMultifactorGetSetup(GetSetup $event): void $user = Factory::getContainer()->get(UserFactoryInterface::class)->loadUserById($record->user_id); $hostname = Uri::getInstance()->toString(['host']); $otpURL = sprintf("otpauth://totp/%s@%s?secret=%s", $user->username, $hostname, $key); - $document = $this->app->getDocument(); + $document = $this->getApplication()->getDocument(); $wam = $document->getWebAssetManager(); $document->addScriptOptions('plg_multifactorauth_totp.totp.qr', $otpURL); @@ -277,7 +268,7 @@ public function onUserMultifactorSaveSetup(SaveSetup $event): void $options = $this->decodeRecordOptions($record); $optionsKey = $options['key'] ?? ''; $key = $optionsKey; - $session = $this->app->getSession(); + $session = $this->getApplication()->getSession(); // If there is no key in the options fetch one from the session if (empty($key)) diff --git a/plugins/multifactorauth/webauthn/services/provider.php b/plugins/multifactorauth/webauthn/services/provider.php index f639252976259..079bfebacde8e 100644 --- a/plugins/multifactorauth/webauthn/services/provider.php +++ b/plugins/multifactorauth/webauthn/services/provider.php @@ -10,6 +10,7 @@ defined('_JEXEC') || die; use Joomla\CMS\Extension\PluginInterface; +use Joomla\CMS\Factory; use Joomla\CMS\Plugin\PluginHelper; use Joomla\DI\Container; use Joomla\DI\ServiceProviderInterface; @@ -35,7 +36,10 @@ function (Container $container) { $config = (array) PluginHelper::getPlugin('multifactorauth', 'webauthn'); $subject = $container->get(DispatcherInterface::class); - return new Webauthn($subject, $config); + $plugin = new Webauthn($subject, $config); + $plugin->setApplication(Factory::getApplication()); + + return $plugin; } ); } diff --git a/plugins/multifactorauth/webauthn/src/Extension/Webauthn.php b/plugins/multifactorauth/webauthn/src/Extension/Webauthn.php index 9c381a3ccc935..5368078c27ec8 100644 --- a/plugins/multifactorauth/webauthn/src/Extension/Webauthn.php +++ b/plugins/multifactorauth/webauthn/src/Extension/Webauthn.php @@ -10,9 +10,7 @@ namespace Joomla\Plugin\Multifactorauth\Webauthn\Extension; use Exception; -use Joomla\CMS\Application\AdministratorApplication; use Joomla\CMS\Application\CMSApplication; -use Joomla\CMS\Application\SiteApplication; use Joomla\CMS\Event\MultiFactor\Captive; use Joomla\CMS\Event\MultiFactor\GetMethod; use Joomla\CMS\Event\MultiFactor\GetSetup; @@ -42,14 +40,6 @@ */ class Webauthn extends CMSPlugin implements SubscriberInterface { - /** - * The application object - * - * @var CMSApplication|SiteApplication|AdministratorApplication - * @since 4.2.0 - */ - protected $app; - /** * Auto-load the plugin's language files * @@ -147,7 +137,7 @@ public function onUserMultifactorGetSetup(GetSetup $event): void */ if (!is_array($record->options) || empty($record->options['credentialId'] ?? '')) { - $document = $this->app->getDocument(); + $document = $this->getApplication()->getDocument(); $wam = $document->getWebAssetManager(); $wam->getRegistry()->addExtensionRegistryFile('plg_multifactorauth_webauthn'); @@ -232,7 +222,7 @@ public function onUserMultifactorSaveSetup(SaveSetup $event): void } $code = $input->get('code', null, 'base64'); - $session = $this->app->getSession(); + $session = $this->getApplication()->getSession(); $registrationRequest = $session->get('plg_multifactorauth_webauthn.publicKeyCredentialCreationOptions', null); // If there was no registration request BUT there is a registration response throw an error @@ -328,10 +318,10 @@ public function onUserMultifactorCaptive(Captive $event): void * That was fun to debug - for "poke your eyes with a rusty fork" values of fun. */ - $session = $this->app->getSession(); + $session = $this->getApplication()->getSession(); $pkOptionsEncoded = $session->get('plg_multifactorauth_webauthn.publicKeyCredentialRequestOptions', null); - $force = $this->app->input->getInt('force', 0); + $force = $this->getApplication()->input->getInt('force', 0); try { @@ -361,7 +351,7 @@ public function onUserMultifactorCaptive(Captive $event): void $pkRequest = Credentials::requestAssertion($record->user_id); } - $document = $this->app->getDocument(); + $document = $this->getApplication()->getDocument(); $wam = $document->getWebAssetManager(); $wam->getRegistry()->addExtensionRegistryFile('plg_multifactorauth_webauthn'); @@ -461,7 +451,7 @@ public function onUserMultifactorValidate(Validate $event): void { try { - $this->app->enqueueMessage($e->getMessage(), 'error'); + $this->getApplication()->enqueueMessage($e->getMessage(), 'error'); } catch (Exception $e) { diff --git a/plugins/multifactorauth/yubikey/services/provider.php b/plugins/multifactorauth/yubikey/services/provider.php index 7afd9aea77d64..6fe291868d01b 100644 --- a/plugins/multifactorauth/yubikey/services/provider.php +++ b/plugins/multifactorauth/yubikey/services/provider.php @@ -10,6 +10,7 @@ defined('_JEXEC') || die; use Joomla\CMS\Extension\PluginInterface; +use Joomla\CMS\Factory; use Joomla\CMS\Plugin\PluginHelper; use Joomla\DI\Container; use Joomla\DI\ServiceProviderInterface; @@ -35,7 +36,10 @@ function (Container $container) { $config = (array) PluginHelper::getPlugin('multifactorauth', 'yubikey'); $subject = $container->get(DispatcherInterface::class); - return new Yubikey($subject, $config); + $plugin = new Yubikey($subject, $config); + $plugin->setApplication(Factory::getApplication()); + + return $plugin; } ); } diff --git a/plugins/multifactorauth/yubikey/src/Extension/Yubikey.php b/plugins/multifactorauth/yubikey/src/Extension/Yubikey.php index 57f40108dfeef..4ec29787e1794 100644 --- a/plugins/multifactorauth/yubikey/src/Extension/Yubikey.php +++ b/plugins/multifactorauth/yubikey/src/Extension/Yubikey.php @@ -10,7 +10,6 @@ namespace Joomla\Plugin\Multifactorauth\Yubikey\Extension; use Exception; -use Joomla\CMS\Application\CMSApplication; use Joomla\CMS\Event\MultiFactor\Captive; use Joomla\CMS\Event\MultiFactor\GetMethod; use Joomla\CMS\Event\MultiFactor\GetSetup; @@ -37,14 +36,6 @@ */ class Yubikey extends CMSPlugin implements SubscriberInterface { - /** - * The application we are running under. - * - * @var CMSApplication - * @since 4.2.0 - */ - protected $app; - /** * Affects constructor behavior. If true, language files will be loaded automatically. * @@ -386,7 +377,7 @@ private function validateYubikeyOtp(string $otp): bool $gotResponse = false; $http = HttpFactory::getHttp(); - $token = $this->app->getFormToken(); + $token = $this->getApplication()->getFormToken(); $nonce = md5($token . uniqid(random_int(0, mt_getrandmax()))); $response = null; diff --git a/plugins/quickicon/joomlaupdate/services/provider.php b/plugins/quickicon/joomlaupdate/services/provider.php index f47fd38a017e9..59a075a192bf1 100644 --- a/plugins/quickicon/joomlaupdate/services/provider.php +++ b/plugins/quickicon/joomlaupdate/services/provider.php @@ -36,11 +36,14 @@ function (Container $container) // @Todo This needs to be changed to a proper factory $plugin = \Joomla\CMS\Plugin\PluginHelper::getPlugin('quickicon', 'joomlaupdate'); - return new Joomlaupdate( + $plugin = new Joomlaupdate( $container->get(DispatcherInterface::class), Factory::getApplication()->getDocument(), (array) $plugin ); + $plugin->setApplication(Factory::getApplication()); + + return $plugin; } ); } diff --git a/plugins/quickicon/joomlaupdate/src/Extension/Joomlaupdate.php b/plugins/quickicon/joomlaupdate/src/Extension/Joomlaupdate.php index eab04cdf218c0..381489cb0b27a 100644 --- a/plugins/quickicon/joomlaupdate/src/Extension/Joomlaupdate.php +++ b/plugins/quickicon/joomlaupdate/src/Extension/Joomlaupdate.php @@ -12,7 +12,6 @@ \defined('_JEXEC') or die; use Joomla\CMS\Document\Document; -use Joomla\CMS\Extension\ExtensionHelper; use Joomla\CMS\Language\Text; use Joomla\CMS\Plugin\CMSPlugin; use Joomla\CMS\Session\Session; @@ -36,14 +35,6 @@ class Joomlaupdate extends CMSPlugin implements SubscriberInterface */ protected $autoloadLanguage = true; - /** - * Application object. - * - * @var \Joomla\CMS\Application\CMSApplication - * @since 3.7.0 - */ - protected $app; - /** * The document. * @@ -101,7 +92,7 @@ public function getCoreUpdateNotification(QuickIconsEvent $event) $context = $event->getContext(); if ($context !== $this->params->get('context', 'update_quickicon') - || !$this->app->getIdentity()->authorise('core.manage', 'com_joomlaupdate')) + || !$this->getApplication()->getIdentity()->authorise('core.manage', 'com_joomlaupdate')) { return; } diff --git a/plugins/system/cache/services/provider.php b/plugins/system/cache/services/provider.php index 4d918b06b2e39..aad575e576d10 100644 --- a/plugins/system/cache/services/provider.php +++ b/plugins/system/cache/services/provider.php @@ -11,6 +11,7 @@ use Joomla\CMS\Cache\CacheControllerFactoryInterface; use Joomla\CMS\Extension\PluginInterface; +use Joomla\CMS\Factory; use Joomla\CMS\Plugin\PluginHelper; use Joomla\CMS\Profiler\Profiler; use Joomla\CMS\Router\SiteRouter; @@ -42,7 +43,10 @@ function (Container $container) $profiler = (defined('JDEBUG') && JDEBUG) ? Profiler::getInstance('Application') : null; $router = $container->has(SiteRouter::class) ? $container->get(SiteRouter::class) : null; - return new Cache($dispatcher, (array) $plugin, $documentFactory, $cacheControllerFactory, $profiler, $router); + $plugin = new Cache($dispatcher, (array) $plugin, $documentFactory, $cacheControllerFactory, $profiler, $router); + $plugin->setApplication(Factory::getApplication()); + + return $plugin; } ); } diff --git a/plugins/system/cache/src/Extension/Cache.php b/plugins/system/cache/src/Extension/Cache.php index 0a78beda68cd0..689af89340265 100644 --- a/plugins/system/cache/src/Extension/Cache.php +++ b/plugins/system/cache/src/Extension/Cache.php @@ -33,14 +33,6 @@ */ final class Cache extends CMSPlugin implements SubscriberInterface { - /** - * Application object. - * - * @var CMSApplication - * @since 3.8.0 - */ - protected $app; - /** * Cache instance. * @@ -159,7 +151,7 @@ public function onAfterRoute(Event $event) // If any `pagecache` plugins return false for onPageCacheSetCaching, do not use the cache. PluginHelper::importPlugin('pagecache'); - $results = $this->app->triggerEvent('onPageCacheSetCaching'); + $results = $this->getApplication()->triggerEvent('onPageCacheSetCaching'); $this->getCacheController()->setCaching(!in_array(false, $results, true)); @@ -172,28 +164,28 @@ public function onAfterRoute(Event $event) } // Set the page content from the cache and output it to the browser. - $this->app->setBody($data); + $this->getApplication()->setBody($data); - echo $this->app->toString((bool) $this->app->get('gzip')); + echo $this->getApplication()->toString((bool) $this->getApplication()->get('gzip')); // Mark afterCache in debug and run debug onAfterRespond events, e.g. show Joomla Debug Console if debug is active. if (JDEBUG) { // Create a document instance and load it into the application. $document = $this->documentFactory - ->createDocument($this->app->input->get('format', 'html')); - $this->app->loadDocument($document); + ->createDocument($this->getApplication()->input->get('format', 'html')); + $this->getApplication()->loadDocument($document); if ($this->profiler) { $this->profiler->mark('afterCache'); } - $this->app->triggerEvent('onAfterRespond'); + $this->getApplication()->triggerEvent('onAfterRespond'); } // Closes the application. - $this->app->close(); + $this->getApplication()->close(); } /** @@ -222,16 +214,15 @@ private function appStateSupportsCaching(): bool if ($isSite === null) { - $isSite = ($this->app instanceof CMSApplicationInterface) - && $this->app->isClient('site'); - $isGET = $this->app->input->getMethod() === 'GET'; + $isSite = $this->getApplication()->isClient('site'); + $isGET = $this->getApplication()->input->getMethod() === 'GET'; } // Boolean short–circuit evaluation means this returns fast false when $isSite is false. return $isSite && $isGET - && $this->app->getIdentity()->guest - && empty($this->app->getMessageQueue()); + && $this->getApplication()->getIdentity()->guest + && empty($this->getApplication()->getMessageQueue()); } /** @@ -275,7 +266,7 @@ private function getCacheKey(): string { PluginHelper::importPlugin('pagecache'); - $parts = $this->app->triggerEvent('onPageCacheGetKey'); + $parts = $this->getApplication()->triggerEvent('onPageCacheGetKey'); $parts[] = Uri::getInstance()->toString(); $key = md5(serialize($parts)); @@ -308,7 +299,7 @@ public function onAfterRender(Event $event) } // Disable compression before caching the page. - $this->app->set('gzip', false); + $this->getApplication()->set('gzip', false); } /** @@ -326,7 +317,7 @@ private function isExcluded(): bool if ($excludedMenuItems) { // Get the current menu item. - $active = $this->app->getMenu()->getActive(); + $active = $this->getApplication()->getMenu()->getActive(); if ($active && $active->id && in_array((int) $active->id, (array) $excludedMenuItems)) { @@ -373,7 +364,7 @@ private function isExcluded(): bool // If any pagecache plugins return true for onPageCacheIsExcluded, exclude. PluginHelper::importPlugin('pagecache'); - $results = $this->app->triggerEvent('onPageCacheIsExcluded'); + $results = $this->getApplication()->triggerEvent('onPageCacheIsExcluded'); return in_array(true, $results, true); } @@ -395,6 +386,6 @@ public function onAfterRespond(Event $event) } // Saves current page in cache. - $this->getCacheController()->store($this->app->getBody(), $this->getCacheKey()); + $this->getCacheController()->store($this->getApplication()->getBody(), $this->getCacheKey()); } } diff --git a/plugins/task/requests/services/provider.php b/plugins/task/requests/services/provider.php index f6600db7c022d..b7320429f62bc 100644 --- a/plugins/task/requests/services/provider.php +++ b/plugins/task/requests/services/provider.php @@ -10,6 +10,7 @@ defined('_JEXEC') or die; use Joomla\CMS\Extension\PluginInterface; +use Joomla\CMS\Factory; use Joomla\CMS\Plugin\PluginHelper; use Joomla\DI\Container; use Joomla\DI\ServiceProviderInterface; @@ -37,8 +38,10 @@ function (Container $container) $plugin = new Requests( $container->get(DispatcherInterface::class), (array) PluginHelper::getPlugin('task', 'requests'), - new HttpFactory + new HttpFactory, + JPATH_ROOT . '/tmp' ); + $plugin->setApplication(Factory::getApplication()); return $plugin; } diff --git a/plugins/task/requests/src/Extension/Requests.php b/plugins/task/requests/src/Extension/Requests.php index 98fe7f53ab3cf..96cac4e98a7a4 100644 --- a/plugins/task/requests/src/Extension/Requests.php +++ b/plugins/task/requests/src/Extension/Requests.php @@ -29,7 +29,7 @@ * * @since 4.1.0 */ -class Requests extends CMSPlugin implements SubscriberInterface +final class Requests extends CMSPlugin implements SubscriberInterface { use TaskPluginTrait; @@ -68,35 +68,37 @@ public static function getSubscribedEvents(): array protected $autoloadLanguage = true; /** - * The application object + * The http factory * - * @var CMSApplicationInterface + * @var HttpFactory * @since __DEPLOY_VERSION__ */ - protected $app; + private $httpFactory; /** - * The http factory + * The root directory * - * @var HttpFactory + * @var string * @since __DEPLOY_VERSION__ */ - private $httpFactory; + private $rootDirectory; /** * Constructor. * - * @param DispatcherInterface $dispatcher The dispatcher - * @param array $config An optional associative array of configuration settings - * @param HttpFactory $httpFactory The http factory + * @param DispatcherInterface $dispatcher The dispatcher + * @param array $config An optional associative array of configuration settings + * @param HttpFactory $httpFactory The http factory + * @param string $rootDirectory The root directory to store the output file in * * @since __DEPLOY_VERSION__ */ - public function __construct(DispatcherInterface $dispatcher, array $config, HttpFactory $httpFactory) + public function __construct(DispatcherInterface $dispatcher, array $config, HttpFactory $httpFactory, string $rootDirectory) { parent::__construct($dispatcher, $config); - $this->httpFactory = $httpFactory; + $this->httpFactory = $httpFactory; + $this->rootDirectory = $rootDirectory; } /** @@ -132,7 +134,7 @@ protected function makeGetRequest(ExecuteTaskEvent $event): int } catch (Exception $e) { - $this->logTask($this->app->getLanguage()->_('PLG_TASK_REQUESTS_TASK_GET_REQUEST_LOG_TIMEOUT')); + $this->logTask($this->translate('PLG_TASK_REQUESTS_TASK_GET_REQUEST_LOG_TIMEOUT')); return TaskStatus::TIMEOUT; } @@ -141,16 +143,17 @@ protected function makeGetRequest(ExecuteTaskEvent $event): int $responseBody = $response->body; // @todo this handling must be rethought and made safe. stands as a good demo right now. - $responseFilename = Path::clean(JPATH_ROOT . "/tmp/task_{$id}_response.html"); + $responseFilename = Path::clean($this->rootDirectory . "/task_{$id}_response.html"); - if (File::write($responseFilename, $responseBody)) + try { + File::write($responseFilename, $responseBody); $this->snapshot['output_file'] = $responseFilename; $responseStatus = 'SAVED'; } - else + catch (Exception $e) { - $this->logTask($this->app->getLanguage()->_('PLG_TASK_REQUESTS_TASK_GET_REQUEST_LOG_UNWRITEABLE_OUTPUT'), 'error'); + $this->logTask($this->translate('PLG_TASK_REQUESTS_TASK_GET_REQUEST_LOG_UNWRITEABLE_OUTPUT'), 'error'); $responseStatus = 'NOT_SAVED'; } @@ -161,7 +164,7 @@ protected function makeGetRequest(ExecuteTaskEvent $event): int > Response: $responseStatus EOF; - $this->logTask(sprintf($this->app->getLanguage()->_('PLG_TASK_REQUESTS_TASK_GET_REQUEST_LOG_RESPONSE'), $responseCode)); + $this->logTask($this->translate('PLG_TASK_REQUESTS_TASK_GET_REQUEST_LOG_RESPONSE', $responseCode)); if ($response->code !== 200) { diff --git a/tests/Unit/Libraries/Cms/Plugin/CMSPluginTest.php b/tests/Unit/Libraries/Cms/Plugin/CMSPluginTest.php new file mode 100644 index 0000000000000..32c35f23c0642 --- /dev/null +++ b/tests/Unit/Libraries/Cms/Plugin/CMSPluginTest.php @@ -0,0 +1,533 @@ + + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +namespace Joomla\Tests\Unit\Libraries\Cms\Plugin; + +use Joomla\CMS\Application\CMSApplicationInterface; +use Joomla\CMS\Language\Language; +use Joomla\CMS\Plugin\CMSPlugin; +use Joomla\Event\Dispatcher; +use Joomla\Event\Event; +use Joomla\Event\EventInterface; +use Joomla\Event\SubscriberInterface; +use Joomla\Registry\Registry; +use Joomla\Tests\Unit\UnitTestCase; +use stdClass; + +/** + * Test class for \Joomla\CMS\Plugin\CMSPlugin + * + * @package Joomla.UnitTest + * @subpackage Plugin + * + * @testdox The CMSPlugin + * + * @since __DEPLOY_VERSION__ + */ +class CMSPluginTest extends UnitTestCase +{ + /** + * @testdox has the correct dispatcher + * + * @return void + * + * @since __DEPLOY_VERSION__ + */ + public function testInjectedDispatcher() + { + $dispatcher = new Dispatcher; + + $plugin = new class($dispatcher, []) extends CMSPlugin + {}; + + $this->assertEquals($dispatcher, $plugin->getDispatcher()); + } + + /** + * @testdox has the correct dispatcher + * + * @return void + * + * @since __DEPLOY_VERSION__ + */ + public function testInjectedApplication() + { + $dispatcher = new Dispatcher; + $app = $this->createStub(CMSApplicationInterface::class); + + $plugin = new class($dispatcher, []) extends CMSPlugin + { + public function getApplication(): CMSApplicationInterface + { + return parent::getApplication(); + } + }; + $plugin->setApplication($app); + + $this->assertEquals($app, $plugin->getApplication()); + } + + /** + * @testdox has null params when not set + * + * @return void + * + * @since __DEPLOY_VERSION__ + */ + public function testEmptyParams() + { + $dispatcher = new Dispatcher; + + $plugin = new class($dispatcher, []) extends CMSPlugin + {}; + + $this->assertNull($plugin->params); + } + + /** + * @testdox gets the injected params from a registry object + * + * @return void + * + * @since __DEPLOY_VERSION__ + */ + public function testInjectedRegistryParams() + { + $dispatcher = new Dispatcher; + $registry = new Registry; + + $plugin = new class($dispatcher, ['params' => $registry]) extends CMSPlugin + {}; + + $this->assertEquals($registry, $plugin->params); + } + + /** + * @testdox gets the injected params from array + * + * @return void + * + * @since __DEPLOY_VERSION__ + */ + public function testInjectedArrayParams() + { + $dispatcher = new Dispatcher; + + $plugin = new class($dispatcher, ['params' => ['test' => 'unit']]) extends CMSPlugin + {}; + + $this->assertEquals('unit', $plugin->params->get('test')); + } + + /** + * @testdox gets the injected name + * + * @return void + * + * @since __DEPLOY_VERSION__ + */ + public function testInjectedName() + { + $dispatcher = new Dispatcher; + + $plugin = new class($dispatcher, ['name' => 'test']) extends CMSPlugin + { + public function getName() + { + return $this->_name; + } + }; + + $this->assertEquals('test', $plugin->getName()); + } + + /** + * @testdox gets the injected type + * + * @return void + * + * @since __DEPLOY_VERSION__ + */ + public function testInjectedType() + { + $dispatcher = new Dispatcher; + + $plugin = new class($dispatcher, ['type' => 'test']) extends CMSPlugin + { + public function getType() + { + return $this->_type; + } + }; + + $this->assertEquals('test', $plugin->getType()); + } + + /** + * @testdox can load the language + * + * @return void + * + * @since __DEPLOY_VERSION__ + */ + public function testLoadLanguage() + { + $dispatcher = new Dispatcher; + $language = $this->createMock(Language::class); + $language->expects($this->once())->method('load')->with($this->equalTo('plg__'), JPATH_ADMINISTRATOR)->willReturn(true); + + $app = $this->createStub(CMSApplicationInterface::class); + $app->method('getLanguage')->willReturn($language); + + $plugin = new class($dispatcher, []) extends CMSPlugin + {}; + $plugin->setApplication($app); + $plugin->loadLanguage(); + } + + /** + * @testdox can load the language for a custom extension and path + * + * @return void + * + * @since __DEPLOY_VERSION__ + */ + public function testLoadLanguageWithExtensionAndPath() + { + $dispatcher = new Dispatcher; + $language = $this->createMock(Language::class); + $language->expects($this->once())->method('load')->with($this->equalTo('test'), __DIR__)->willReturn(true); + + $app = $this->createStub(CMSApplicationInterface::class); + $app->method('getLanguage')->willReturn($language); + + $plugin = new class($dispatcher, []) extends CMSPlugin + {}; + $plugin->setApplication($app); + $plugin->loadLanguage('test', __DIR__); + } + + /** + * @testdox does not load the language when the path exists + * + * @return void + * + * @since __DEPLOY_VERSION__ + */ + public function testNotLoadLanguageWhenExists() + { + $dispatcher = new Dispatcher; + $language = $this->createMock(Language::class); + $language->method('getPaths')->willReturn(true); + $language->expects($this->never())->method('load'); + + $app = $this->createStub(CMSApplicationInterface::class); + $app->method('getLanguage')->willReturn($language); + + $plugin = new class($dispatcher, []) extends CMSPlugin + {}; + $plugin->setApplication($app); + $plugin->loadLanguage(); + } + + /** + * @testdox can translate a string without arguments + * + * @return void + * + * @since __DEPLOY_VERSION__ + */ + public function testTranslateWithoutArguments() + { + $dispatcher = new Dispatcher; + $language = $this->createMock(Language::class); + $language->method('_')->willReturn('test'); + + $app = $this->createStub(CMSApplicationInterface::class); + $app->method('getLanguage')->willReturn($language); + + $plugin = new class($dispatcher, []) extends CMSPlugin + { + public function test(): string + { + return parent::translate('unit'); + } + }; + $plugin->setApplication($app); + + $this->assertEquals('test', $plugin->test()); + } + + /** + * @testdox can translate a string with arguments + * + * @return void + * + * @since __DEPLOY_VERSION__ + */ + public function testTranslateWithArguments() + { + $dispatcher = new Dispatcher; + $language = $this->createMock(Language::class); + $language->method('_')->willReturn('test %s in %s'); + + $app = $this->createStub(CMSApplicationInterface::class); + $app->method('getLanguage')->willReturn($language); + + $plugin = new class($dispatcher, []) extends CMSPlugin + { + public function test(): string + { + return parent::translate('unit', 1, 'two'); + } + }; + $plugin->setApplication($app); + + $this->assertEquals('test 1 in two', $plugin->test()); + } + + /** + * @testdox can register the listeners when is SubscriberInterface + * + * @return void + * + * @since __DEPLOY_VERSION__ + */ + public function testRegisterListenersAsSubscriber() + { + $dispatcher = new Dispatcher; + + $plugin = new class($dispatcher, []) extends CMSPlugin implements SubscriberInterface + { + public static function getSubscribedEvents(): array + { + return ['test' => 'unit']; + } + + public function unit() + {} + }; + $plugin->registerListeners(); + + $this->assertEquals([[$plugin, 'unit']], $dispatcher->getListeners('test')); + } + + /** + * @testdox can register the listeners when is legacy + * + * @return void + * + * @since __DEPLOY_VERSION__ + */ + public function testRegisterListenersAsLegacy() + { + $dispatcher = new Dispatcher; + + $plugin = new class($dispatcher, []) extends CMSPlugin + { + public function onTest() + {} + }; + $plugin->registerListeners(); + + $this->assertCount(1, $dispatcher->getListeners('onTest')); + } + + /** + * @testdox can register the listeners with event interface + * + * @return void + * + * @since __DEPLOY_VERSION__ + */ + public function testRegisterListenersForEventInterface() + { + $dispatcher = new Dispatcher; + + $plugin = new class($dispatcher, []) extends CMSPlugin + { + public function onTest(EventInterface $event) + {} + }; + $plugin->registerListeners(); + + $this->assertCount(1, $dispatcher->getListeners('onTest')); + } + + /** + * @testdox must register the listeners with event interface + * + * @return void + * + * @since __DEPLOY_VERSION__ + */ + public function testRegisterListenersWithForcedEventInterface() + { + $dispatcher = new Dispatcher; + + $plugin = new class($dispatcher, []) extends CMSPlugin + { + protected $allowLegacyListeners = false; + + public function onTest(EventInterface $event) + {} + }; + $plugin->registerListeners(); + + $this->assertCount(1, $dispatcher->getListeners('onTest')); + } + + /** + * @testdox can register the listeners when has typed arguments + * + * @return void + * + * @since __DEPLOY_VERSION__ + */ + public function testRegisterListenersForNoEventInterface() + { + $dispatcher = new Dispatcher; + + $plugin = new class($dispatcher, []) extends CMSPlugin + { + public function onTest(string $context) + {} + }; + $plugin->registerListeners(); + + $this->assertCount(1, $dispatcher->getListeners('onTest')); + } + + /** + * @testdox can register the listeners when has untyped arguments + * + * @return void + * + * @since __DEPLOY_VERSION__ + */ + public function testRegisterListenersNotTyped() + { + $dispatcher = new Dispatcher; + + $plugin = new class($dispatcher, []) extends CMSPlugin + { + public function onTest($event) + {} + }; + $plugin->registerListeners(); + + $this->assertCount(1, $dispatcher->getListeners('onTest')); + } + + /** + * @testdox can register the listeners when has nullable arguments + * + * @return void + * + * @since __DEPLOY_VERSION__ + */ + public function testRegisterListenersNullable() + { + $dispatcher = new Dispatcher; + + $plugin = new class($dispatcher, []) extends CMSPlugin + { + public function onTest(stdClass $event = null) + {} + }; + $plugin->registerListeners(); + + $this->assertCount(1, $dispatcher->getListeners('onTest')); + } + + /** + * @testdox can dispatch a legacy listener + * + * @return void + * + * @since __DEPLOY_VERSION__ + */ + public function testDispatchLegacyListener() + { + $dispatcher = new Dispatcher; + + $plugin = new class($dispatcher, []) extends CMSPlugin + { + public function registerTestListener() + { + parent::registerLegacyListener('onTest'); + } + + public function onTest() + { + return 'unit'; + } + }; + $plugin->registerTestListener(); + $event = $dispatcher->dispatch('onTest'); + + $this->assertEquals(['unit'], $event->getArgument('result')); + } + + /** + * @testdox can dispatch a legacy listener with null result + * + * @return void + * + * @since __DEPLOY_VERSION__ + */ + public function testDispatchLegacyListenerWhenNullIsReturned() + { + $dispatcher = new Dispatcher; + + $plugin = new class($dispatcher, []) extends CMSPlugin + { + public function registerTestListener() + { + parent::registerLegacyListener('onTest'); + } + + public function onTest() + {} + }; + $plugin->registerTestListener(); + $event = $dispatcher->dispatch('onTest'); + + $this->assertEquals(null, $event->getArgument('result')); + } + + /** + * @testdox can dispatch a legacy listener and contains the result from the event and the plugin + * + * @return void + * + * @since __DEPLOY_VERSION__ + */ + public function testDispatchLegacyListenerWhenEventHasResult() + { + $dispatcher = new Dispatcher; + + $plugin = new class($dispatcher, []) extends CMSPlugin + { + public function registerTestListener() + { + parent::registerLegacyListener('onTest'); + } + + public function onTest() + { + return 'unit'; + } + }; + $plugin->registerTestListener(); + $event = $dispatcher->dispatch('onTest', new Event('onTest', ['result' => ['test']])); + + $this->assertEquals(['test', 'unit'], $event->getArgument('result')); + } +} diff --git a/tests/Unit/Plugin/Task/Requests/Extension/RequestsPluginTest.php b/tests/Unit/Plugin/Task/Requests/Extension/RequestsPluginTest.php new file mode 100644 index 0000000000000..ced18b36249d3 --- /dev/null +++ b/tests/Unit/Plugin/Task/Requests/Extension/RequestsPluginTest.php @@ -0,0 +1,327 @@ + + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +namespace Joomla\Tests\Unit\Plugin\Task\Requests\Extension; + +use Exception; +use Joomla\CMS\Application\CMSApplicationInterface; +use Joomla\CMS\Http\Http; +use Joomla\CMS\Language\Language; +use Joomla\Component\Scheduler\Administrator\Event\ExecuteTaskEvent; +use Joomla\Component\Scheduler\Administrator\Task\Status; +use Joomla\Component\Scheduler\Administrator\Task\Task; +use Joomla\Event\Dispatcher; +use Joomla\Filesystem\Folder; +use Joomla\Http\HttpFactory; +use Joomla\Http\TransportInterface; +use Joomla\Plugin\Task\Requests\Extension\Requests; +use Joomla\Tests\Unit\UnitTestCase; +use Joomla\Uri\UriInterface; + +/** + * Test class for Requests plugin + * + * @package Joomla.UnitTest + * @subpackage Requests + * + * @testdox The Requests plugin + * + * @since __DEPLOY_VERSION__ + */ +class RequestsPluginTest extends UnitTestCase +{ + /** + * Setup + * + * @return void + * + * @since __DEPLOY_VERSION__ + */ + public function setUp(): void + { + if (is_dir(__DIR__ . '/tmp')) + { + Folder::delete(__DIR__ . '/tmp'); + } + } + + /** + * Cleanup + * + * @return void + * + * @since __DEPLOY_VERSION__ + */ + public function tearDown(): void + { + if (is_dir(__DIR__ . '/tmp')) + { + Folder::delete(__DIR__ . '/tmp'); + } + } + + /** + * @testdox can perform a HTTP GET request + * + * @return void + * + * @since __DEPLOY_VERSION__ + */ + public function testRequest() + { + $transport = new class implements TransportInterface + { + public $url; + + public function request($method, UriInterface $uri, $data = null, array $headers = [], $timeout = null, $userAgent = null) + { + $this->url = $uri->toString(); + + return (object)['code' => 200, 'body' => 'test']; + } + + public static function isSupported() + { + return true; + } + }; + + $http = new Http([], $transport); + $factory = $this->createStub(HttpFactory::class); + $factory->method('getHttp')->willReturn($http); + + $app = $this->createStub(CMSApplicationInterface::class); + $app->method('getLanguage')->willReturn($this->createStub(Language::class)); + + $plugin = new Requests(new Dispatcher, [], $factory, __DIR__ . '/tmp'); + $plugin->setApplication($app); + + $task = $this->createStub(Task::class); + $task->method('get')->willReturnMap([['id', null, 1], ['type', null, 'plg_task_requests_task_get']]); + + $event = new ExecuteTaskEvent( + 'test', + [ + 'subject' => $task, + 'params' => (object)['url' => 'http://example.com', 'timeout' => 0, 'auth' => 0, 'authType' => '', 'authKey' => ''] + ] + ); + $plugin->standardRoutineHandler($event); + + $this->assertEquals(Status::OK, $event->getResultSnapshot()['status']); + $this->assertStringContainsString('SAVED', $event->getResultSnapshot()['output']); + $this->assertEquals('http://example.com', $transport->url); + $this->assertStringEqualsFile(__DIR__ . '/tmp/task_1_response.html', 'test'); + } + + /** + * @testdox can perform a HTTP GET request where the return code is not 200 + * + * @return void + * + * @since __DEPLOY_VERSION__ + */ + public function testInvalidRequest() + { + $transport = new class implements TransportInterface + { + public $url; + + public function request($method, UriInterface $uri, $data = null, array $headers = [], $timeout = null, $userAgent = null) + { + $this->url = $uri->toString(); + + return (object)['code' => 404, 'body' => 'test']; + } + + public static function isSupported() + { + return true; + } + }; + + $http = new Http([], $transport); + $factory = $this->createStub(HttpFactory::class); + $factory->method('getHttp')->willReturn($http); + + $app = $this->createStub(CMSApplicationInterface::class); + $app->method('getLanguage')->willReturn($this->createStub(Language::class)); + + $plugin = new Requests(new Dispatcher, [], $factory, __DIR__ . '/tmp'); + $plugin->setApplication($app); + + $task = $this->createStub(Task::class); + $task->method('get')->willReturnMap([['id', null, 1], ['type', null, 'plg_task_requests_task_get']]); + + $event = new ExecuteTaskEvent( + 'test', + [ + 'subject' => $task, + 'params' => (object)['url' => 'http://example.com', 'timeout' => 0, 'auth' => 0, 'authType' => '', 'authKey' => ''] + ] + ); + $plugin->standardRoutineHandler($event); + + $this->assertEquals(Status::KNOCKOUT, $event->getResultSnapshot()['status']); + $this->assertStringContainsString('SAVED', $event->getResultSnapshot()['output']); + $this->assertEquals('http://example.com', $transport->url); + $this->assertStringEqualsFile(__DIR__ . '/tmp/task_1_response.html', 'test'); + } + + /** + * @testdox can perform a HTTP GET request with auth headers + * + * @return void + * + * @since __DEPLOY_VERSION__ + */ + public function testAuthRequest() + { + $transport = new class implements TransportInterface + { + public $headers; + + public function request($method, UriInterface $uri, $data = null, array $headers = [], $timeout = null, $userAgent = null) + { + $this->headers = $headers; + + return (object)['code' => 200, 'body' => 'test']; + } + + public static function isSupported() + { + return true; + } + }; + + $http = new Http([], $transport); + $factory = $this->createStub(HttpFactory::class); + $factory->method('getHttp')->willReturn($http); + + $app = $this->createStub(CMSApplicationInterface::class); + $app->method('getLanguage')->willReturn($this->createStub(Language::class)); + + $plugin = new Requests(new Dispatcher, [], $factory, __DIR__ . '/tmp'); + $plugin->setApplication($app); + + $task = $this->createStub(Task::class); + $task->method('get')->willReturnMap([['id', null, 1], ['type', null, 'plg_task_requests_task_get']]); + + $event = new ExecuteTaskEvent( + 'test', + [ + 'subject' => $task, + 'params' => (object)['url' => 'http://example.com', 'timeout' => 0, 'auth' => 1, 'authType' => 'basic', 'authKey' => '123'] + ] + ); + $plugin->standardRoutineHandler($event); + + $this->assertEquals(['basic' => '123'], $transport->headers); + } + + /** + * @testdox can handle an exception during the request + * + * @return void + * + * @since __DEPLOY_VERSION__ + */ + public function testExceptionInRequest() + { + $transport = new class implements TransportInterface + { + public function request($method, UriInterface $uri, $data = null, array $headers = [], $timeout = null, $userAgent = null) + { + throw new Exception('test'); + } + + public static function isSupported() + { + return true; + } + }; + + $http = new Http([], $transport); + $factory = $this->createStub(HttpFactory::class); + $factory->method('getHttp')->willReturn($http); + + $language = $this->createStub(Language::class); + $language->method('_')->willReturn('test'); + + $app = $this->createStub(CMSApplicationInterface::class); + $app->method('getLanguage')->willReturn($language); + + $plugin = new Requests(new Dispatcher, [], $factory, __DIR__ . '/tmp'); + $plugin->setApplication($app); + + $task = $this->createStub(Task::class); + $task->method('get')->willReturnMap([['id', null, 1], ['type', null, 'plg_task_requests_task_get']]); + + $event = new ExecuteTaskEvent( + 'test', + [ + 'subject' => $task, + 'params' => (object)['url' => 'http://example.com', 'timeout' => 0, 'auth' => 0, 'authType' => '', 'authKey' => ''] + ] + ); + $plugin->standardRoutineHandler($event); + + $this->assertEquals(Status::TIMEOUT, $event->getResultSnapshot()['status']); + } + /** + * @testdox can handle an invalid file location + * + * @return void + * + * @since __DEPLOY_VERSION__ + */ + public function testInvalidFileToWrite() + { + $transport = new class implements TransportInterface + { + public function request($method, UriInterface $uri, $data = null, array $headers = [], $timeout = null, $userAgent = null) + { + return (object)['code' => 200, 'body' => 'test']; + } + + public static function isSupported() + { + return true; + } + }; + + $http = new Http([], $transport); + $factory = $this->createStub(HttpFactory::class); + $factory->method('getHttp')->willReturn($http); + + $language = $this->createStub(Language::class); + $language->method('_')->willReturn('test'); + + $app = $this->createStub(CMSApplicationInterface::class); + $app->method('getLanguage')->willReturn($language); + + $plugin = new Requests(new Dispatcher, [], $factory, '/invalid'); + $plugin->setApplication($app); + + $task = $this->createStub(Task::class); + $task->method('get')->willReturnMap([['id', null, 1], ['type', null, 'plg_task_requests_task_get']]); + + $event = new ExecuteTaskEvent( + 'test', + [ + 'subject' => $task, + 'params' => (object)['url' => 'http://example.com', 'timeout' => 0, 'auth' => 0, 'authType' => '', 'authKey' => ''] + ] + ); + $plugin->standardRoutineHandler($event); + + $this->assertEquals(Status::OK, $event->getResultSnapshot()['status']); + $this->assertStringContainsString('NOT_SAVED', $event->getResultSnapshot()['output']); + } +}