Skip to content

Commit eadc217

Browse files
authored
[4.3] Local adapter thumbnails (PR 36552 clone) (#38805)
1 parent bdf3476 commit eadc217

File tree

5 files changed

+211
-23
lines changed

5 files changed

+211
-23
lines changed

administrator/language/en-GB/plg_filesystem_local.ini

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
PLG_FILESYSTEM_LOCAL="FileSystem - Local"
77
PLG_FILESYSTEM_LOCAL_DEFAULT_NAME="Local"
8-
PLG_FILESYSTEM_LOCAL_DIRECTORIES_DIRECTORY_LABEL="Select directories"
8+
PLG_FILESYSTEM_LOCAL_DIRECTORIES_DIRECTORY_LABEL="Select Directories"
9+
PLG_FILESYSTEM_LOCAL_DIRECTORIES_DIRECTORY_THUMBNAILS_LABEL="Create Thumbnails"
910
PLG_FILESYSTEM_LOCAL_DIRECTORIES_LABEL="Directories"
1011
PLG_FILESYSTEM_LOCAL_XML_DESCRIPTION="Filesystem plugin to define one or multiple local directories to store your media files."

libraries/src/Image/Image.php

Lines changed: 33 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -305,17 +305,18 @@ public function generateThumbs($thumbSizes, $creationMethod = self::SCALE_INSIDE
305305
/**
306306
* Method to create thumbnails from the current image and save them to disk. It allows creation by resizing or cropping the original image.
307307
*
308-
* @param mixed $thumbSizes string or array of strings. Example: $thumbSizes = array('150x75','250x150');
309-
* @param integer $creationMethod 1-3 resize $scaleMethod | 4 create cropping
310-
* @param string $thumbsFolder destination thumbs folder. null generates a thumbs folder in the image folder
308+
* @param mixed $thumbSizes string or array of strings. Example: $thumbSizes = ['150x75','250x150'];
309+
* @param integer $creationMethod 1-3 resize $scaleMethod | 4 create cropping
310+
* @param string $thumbsFolder destination thumbs folder. null generates a thumbs folder in the image folder
311+
* @param boolean $useOriginalName Shall we use the original image name? Defaults is false, {filename}_{width}x{height}.{ext}
311312
*
312313
* @return array
313314
*
314-
* @since 2.5.0
315+
* @since __DEPLOY_VERSION__
315316
* @throws \LogicException
316317
* @throws \InvalidArgumentException
317318
*/
318-
public function createThumbs($thumbSizes, $creationMethod = self::SCALE_INSIDE, $thumbsFolder = null)
319+
public function createThumbnails($thumbSizes, $creationMethod = self::SCALE_INSIDE, $thumbsFolder = null, $useOriginalName = false)
319320
{
320321
// Make sure the resource handle is valid.
321322
if (!$this->isLoaded()) {
@@ -349,8 +350,13 @@ public function createThumbs($thumbSizes, $creationMethod = self::SCALE_INSIDE,
349350
$thumbWidth = $thumb->getWidth();
350351
$thumbHeight = $thumb->getHeight();
351352

352-
// Generate thumb name
353-
$thumbFileName = $filename . '_' . $thumbWidth . 'x' . $thumbHeight . '.' . $fileExtension;
353+
if ($useOriginalName) {
354+
// Generate thumb name
355+
$thumbFileName = $filename . '.' . $fileExtension;
356+
} else {
357+
// Generate thumb name
358+
$thumbFileName = $filename . '_' . $thumbWidth . 'x' . $thumbHeight . '.' . $fileExtension;
359+
}
354360

355361
// Save thumb file to disk
356362
$thumbFileName = $thumbsFolder . '/' . $thumbFileName;
@@ -366,6 +372,26 @@ public function createThumbs($thumbSizes, $creationMethod = self::SCALE_INSIDE,
366372
return $thumbsCreated;
367373
}
368374

375+
/**
376+
* Method to create thumbnails from the current image and save them to disk. It allows creation by resizing or cropping the original image.
377+
*
378+
* @param mixed $thumbSizes string or array of strings. Example: $thumbSizes = ['150x75','250x150'];
379+
* @param integer $creationMethod 1-3 resize $scaleMethod | 4 create cropping
380+
* @param string $thumbsFolder destination thumbs folder. null generates a thumbs folder in the image folder
381+
*
382+
* @return array
383+
*
384+
* @since 2.5.0
385+
* @throws \LogicException
386+
* @throws \InvalidArgumentException
387+
*
388+
* @deprecated 6.0 Use \Joomla\CMS\Image\createThumbnails instead
389+
*/
390+
public function createThumbs($thumbSizes, $creationMethod = self::SCALE_INSIDE, $thumbsFolder = null)
391+
{
392+
return $this->createThumbnails($thumbSizes, $creationMethod, $thumbsFolder, false);
393+
}
394+
369395
/**
370396
* Method to crop the current image.
371397
*

plugins/filesystem/local/local.php

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ public function getDisplayName()
8484
public function getAdapters()
8585
{
8686
$adapters = [];
87-
$directories = $this->params->get('directories', '[{"directory": "images"}]');
87+
$directories = $this->params->get('directories', '[{"directory": "images", "thumbs": 0}]');
8888

8989
// Do a check if default settings are not saved by user
9090
// If not initialize them manually
@@ -97,9 +97,15 @@ public function getAdapters()
9797
$directoryPath = JPATH_ROOT . '/' . $directoryEntity->directory;
9898
$directoryPath = rtrim($directoryPath) . '/';
9999

100+
if (!isset($directoryEntity->thumbs)) {
101+
$directoryEntity->thumbs = 0;
102+
}
103+
100104
$adapter = new \Joomla\Plugin\Filesystem\Local\Adapter\LocalAdapter(
101105
$directoryPath,
102-
$directoryEntity->directory
106+
$directoryEntity->directory,
107+
$directoryEntity->thumbs,
108+
[200, 200]
103109
);
104110

105111
$adapters[$adapter->getAdapterName()] = $adapter;

plugins/filesystem/local/local.xml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,17 @@
4444
hide_none="true"
4545
validate="options"
4646
/>
47+
<field
48+
name="thumbs"
49+
type="radio"
50+
label="PLG_FILESYSTEM_LOCAL_DIRECTORIES_DIRECTORY_THUMBNAILS_LABEL"
51+
layout="joomla.form.field.radio.switcher"
52+
default="0"
53+
filter="integer"
54+
>
55+
<option value="0">JNO</option>
56+
<option value="1">JYES</option>
57+
</field>
4758
</form>
4859
</field>
4960
</fieldset>

plugins/filesystem/local/src/Adapter/LocalAdapter.php

Lines changed: 157 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -55,22 +55,52 @@ class LocalAdapter implements AdapterInterface
5555
*/
5656
private $filePath = null;
5757

58+
/**
59+
* Should the adapter create a thumbnail for the image?
60+
*
61+
* @var boolean
62+
*
63+
* @since __DEPLOY_VERSION__
64+
*/
65+
private $thumbnails = false;
66+
67+
/**
68+
* Thumbnail dimensions in pixels, [0] = width, [1] = height
69+
*
70+
* @var array
71+
*
72+
* @since __DEPLOY_VERSION__
73+
*/
74+
private $thumbnailSize = [200, 200];
75+
5876
/**
5977
* The absolute root path in the local file system.
6078
*
61-
* @param string $rootPath The root path
62-
* @param string $filePath The file path of media folder
79+
* @param string $rootPath The root path
80+
* @param string $filePath The file path of media folder
81+
* @param boolean $thumbnails The thumbnails option
82+
* @param array $thumbnailSize The thumbnail dimensions in pixels
6383
*
6484
* @since 4.0.0
6585
*/
66-
public function __construct(string $rootPath, string $filePath)
86+
public function __construct(string $rootPath, string $filePath, bool $thumbnails = false, array $thumbnailSize = [200, 200])
6787
{
6888
if (!file_exists($rootPath)) {
6989
throw new \InvalidArgumentException(Text::_('COM_MEDIA_ERROR_MISSING_DIR'));
7090
}
7191

72-
$this->rootPath = Path::clean(realpath($rootPath), '/');
73-
$this->filePath = $filePath;
92+
$this->rootPath = Path::clean(realpath($rootPath), '/');
93+
$this->filePath = $filePath;
94+
$this->thumbnails = $thumbnails;
95+
$this->thumbnailSize = $thumbnailSize;
96+
97+
if ($this->thumbnails) {
98+
$dir = JPATH_ROOT . '/media/cache/com_media/thumbs/' . $this->filePath;
99+
100+
if (!is_dir($dir)) {
101+
Folder::create($dir);
102+
}
103+
}
74104
}
75105

76106
/**
@@ -221,14 +251,24 @@ public function createFolder(string $name, string $path): string
221251
*/
222252
public function createFile(string $name, string $path, $data): string
223253
{
224-
$name = $this->getSafeName($name);
225-
254+
$name = $this->getSafeName($name);
226255
$localPath = $this->getLocalPath($path . '/' . $name);
227256

228257
$this->checkContent($localPath, $data);
229258

230259
File::write($localPath, $data);
231260

261+
if ($this->thumbnails && MediaHelper::isImage(pathinfo($localPath)['basename'])) {
262+
$thumbnailPaths = $this->getLocalThumbnailPaths($localPath);
263+
264+
if (empty($thumbnailPaths)) {
265+
return $name;
266+
}
267+
268+
// Create the thumbnail
269+
$this->createThumbnail($localPath, $thumbnailPaths['fs']);
270+
}
271+
232272
return $name;
233273
}
234274

@@ -255,6 +295,17 @@ public function updateFile(string $name, string $path, $data)
255295
$this->checkContent($localPath, $data);
256296

257297
File::write($localPath, $data);
298+
299+
if ($this->thumbnails && MediaHelper::isImage(pathinfo($localPath)['basename'])) {
300+
$thumbnailPaths = $this->getLocalThumbnailPaths($localPath);
301+
302+
if (empty($thumbnailPaths['fs'])) {
303+
return;
304+
}
305+
306+
// Create the thumbnail
307+
$this->createThumbnail($localPath, $thumbnailPaths['fs']);
308+
}
258309
}
259310

260311
/**
@@ -269,20 +320,29 @@ public function updateFile(string $name, string $path, $data)
269320
*/
270321
public function delete(string $path)
271322
{
272-
$localPath = $this->getLocalPath($path);
323+
$localPath = $this->getLocalPath($path);
324+
$thumbnailPaths = $this->getLocalThumbnailPaths($localPath);
273325

274326
if (is_file($localPath)) {
275327
if (!File::exists($localPath)) {
276328
throw new FileNotFoundException();
277329
}
278330

331+
if ($this->thumbnails && !empty($thumbnailPaths['fs']) && is_file($thumbnailPaths['fs'])) {
332+
File::delete($thumbnailPaths['fs']);
333+
}
334+
279335
$success = File::delete($localPath);
280336
} else {
281337
if (!Folder::exists($localPath)) {
282338
throw new FileNotFoundException();
283339
}
284340

285341
$success = Folder::delete($localPath);
342+
343+
if ($this->thumbnails && !empty($thumbnailPaths['fs']) && is_dir($thumbnailPaths['fs'])) {
344+
Folder::delete($thumbnailPaths['fs']);
345+
}
286346
}
287347

288348
if (!$success) {
@@ -303,7 +363,7 @@ public function delete(string $path)
303363
* - mime_type: The mime type
304364
* - width: The width, when available
305365
* - height: The height, when available
306-
* - thumb_path The thumbnail path of file, when available
366+
* - thumb_path: The thumbnail path of file, when available
307367
*
308368
* @param string $path The folder
309369
*
@@ -351,8 +411,7 @@ private function getPathInformation(string $path): \stdClass
351411
$obj->width = $props->width;
352412
$obj->height = $props->height;
353413

354-
// @todo : Change this path to an actual thumbnail path
355-
$obj->thumb_path = $this->getUrl($obj->path);
414+
$obj->thumb_path = $this->thumbnails ? $this->getThumbnail($path) : $this->getUrl($obj->path);
356415
} catch (UnparsableImageException $e) {
357416
// Ignore the exception - it's an image that we don't know how to parse right now
358417
}
@@ -689,7 +748,7 @@ private function rglob(string $pattern, int $flags = 0): array
689748
{
690749
$files = glob($pattern, $flags);
691750

692-
foreach (glob(\dirname($pattern) . '/*', GLOB_ONLYDIR | GLOB_NOSORT) as $dir) {
751+
foreach (glob(dirname($pattern) . '/*', GLOB_ONLYDIR | GLOB_NOSORT) as $dir) {
693752
$files = array_merge($files, $this->rglob($dir . '/' . $this->getFileName($pattern), $flags));
694753
}
695754

@@ -763,7 +822,7 @@ private function checkContent(string $localPath, string $mediaContent)
763822
$helper = new MediaHelper();
764823

765824
// @todo find a better way to check the input, by not writing the file to the disk
766-
$tmpFile = Path::clean(\dirname($localPath) . '/' . uniqid() . '.' . File::getExt($name));
825+
$tmpFile = Path::clean(dirname($localPath) . '/' . uniqid() . '.' . File::getExt($name));
767826

768827
if (!File::write($tmpFile, $mediaContent)) {
769828
throw new \Exception(Text::_('JLIB_MEDIA_ERROR_UPLOAD_INPUT'), 500);
@@ -819,4 +878,89 @@ private function getLocalPath(string $path): string
819878
throw new InvalidPathException($e->getMessage());
820879
}
821880
}
881+
882+
/**
883+
* Returns the local filesystem thumbnail path for the given path.
884+
*
885+
* Throws an InvalidPathException if the path is invalid.
886+
*
887+
* @param string $path The path
888+
*
889+
* @return array
890+
*
891+
* @since __DEPLOY_VERSION__
892+
* @throws InvalidPathException
893+
*/
894+
private function getLocalThumbnailPaths(string $path): array
895+
{
896+
$rootPath = str_replace(['\\', '/'], '/', $this->rootPath);
897+
$path = str_replace(['\\', '/'], '/', $path);
898+
899+
try {
900+
$fs = Path::check(str_replace($rootPath, JPATH_ROOT . '/media/cache/com_media/thumbs/' . $this->filePath, $path));
901+
$url = str_replace($rootPath, 'media/cache/com_media/thumbs/' . $this->filePath, $path);
902+
903+
return [
904+
'fs' => $fs,
905+
'url' => $url,
906+
];
907+
} catch (\Exception $e) {
908+
throw new InvalidPathException($e->getMessage());
909+
}
910+
}
911+
912+
/**
913+
* Returns the path for the thumbnail of the given image.
914+
* If the thumbnail does not exist, it will be created.
915+
*
916+
* @param string $path The path of the image
917+
*
918+
* @return string
919+
*
920+
* @since __DEPLOY_VERSION__
921+
*/
922+
private function getThumbnail(string $path): string
923+
{
924+
$thumbnailPaths = $this->getLocalThumbnailPaths($path);
925+
926+
if (empty($thumbnailPaths['fs'])) {
927+
return $this->getUrl($path);
928+
}
929+
930+
$dir = dirname($thumbnailPaths['fs']);
931+
932+
if (!is_dir($dir)) {
933+
Folder::create($dir);
934+
}
935+
936+
// Create the thumbnail
937+
if (!is_file($thumbnailPaths['fs']) && !$this->createThumbnail($path, $thumbnailPaths['fs'])) {
938+
return $this->getUrl($path);
939+
}
940+
941+
return Uri::root() . $this->getEncodedPath($thumbnailPaths['url']);
942+
}
943+
944+
/**
945+
* Create a thumbnail of the given image.
946+
*
947+
* @param string $path The path of the image
948+
* @param string $thumbnailPath The path of the thumbnail
949+
*
950+
* @return boolean
951+
*
952+
* @since __DEPLOY_VERSION__
953+
*/
954+
private function createThumbnail(string $path, string $thumbnailPath): bool
955+
{
956+
$image = new Image($path);
957+
958+
try {
959+
$image->createThumbnails([$this->thumbnailSize[0] . 'x' . $this->thumbnailSize[1]], $image::SCALE_INSIDE, dirname($thumbnailPath), true);
960+
} catch (\Exception $e) {
961+
return false;
962+
}
963+
964+
return true;
965+
}
822966
}

0 commit comments

Comments
 (0)