diff --git a/plugins/task/sitestatus/services/provider.php b/plugins/task/sitestatus/services/provider.php
new file mode 100644
index 0000000000000..a5e6afce3465f
--- /dev/null
+++ b/plugins/task/sitestatus/services/provider.php
@@ -0,0 +1,50 @@
+
+ * @license GNU General Public License version 2 or later; see LICENSE.txt
+ */
+
+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;
+use Joomla\Event\DispatcherInterface;
+use Joomla\Plugin\Task\SiteStatus\Extension\SiteStatus;
+use Joomla\Utilities\ArrayHelper;
+
+return new class implements ServiceProviderInterface
+{
+ /**
+ * Registers the service provider with a DI container.
+ *
+ * @param Container $container The DI container.
+ *
+ * @return void
+ *
+ * @since __DEPLOY_VERSION__
+ */
+ public function register(Container $container)
+ {
+ $container->set(
+ PluginInterface::class,
+ function (Container $container)
+ {
+ $plugin = new SiteStatus(
+ $container->get(DispatcherInterface::class),
+ (array) PluginHelper::getPlugin('task', 'sitestatus'),
+ ArrayHelper::fromObject(new JConfig),
+ JPATH_CONFIGURATION . '/configuration.php'
+ );
+ $plugin->setApplication(Factory::getApplication());
+
+ return $plugin;
+ }
+ );
+ }
+};
diff --git a/plugins/task/sitestatus/sitestatus.xml b/plugins/task/sitestatus/sitestatus.xml
index ba54f3a508c85..ccae445cbb324 100644
--- a/plugins/task/sitestatus/sitestatus.xml
+++ b/plugins/task/sitestatus/sitestatus.xml
@@ -9,10 +9,10 @@
www.joomla.org
4.1
PLG_TASK_SITE_STATUS_XML_DESCRIPTION
+ Joomla\Plugin\Task\SiteStatus
- sitestatus.php
- language
- forms
+ services
+ src
language/en-GB/plg_task_sitestatus.ini
diff --git a/plugins/task/sitestatus/sitestatus.php b/plugins/task/sitestatus/src/Extension/SiteStatus.php
similarity index 62%
rename from plugins/task/sitestatus/sitestatus.php
rename to plugins/task/sitestatus/src/Extension/SiteStatus.php
index ecb7cbb9817a6..a8bc52c22af93 100644
--- a/plugins/task/sitestatus/sitestatus.php
+++ b/plugins/task/sitestatus/src/Extension/SiteStatus.php
@@ -7,20 +7,21 @@
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
+namespace Joomla\Plugin\Task\SiteStatus\Extension;
+
// Restrict direct access
defined('_JEXEC') or die;
-use Joomla\CMS\Application\CMSApplication;
-use Joomla\CMS\Filesystem\File;
-use Joomla\CMS\Filesystem\Path;
-use Joomla\CMS\Language\Text;
+use Exception;
use Joomla\CMS\Plugin\CMSPlugin;
use Joomla\Component\Scheduler\Administrator\Event\ExecuteTaskEvent;
use Joomla\Component\Scheduler\Administrator\Task\Status;
use Joomla\Component\Scheduler\Administrator\Traits\TaskPluginTrait;
+use Joomla\Event\DispatcherInterface;
use Joomla\Event\SubscriberInterface;
+use Joomla\Filesystem\File;
+use Joomla\Filesystem\Path;
use Joomla\Registry\Registry;
-use Joomla\Utilities\ArrayHelper;
/**
* Task plugin with routines to change the offline status of the site. These routines can be used to control planned
@@ -28,7 +29,7 @@
*
* @since 4.1.0
*/
-class PlgTaskSitestatus extends CMSPlugin implements SubscriberInterface
+final class SiteStatus extends CMSPlugin implements SubscriberInterface
{
use TaskPluginTrait;
@@ -54,14 +55,6 @@ class PlgTaskSitestatus extends CMSPlugin implements SubscriberInterface
];
- /**
- * The application object.
- *
- * @var CMSApplication
- * @since 4.1.0
- */
- protected $app;
-
/**
* Autoload the language file.
*
@@ -85,6 +78,40 @@ public static function getSubscribedEvents(): array
];
}
+ /**
+ * The old config
+ *
+ * @var array
+ * @since __DEPLOY_VERSION__
+ */
+ private $oldConfig;
+
+ /**
+ * The config file
+ *
+ * @var string
+ * @since __DEPLOY_VERSION__
+ */
+ private $configFile;
+
+ /**
+ * Constructor.
+ *
+ * @param DispatcherInterface $dispatcher The dispatcher
+ * @param array $config An optional associative array of configuration settings
+ * @param array $oldConfig The old config
+ * @param string $configFile The config
+ *
+ * @since __DEPLOY_VERSION__
+ */
+ public function __construct(DispatcherInterface $dispatcher, array $config, array $oldConfig, string $configFile)
+ {
+ parent::__construct($dispatcher, $config);
+
+ $this->oldConfig = $oldConfig;
+ $this->configFile = $configFile;
+ }
+
/**
* @param ExecuteTaskEvent $event The onExecuteTask event
*
@@ -102,7 +129,7 @@ public function alterSiteStatus(ExecuteTaskEvent $event): void
$this->startRoutine($event);
- $config = ArrayHelper::fromObject(new JConfig);
+ $config = $this->oldConfig;
$toggle = self::TASKS_MAP[$event->getRoutineId()]['toggle'];
$oldStatus = $config['offline'] ? 'offline' : 'online';
@@ -113,13 +140,12 @@ public function alterSiteStatus(ExecuteTaskEvent $event): void
}
else
{
- $offline = self::TASKS_MAP[$event->getRoutineId()]['offline'];
- $config['offline'] = $offline;
+ $config['offline'] = self::TASKS_MAP[$event->getRoutineId()]['offline'];
}
$newStatus = $config['offline'] ? 'offline' : 'online';
$exit = $this->writeConfigFile(new Registry($config));
- $this->logTask(Text::sprintf('PLG_TASK_SITE_STATUS_TASK_LOG_SITE_STATUS', $oldStatus, $newStatus));
+ $this->logTask($this->translate('PLG_TASK_SITE_STATUS_TASK_LOG_SITE_STATUS', $oldStatus, $newStatus));
$this->endRoutine($event, $exit);
}
@@ -137,20 +163,23 @@ public function alterSiteStatus(ExecuteTaskEvent $event): void
private function writeConfigFile(Registry $config): int
{
// Set the configuration file path.
- $file = JPATH_CONFIGURATION . '/configuration.php';
+ $file = $this->configFile;
// Attempt to make the file writeable.
- if (Path::isOwner($file) && !Path::setPermissions($file))
+ if (file_exists($file) && Path::isOwner($file) && !Path::setPermissions($file))
{
- $this->logTask(Text::_('PLG_TASK_SITE_STATUS_ERROR_CONFIGURATION_PHP_NOTWRITABLE'), 'notice');
+ $this->logTask($this->translate('PLG_TASK_SITE_STATUS_ERROR_CONFIGURATION_PHP_NOTWRITABLE'), 'notice');
}
- // Attempt to write the configuration file as a PHP class named JConfig.
- $configuration = $config->toString('PHP', array('class' => 'JConfig', 'closingtag' => false));
-
- if (!File::write($file, $configuration))
+ try
+ {
+ // Attempt to write the configuration file as a PHP class named JConfig.
+ $configuration = $config->toString('PHP', array('class' => 'JConfig', 'closingtag' => false));
+ File::write($file, $configuration);
+ }
+ catch (Exception $e)
{
- $this->logTask(Text::_('PLG_TASK_SITE_STATUS_ERROR_WRITE_FAILED'), 'error');
+ $this->logTask($this->translate('PLG_TASK_SITE_STATUS_ERROR_WRITE_FAILED'), 'error');
return Status::KNOCKOUT;
}
@@ -164,7 +193,7 @@ private function writeConfigFile(Registry $config): int
// Attempt to make the file un-writeable.
if (Path::isOwner($file) && !Path::setPermissions($file, '0444'))
{
- $this->logTask(Text::_('PLG_TASK_SITE_STATUS_ERROR_CONFIGURATION_PHP_NOTUNWRITABLE'), 'notice');
+ $this->logTask($this->translate('PLG_TASK_SITE_STATUS_ERROR_CONFIGURATION_PHP_NOTUNWRITABLE'), 'notice');
}
return Status::OK;
diff --git a/tests/Unit/Plugin/Task/SiteStatus/Extension/SiteStatusPluginTest.php b/tests/Unit/Plugin/Task/SiteStatus/Extension/SiteStatusPluginTest.php
new file mode 100644
index 0000000000000..66d420824dd7a
--- /dev/null
+++ b/tests/Unit/Plugin/Task/SiteStatus/Extension/SiteStatusPluginTest.php
@@ -0,0 +1,243 @@
+
+ * @license GNU General Public License version 2 or later; see LICENSE.txt
+ */
+
+namespace Joomla\Tests\Unit\Plugin\Task\SiteStatus\Extension;
+
+use Joomla\CMS\Application\CMSApplicationInterface;
+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\Plugin\Task\SiteStatus\Extension\SiteStatus;
+use Joomla\Tests\Unit\UnitTestCase;
+
+/**
+ * Test class for SiteStatus plugin
+ *
+ * @package Joomla.UnitTest
+ * @subpackage SiteStatus
+ *
+ * @testdox The SiteStatus plugin
+ *
+ * @since __DEPLOY_VERSION__
+ */
+class SiteStatusPluginTest extends UnitTestCase
+{
+ /**
+ * Setup
+ *
+ * @return void
+ *
+ * @since __DEPLOY_VERSION__
+ */
+ public function setUp(): void
+ {
+ if (!is_dir(__DIR__ . '/tmp'))
+ {
+ mkdir(__DIR__ . '/tmp');
+ }
+
+ touch(__DIR__ . '/tmp/config.php');
+ }
+
+ /**
+ * Cleanup
+ *
+ * @return void
+ *
+ * @since __DEPLOY_VERSION__
+ */
+ public function tearDown(): void
+ {
+ if (is_dir(__DIR__ . '/tmp'))
+ {
+ Folder::delete(__DIR__ . '/tmp');
+ }
+ }
+
+ /**
+ * @testdox can set the config from online to offline
+ *
+ * @return void
+ *
+ * @since __DEPLOY_VERSION__
+ */
+ public function testSetOnlineWhenOffline()
+ {
+ $app = $this->createStub(CMSApplicationInterface::class);
+ $app->method('getLanguage')->willReturn($this->createStub(Language::class));
+
+ $plugin = new SiteStatus(new Dispatcher, [], ['offline' => true], __DIR__ . '/tmp/config.php');
+ $plugin->setApplication($app);
+
+ $task = $this->createStub(Task::class);
+ $task->method('get')->willReturnMap([['id', null, 1], ['type', null, 'plg_task_toggle_offline_set_online']]);
+
+ $event = new ExecuteTaskEvent('test', ['subject' => $task]);
+ $plugin->alterSiteStatus($event);
+
+ $this->assertEquals(Status::OK, $event->getResultSnapshot()['status']);
+ $this->assertStringContainsString('$offline = false;', file_get_contents(__DIR__ . '/tmp/config.php'));
+ }
+
+ /**
+ * @testdox can keep the config online
+ *
+ * @return void
+ *
+ * @since __DEPLOY_VERSION__
+ */
+ public function testSetOnlineWhenOnline()
+ {
+ $app = $this->createStub(CMSApplicationInterface::class);
+ $app->method('getLanguage')->willReturn($this->createStub(Language::class));
+
+ $plugin = new SiteStatus(new Dispatcher, [], ['offline' => false], __DIR__ . '/tmp/config.php');
+ $plugin->setApplication($app);
+
+ $task = $this->createStub(Task::class);
+ $task->method('get')->willReturnMap([['id', null, 1], ['type', null, 'plg_task_toggle_offline_set_online']]);
+
+ $event = new ExecuteTaskEvent('test', ['subject' => $task]);
+ $plugin->alterSiteStatus($event);
+
+ $this->assertEquals(Status::OK, $event->getResultSnapshot()['status']);
+ $this->assertStringContainsString('$offline = false;', file_get_contents(__DIR__ . '/tmp/config.php'));
+ }
+
+ /**
+ * @testdox can set the config from offline to online
+ *
+ * @return void
+ *
+ * @since __DEPLOY_VERSION__
+ */
+ public function testSetOfflineWhenOnline()
+ {
+ $app = $this->createStub(CMSApplicationInterface::class);
+ $app->method('getLanguage')->willReturn($this->createStub(Language::class));
+
+ $plugin = new SiteStatus(new Dispatcher, [], ['offline' => false], __DIR__ . '/tmp/config.php');
+ $plugin->setApplication($app);
+
+ $task = $this->createStub(Task::class);
+ $task->method('get')->willReturnMap([['id', null, 1], ['type', null, 'plg_task_toggle_offline_set_offline']]);
+
+ $event = new ExecuteTaskEvent('test', ['subject' => $task]);
+ $plugin->alterSiteStatus($event);
+
+ $this->assertEquals(Status::OK, $event->getResultSnapshot()['status']);
+ $this->assertStringContainsString('$offline = true;', file_get_contents(__DIR__ . '/tmp/config.php'));
+ }
+
+ /**
+ * @testdox can keep the config offline
+ *
+ * @return void
+ *
+ * @since __DEPLOY_VERSION__
+ */
+ public function testSetOfflineWhenOffline()
+ {
+ $app = $this->createStub(CMSApplicationInterface::class);
+ $app->method('getLanguage')->willReturn($this->createStub(Language::class));
+
+ $plugin = new SiteStatus(new Dispatcher, [], ['offline' => true], __DIR__ . '/tmp/config.php');
+ $plugin->setApplication($app);
+
+ $task = $this->createStub(Task::class);
+ $task->method('get')->willReturnMap([['id', null, 1], ['type', null, 'plg_task_toggle_offline_set_offline']]);
+
+ $event = new ExecuteTaskEvent('test', ['subject' => $task]);
+ $plugin->alterSiteStatus($event);
+
+ $this->assertEquals(Status::OK, $event->getResultSnapshot()['status']);
+ $this->assertStringContainsString('$offline = true;', file_get_contents(__DIR__ . '/tmp/config.php'));
+ }
+
+ /**
+ * @testdox can toggle the config from online to offline
+ *
+ * @return void
+ *
+ * @since __DEPLOY_VERSION__
+ */
+ public function testToggleOffline()
+ {
+ $app = $this->createStub(CMSApplicationInterface::class);
+ $app->method('getLanguage')->willReturn($this->createStub(Language::class));
+
+ $plugin = new SiteStatus(new Dispatcher, [], ['offline' => false], __DIR__ . '/tmp/config.php');
+ $plugin->setApplication($app);
+
+ $task = $this->createStub(Task::class);
+ $task->method('get')->willReturnMap([['id', null, 1], ['type', null, 'plg_task_toggle_offline']]);
+
+ $event = new ExecuteTaskEvent('test', ['subject' => $task]);
+ $plugin->alterSiteStatus($event);
+
+ $this->assertEquals(Status::OK, $event->getResultSnapshot()['status']);
+ $this->assertStringContainsString('$offline = true;', file_get_contents(__DIR__ . '/tmp/config.php'));
+ }
+
+ /**
+ * @testdox can toggle the config from offline to online
+ *
+ * @return void
+ *
+ * @since __DEPLOY_VERSION__
+ */
+ public function testToggleOnline()
+ {
+ $app = $this->createStub(CMSApplicationInterface::class);
+ $app->method('getLanguage')->willReturn($this->createStub(Language::class));
+
+ $plugin = new SiteStatus(new Dispatcher, [], ['offline' => true], __DIR__ . '/tmp/config.php');
+ $plugin->setApplication($app);
+
+ $task = $this->createStub(Task::class);
+ $task->method('get')->willReturnMap([['id', null, 1], ['type', null, 'plg_task_toggle_offline']]);
+
+ $event = new ExecuteTaskEvent('test', ['subject' => $task]);
+ $plugin->alterSiteStatus($event);
+
+ $this->assertEquals(Status::OK, $event->getResultSnapshot()['status']);
+ $this->assertStringContainsString('$offline = false;', file_get_contents(__DIR__ . '/tmp/config.php'));
+ }
+
+ /**
+ * @testdox can't set the config file'
+ *
+ * @return void
+ *
+ * @since __DEPLOY_VERSION__
+ */
+ public function testInvalidConfigFile()
+ {
+ $language = $this->createStub(Language::class);
+ $language->method('_')->willReturn('test');
+
+ $app = $this->createStub(CMSApplicationInterface::class);
+ $app->method('getLanguage')->willReturn($language);
+
+ $plugin = new SiteStatus(new Dispatcher, [], ['offline' => true], '/invalid/config.php');
+ $plugin->setApplication($app);
+
+ $task = $this->createStub(Task::class);
+ $task->method('get')->willReturnMap([['id', null, 1], ['type', null, 'plg_task_toggle_offline']]);
+
+ $event = new ExecuteTaskEvent('test', ['subject' => $task]);
+ $plugin->alterSiteStatus($event);
+
+ $this->assertEquals(Status::KNOCKOUT, $event->getResultSnapshot()['status']);
+ $this->assertFileNotExists('/invalid/config.php');
+ }
+}