Get file and folder metadata for media items using a single network call if possible (#5046)

Co-Authored-By: Ben Thomson <ben@abweb.com.au>. Fixes #5045.
This commit is contained in:
Dieter Holvoet 2020-05-26 11:20:41 +02:00 committed by GitHub
parent 71d579b947
commit 40d8bb453e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 93 additions and 20 deletions

View File

@ -595,14 +595,14 @@ class MediaLibrary
} }
/** /**
* Initializes a library item from a path and item type. * Initializes a library item from file metadata and item type.
* @param string $path Specifies the item path relative to the storage disk root. * @param array $item Specifies the file metadata as returned by the storage adapter.
* @param string $itemType Specifies the item type. * @param string $itemType Specifies the item type.
* @return mixed Returns the MediaLibraryItem object or NULL if the item is not visible. * @return mixed Returns the MediaLibraryItem object or NULL if the item is not visible.
*/ */
protected function initLibraryItem($path, $itemType) protected function initLibraryItem($item, $itemType)
{ {
$relativePath = $this->getMediaRelativePath($path); $relativePath = $this->getMediaRelativePath($item['path']);
if (!$this->isVisible($relativePath)) { if (!$this->isVisible($relativePath)) {
return; return;
@ -612,9 +612,11 @@ class MediaLibrary
* S3 doesn't allow getting the last modified timestamp for folders, * S3 doesn't allow getting the last modified timestamp for folders,
* so this feature is disabled - folders timestamp is always NULL. * so this feature is disabled - folders timestamp is always NULL.
*/ */
$lastModified = $itemType == MediaLibraryItem::TYPE_FILE if ($itemType === MediaLibraryItem::TYPE_FILE) {
? $this->getStorageDisk()->lastModified($path) $lastModified = $item['timestamp'] ?? $this->getStorageDisk()->lastModified($item['path']);
: null; } else {
$lastModified = null;
}
/* /*
* The folder size (number of items) doesn't respect filters. That * The folder size (number of items) doesn't respect filters. That
@ -622,9 +624,11 @@ class MediaLibrary
* zero items for a folder that contains files not visible with a * zero items for a folder that contains files not visible with a
* currently applied filter. -ab * currently applied filter. -ab
*/ */
$size = $itemType == MediaLibraryItem::TYPE_FILE if ($itemType === MediaLibraryItem::TYPE_FILE) {
? $this->getStorageDisk()->size($path) $size = $item['size'] ?? $this->getStorageDisk()->size($item['path']);
: $this->getFolderItemCount($path); } else {
$size = $this->getFolderItemCount($item['path']);
}
$publicUrl = $this->getPathUrl($relativePath); $publicUrl = $this->getPathUrl($relativePath);
@ -665,17 +669,20 @@ class MediaLibrary
'folders' => [] 'folders' => []
]; ];
$files = $this->getStorageDisk()->files($fullFolderPath); $contents = $this->getStorageDisk()->listContents($fullFolderPath);
foreach ($files as $file) {
if ($libraryItem = $this->initLibraryItem($file, MediaLibraryItem::TYPE_FILE)) { foreach ($contents as $content) {
$result['files'][] = $libraryItem; if ($content['type'] === 'file') {
} $type = MediaLibraryItem::TYPE_FILE;
$key = 'files';
} elseif ($content['type'] === 'dir') {
$type = MediaLibraryItem::TYPE_FOLDER;
$key = 'folders';
} }
$folders = $this->getStorageDisk()->directories($fullFolderPath); $libraryItem = $this->initLibraryItem($content, $type);
foreach ($folders as $folder) { if (!is_null($libraryItem)) {
if ($libraryItem = $this->initLibraryItem($folder, MediaLibraryItem::TYPE_FOLDER)) { $result[$key][] = $libraryItem;
$result['folders'][] = $libraryItem;
} }
} }

1
tests/fixtures/media/text.txt vendored Normal file
View File

@ -0,0 +1 @@
THIS IS A TEXT DOCUMENT

View File

@ -4,6 +4,12 @@ use System\Classes\MediaLibrary;
class MediaLibraryTest extends TestCase // @codingStandardsIgnoreLine class MediaLibraryTest extends TestCase // @codingStandardsIgnoreLine
{ {
protected function tearDown()
{
$this->removeMedia();
parent::tearDown();
}
public function invalidPathsProvider() public function invalidPathsProvider()
{ {
return [ return [
@ -62,4 +68,63 @@ class MediaLibraryTest extends TestCase // @codingStandardsIgnoreLine
$result = MediaLibrary::validatePath($path); $result = MediaLibrary::validatePath($path);
$this->assertInternalType('string', $result); $this->assertInternalType('string', $result);
} }
public function testListFolderContents()
{
$this->setUpStorage();
$this->copyMedia();
$contents = MediaLibrary::instance()->listFolderContents();
$this->assertNotEmpty($contents, 'Media library item is not discovered');
$item = reset($contents);
$this->assertAttributeEquals('file', 'type', $item, 'Media library item does not have the right type');
$this->assertAttributeEquals('/text.txt', 'path', $item, 'Media library item does not have the right path');
$this->assertAttributeNotEmpty('lastModified', $item, 'Media library item last modified is empty');
$this->assertAttributeNotEmpty('size', $item, 'Media library item size is empty');
}
protected function setUpStorage()
{
$this->app->useStoragePath(base_path('storage/temp'));
config(['filesystems.disks.test_local' => [
'driver' => 'local',
'root' => storage_path('app'),
]]);
config(['cms.storage.media' => [
'disk' => 'test_local',
'folder' => 'media',
'path' => '/storage/app/media',
]]);
}
protected function copyMedia()
{
$mediaPath = storage_path('app/media');
if (!is_dir($mediaPath)) {
mkdir($mediaPath, 0777, true);
}
foreach (glob(base_path('tests/fixtures/media/*')) as $file) {
$path = pathinfo($file);
copy($file, $mediaPath . DIRECTORY_SEPARATOR . $path['basename']);
}
}
protected function removeMedia()
{
if ($this->app->storagePath() !== base_path('storage/temp')) {
return;
}
foreach (glob(storage_path('app/media/*')) as $file) {
unlink($file);
}
rmdir(storage_path('app/media'));
rmdir(storage_path('app'));
}
} }