diff --git a/plugins/task/checkfiles/checkfiles.xml b/plugins/task/checkfiles/checkfiles.xml index 2a3cbb4f2be36..61c94a5dd9ae3 100644 --- a/plugins/task/checkfiles/checkfiles.xml +++ b/plugins/task/checkfiles/checkfiles.xml @@ -9,9 +9,10 @@ www.joomla.org 4.1 PLG_TASK_CHECK_FILES_XML_DESCRIPTION + Joomla\Plugin\Task\Checkfiles - checkfiles.php - language + services + src forms diff --git a/plugins/task/checkfiles/services/provider.php b/plugins/task/checkfiles/services/provider.php new file mode 100644 index 0000000000000..2a518e2f0571e --- /dev/null +++ b/plugins/task/checkfiles/services/provider.php @@ -0,0 +1,48 @@ + + * @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\Checkfiles\Extension\Checkfiles; + +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 Checkfiles( + $container->get(DispatcherInterface::class), + (array) PluginHelper::getPlugin('task', 'checkfiles'), + JPATH_ROOT . '/images/' + ); + $plugin->setApplication(Factory::getApplication()); + + return $plugin; + } + ); + } +}; diff --git a/plugins/task/checkfiles/checkfiles.php b/plugins/task/checkfiles/src/Extension/Checkfiles.php similarity index 61% rename from plugins/task/checkfiles/checkfiles.php rename to plugins/task/checkfiles/src/Extension/Checkfiles.php index d8505700bef0c..50a8f85ed5fff 100644 --- a/plugins/task/checkfiles/checkfiles.php +++ b/plugins/task/checkfiles/src/Extension/Checkfiles.php @@ -6,19 +6,20 @@ * * @copyright (C) 2021 Open Source Matters, Inc. * @license GNU General Public License version 2 or later; see LICENSE.txt - - * @phpcs:disable PSR1.Classes.ClassDeclaration.MissingNamespace */ -use Joomla\CMS\Filesystem\Folder; +namespace Joomla\Plugin\Task\Checkfiles\Extension; + use Joomla\CMS\Image\Image; -use Joomla\CMS\Language\Text; use Joomla\CMS\Plugin\CMSPlugin; use Joomla\Component\Scheduler\Administrator\Event\ExecuteTaskEvent; use Joomla\Component\Scheduler\Administrator\Task\Status as TaskStatus; use Joomla\Component\Scheduler\Administrator\Traits\TaskPluginTrait; +use Joomla\Event\DispatcherInterface; use Joomla\Event\SubscriberInterface; +use Joomla\Filesystem\Folder; use Joomla\Filesystem\Path; +use LogicException; /** * Task plugin with routines that offer checks on files. @@ -26,7 +27,7 @@ * * @since 4.1.0 */ -class PlgTaskCheckfiles extends CMSPlugin implements SubscriberInterface +final class Checkfiles extends CMSPlugin implements SubscriberInterface { use TaskPluginTrait; @@ -43,12 +44,6 @@ class PlgTaskCheckfiles extends CMSPlugin implements SubscriberInterface ], ]; - /** - * @var boolean - * @since 4.1.0 - */ - protected $autoloadLanguage = true; - /** * @inheritDoc * @@ -65,6 +60,36 @@ public static function getSubscribedEvents(): array ]; } + /** + * @var boolean + * @since 4.1.0 + */ + protected $autoloadLanguage = true; + + /** + * The root directory path + * + * @var string + * @since __DEPLOY_VERSION__ + */ + private $rootDirectory; + + /** + * Constructor. + * + * @param DispatcherInterface $dispatcher The dispatcher + * @param array $config An optional associative array of configuration settings + * @param string $rootDirectory The root directory to look for images + * + * @since __DEPLOY_VERSION__ + */ + public function __construct(DispatcherInterface $dispatcher, array $config, string $rootDirectory) + { + parent::__construct($dispatcher, $config); + + $this->rootDirectory = $rootDirectory; + } + /** * @param ExecuteTaskEvent $event The onExecuteTask event * @@ -76,22 +101,19 @@ public static function getSubscribedEvents(): array */ protected function checkImages(ExecuteTaskEvent $event): int { - $params = $event->getArgument('params'); - - $path = Path::check(JPATH_ROOT . '/images/' . $params->path); + $params = $event->getArgument('params'); + $path = Path::check($this->rootDirectory . $params->path); $dimension = $params->dimension; $limit = $params->limit; $numImages = max(1, (int) $params->numImages ?? 1); - if (!Folder::exists($path)) { - $this->logTask(Text::_('PLG_TASK_CHECK_FILES_LOG_IMAGE_PATH_NA'), 'warning'); + if (!is_dir($path)) { + $this->logTask($this->getApplication()->getLanguage()->_('PLG_TASK_CHECK_FILES_LOG_IMAGE_PATH_NA'), 'warning'); return TaskStatus::NO_RUN; } - $images = Folder::files($path, '^.*\.(jpg|jpeg|png|gif|webp)', 2, true); - - foreach ($images as $imageFilename) { + foreach (Folder::files($path, '^.*\.(jpg|jpeg|png|gif|webp)', 2, true) as $imageFilename) { $properties = Image::getImageFileProperties($imageFilename); $resize = $properties->$dimension > $limit; @@ -105,23 +127,29 @@ protected function checkImages(ExecuteTaskEvent $event): int $newHeight = $dimension === 'height' ? $limit : $height * $limit / $width; $newWidth = $dimension === 'width' ? $limit : $width * $limit / $height; - $this->logTask(Text::sprintf('PLG_TASK_CHECK_FILES_LOG_RESIZING_IMAGE', $width, $height, $newWidth, $newHeight, $imageFilename)); + $this->logTask(sprintf( + $this->getApplication()->getLanguage()->_('PLG_TASK_CHECK_FILES_LOG_RESIZING_IMAGE'), + $width, + $height, + $newWidth, + $newHeight, + $imageFilename + )); $image = new Image($imageFilename); try { $image->resize($newWidth, $newHeight, false); } catch (LogicException $e) { - $this->logTask('PLG_TASK_CHECK_FILES_LOG_RESIZE_FAIL', 'error'); - $resizeFail = true; - } + $this->logTask($this->getApplication()->getLanguage()->_('PLG_TASK_CHECK_FILES_LOG_RESIZE_FAIL'), 'error'); - if (!empty($resizeFail)) { return TaskStatus::KNOCKOUT; } if (!$image->toFile($imageFilename, $properties->type)) { - $this->logTask('PLG_TASK_CHECK_FILES_LOG_IMAGE_SAVE_FAIL', 'error'); + $this->logTask($this->getApplication()->getLanguage()->_('PLG_TASK_CHECK_FILES_LOG_IMAGE_SAVE_FAIL'), 'error'); + + return TaskStatus::KNOCKOUT; } --$numImages; diff --git a/tests/Unit/Plugin/Task/Checkfiles/Extension/CheckfilesPluginTest.php b/tests/Unit/Plugin/Task/Checkfiles/Extension/CheckfilesPluginTest.php new file mode 100644 index 0000000000000..cd406a7881d2f --- /dev/null +++ b/tests/Unit/Plugin/Task/Checkfiles/Extension/CheckfilesPluginTest.php @@ -0,0 +1,220 @@ + + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +namespace Joomla\Tests\Unit\Plugin\Task\Checkfiles\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\Checkfiles\Extension\Checkfiles; +use Joomla\Tests\Unit\UnitTestCase; + +/** + * Test class for Checkfiles plugin + * + * @package Joomla.UnitTest + * @subpackage Checkfiles + * + * @testdox The Checkfiles plugin + * + * @since __DEPLOY_VERSION__ + */ +class CheckfilesPluginTest extends UnitTestCase +{ + /** + * Setup + * + * @return void + * + * @since __DEPLOY_VERSION__ + */ + public function setUp(): void + { + if (!is_dir(__DIR__ . '/tmp')) { + mkdir(__DIR__ . '/tmp'); + } + + $image = imagecreate(200, 200); + imagecolorallocate($image, 255, 255, 0); + imagepng($image, __DIR__ . '/tmp/test.png'); + imagedestroy($image); + } + + /** + * Cleanup + * + * @return void + * + * @since __DEPLOY_VERSION__ + */ + public function tearDown(): void + { + if (is_dir(__DIR__ . '/tmp')) { + Folder::delete(__DIR__ . '/tmp'); + } + } + + /** + * @testdox can resize an image + * + * @return void + * + * @since __DEPLOY_VERSION__ + */ + public function testResize() + { + $language = $this->createStub(Language::class); + $language->method('_')->willReturn('test'); + + $app = $this->createStub(CMSApplicationInterface::class); + $app->method('getLanguage')->willReturn($language); + + $plugin = new Checkfiles(new Dispatcher(), [], __DIR__); + $plugin->setApplication($app); + + $task = $this->createStub(Task::class); + $task->method('get')->willReturnMap([['id', null, 1], ['type', null, 'checkfiles.imagesize']]); + + $event = new ExecuteTaskEvent( + 'test', + [ + 'subject' => $task, + 'params' => (object)['path' => '/tmp', 'dimension' => 'width', 'limit' => 20, 'numImages' => 1] + ] + ); + $plugin->standardRoutineHandler($event); + + $this->assertEquals(Status::OK, $event->getResultSnapshot()['status']); + + list($width, $height) = getimagesize(__DIR__ . '/tmp/test.png'); + $this->assertEquals(20, $width); + $this->assertEquals(20, $height); + } + + /** + * @testdox can resize a subset of images + * + * @return void + * + * @since __DEPLOY_VERSION__ + */ + public function testResizeWithLimit() + { + copy(__DIR__ . '/tmp/test.png', __DIR__ . '/tmp/test1.png'); + + $language = $this->createStub(Language::class); + $language->method('_')->willReturn('test'); + + $app = $this->createStub(CMSApplicationInterface::class); + $app->method('getLanguage')->willReturn($language); + + $plugin = new Checkfiles(new Dispatcher(), [], __DIR__); + $plugin->setApplication($app); + + $task = $this->createStub(Task::class); + $task->method('get')->willReturnMap([['id', null, 1], ['type', null, 'checkfiles.imagesize']]); + + $event = new ExecuteTaskEvent( + 'test', + [ + 'subject' => $task, + 'params' => (object)['path' => '/tmp', 'dimension' => 'width', 'limit' => 20, 'numImages' => 1] + ] + ); + $plugin->standardRoutineHandler($event); + + $this->assertEquals(Status::OK, $event->getResultSnapshot()['status']); + + list($width, $height) = getimagesize(__DIR__ . '/tmp/test.png'); + $this->assertEquals(20, $width); + $this->assertEquals(20, $height); + + list($width, $height) = getimagesize(__DIR__ . '/tmp/test1.png'); + $this->assertEquals(200, $width); + $this->assertEquals(200, $height); + } + + /** + * @testdox can resize an image + * + * @return void + * + * @since __DEPLOY_VERSION__ + */ + public function testIgnoreResize() + { + $language = $this->createStub(Language::class); + $language->method('_')->willReturn('test'); + + $app = $this->createStub(CMSApplicationInterface::class); + $app->method('getLanguage')->willReturn($language); + + $plugin = new Checkfiles(new Dispatcher(), [], __DIR__); + $plugin->setApplication($app); + + $task = $this->createStub(Task::class); + $task->method('get')->willReturnMap([['id', null, 1], ['type', null, 'checkfiles.imagesize']]); + + $event = new ExecuteTaskEvent( + 'test', + [ + 'subject' => $task, + 'params' => (object)['path' => '/tmp', 'dimension' => 'width', 'limit' => 2000, 'numImages' => 1] + ] + ); + $plugin->standardRoutineHandler($event); + + $this->assertEquals(Status::OK, $event->getResultSnapshot()['status']); + + list($width, $height) = getimagesize(__DIR__ . '/tmp/test.png'); + $this->assertEquals(200, $width); + $this->assertEquals(200, $height); + } + + /** + * @testdox can not run when invalid folder + * + * @return void + * + * @since __DEPLOY_VERSION__ + */ + public function testInvalidFolder() + { + $language = $this->createStub(Language::class); + $language->method('_')->willReturn('test'); + + $app = $this->createStub(CMSApplicationInterface::class); + $app->method('getLanguage')->willReturn($language); + + $plugin = new Checkfiles(new Dispatcher(), [], __DIR__); + $plugin->setApplication($app); + + $task = $this->createStub(Task::class); + $task->method('get')->willReturnMap([['id', null, 1], ['type', null, 'checkfiles.imagesize']]); + + $event = new ExecuteTaskEvent( + 'test', + [ + 'subject' => $task, + 'params' => (object)['path' => '/invalid', 'dimension' => 'width', 'limit' => 20, 'numImages' => 1] + ] + ); + $plugin->standardRoutineHandler($event); + + list($width, $height) = getimagesize(__DIR__ . '/tmp/test.png'); + $this->assertEquals(Status::NO_RUN, $event->getResultSnapshot()['status']); + $this->assertEquals(200, $width); + $this->assertEquals(200, $height); + } +}