From 1e0cf2fabc20fd430a0f9bcc14d8121d9a0d9b9b Mon Sep 17 00:00:00 2001 From: Dennis Eichhorn Date: Sun, 1 Nov 2020 21:23:33 +0100 Subject: [PATCH] rename virtual path and allow loading by virtual path --- Controller/BackendController.php | 7 +- Models/Collection.php | 8 +++ Models/CollectionMapper.php | 105 +++++++++++++++++++++++++++++ Models/Media.php | 8 +++ Models/MediaMapper.php | 1 + Theme/Backend/media-single.tpl.php | 4 +- 6 files changed, 128 insertions(+), 5 deletions(-) diff --git a/Controller/BackendController.php b/Controller/BackendController.php index 1b25940..16b6ebf 100755 --- a/Controller/BackendController.php +++ b/Controller/BackendController.php @@ -107,12 +107,11 @@ final class BackendController extends Controller $view = new View($this->app->l11nManager, $request, $response); $view->setTemplate('/Modules/Media/Theme/Backend/media-list'); - $path = (string) ($request->getData('path') ?? '/'); + $path = \str_replace('+', ' ', (string) ($request->getData('path') ?? '/')); /** @var Media[] $media */ - $media = MediaMapper::getByVirtualPath(\str_replace('+', ' ', $path)); - - $collection = CollectionMapper::getParentCollection(\str_replace('+', ' ', $path)); + $media = MediaMapper::getByVirtualPath($path); + $collection = CollectionMapper::getParentCollection($path); if (\is_array($collection) && \is_dir(__DIR__ . '/../Files' . $path)) { $collection = new Collection(); diff --git a/Models/Collection.php b/Models/Collection.php index 57c2968..034a9d4 100755 --- a/Models/Collection.php +++ b/Models/Collection.php @@ -40,6 +40,14 @@ class Collection extends Media implements \Iterator */ protected string $extension = 'collection'; + /** + * Is collection. + * + * @var int + * @since 1.0.0 + */ + protected int $collection = 1; + /** * Constructor. * diff --git a/Models/CollectionMapper.php b/Models/CollectionMapper.php index 63081f9..517be0a 100755 --- a/Models/CollectionMapper.php +++ b/Models/CollectionMapper.php @@ -14,6 +14,9 @@ declare(strict_types=1); namespace Modules\Media\Models; +use phpOMS\DataStorage\Database\RelationType; +use Modules\Admin\Models\Account; + /** * Mapper class. * @@ -70,4 +73,106 @@ final class CollectionMapper extends MediaMapper * @since 1.0.0 */ protected static string $primaryField = 'media_id'; + + /** + * Get media based on virtual path. + * + * The virtual path is equivalent to the directory path on a file system. + * + * A media model also has a file path, this however doesn't have to be the same as the virtual path + * and in fact most of the time it is different. This is because the location on a hard drive or web + * drive should not have any impact on the media file/media structure in the application. + * + * As a result media files are structured by virutal path in the app, by file path on the file system + * and by Collections which can have sub-collections as well. Collections allow to reference files + * in a different virtual path and are therfore similar to "symlinks", except that they don't reference + * a file but create a new virtual media model which groups other media models together in a new virtual + * path if so desired without deleting or moving the orginal media files. + * + * @param string $virtualPath Virtual path + * @param bool $hidden Get hidden files + * + * @return array + * + * @since 1.0.0 + */ + public static function getByVirtualPath(string $virtualPath = '/', bool $hidden = false) : array + { + $depth = 3; + $query = self::getQuery(); + $query->where(self::$table . '_' . $depth . '.media_virtual', '=', $virtualPath); + $query->where(self::$table . '_' . $depth . '.media_collection', '=', 1); + + if ($hidden === false) { + $query->andWhere(self::$table . '_' . $depth . '.media_hidden', '=', (int) $hidden); + } + + return self::getAllByQuery($query, RelationType::ALL, $depth); + } + + /** + * Get collections and optionally hard drive directories. + * + * @param string $virtualPath Virtual path + * @param bool $showDirectories Show local hard drive directories + * + * @return array + * + * @since 1.0.0 + */ + public static function getCollectionsByPath(string $path, bool $showDirectories = false) : array + { + $collection = CollectionMapper::getByVirtualPath($path); + $parent = []; + + if ($showDirectories) { + $parent = CollectionMapper::getParentCollection($path); + if (\is_array($parent) && \is_dir(__DIR__ . '/../../Media/Files' . $path)) { + $parent = new Collection(); + $parent->setName(\basename($path)); + $parent->setVirtualPath(\dirname($path)); + $parent->setPath(\dirname($path)); + $parent->setAbsolute(false); + } + + if ($parent instanceof Collection) { + $collection += $parent->getSources(); + + /** @var string[] $glob */ + $glob = $parent->isAbsolute() + ? $parent->getPath() . '/' . $parent->getName() . '/*' + : \glob(__DIR__ . '/../Files/' . \rtrim($parent->getPath(), '/') . '/' . $parent->getName() . '/*'); + $glob = $glob === false ? [] : $glob; + + foreach ($glob as $file) { + if (!\is_dir($file)) { + continue; + } + + foreach ($collection as $obj) { + if (($obj->getExtension() !== 'collection' + && !empty($obj->getExtension()) + && $obj->getName() . '.' . $obj->getExtension() === \basename($file)) + || ($obj->getExtension() === 'collection' + && $obj->getName() === \basename($file)) + ) { + continue 2; + } + } + + $pathinfo = \pathinfo($file); + + $localMedia = new Collection(); + $localMedia->setName($pathinfo['filename']); + $localMedia->setExtension(\is_dir($file) ? 'collection' : $pathinfo['extension'] ?? ''); + $localMedia->setVirtualPath($path); + $localMedia->setCreatedBy(new Account()); + + $collection[] = $localMedia; + } + } + } + + return [$collection, $parent]; + } } diff --git a/Models/Media.php b/Models/Media.php index 84ff3f4..24213a4 100755 --- a/Models/Media.php +++ b/Models/Media.php @@ -155,6 +155,14 @@ class Media implements \JsonSerializable */ protected bool $hidden = false; + /** + * Is collection. + * + * @var int + * @since 1.0.0 + */ + protected int $collection = 0; + /** * Constructor. * diff --git a/Models/MediaMapper.php b/Models/MediaMapper.php index 784c905..1c0d024 100755 --- a/Models/MediaMapper.php +++ b/Models/MediaMapper.php @@ -49,6 +49,7 @@ class MediaMapper extends DataMapperAbstract 'media_password' => ['name' => 'media_password', 'type' => 'string', 'internal' => 'password'], 'media_extension' => ['name' => 'media_extension', 'type' => 'string', 'internal' => 'extension'], 'media_size' => ['name' => 'media_size', 'type' => 'int', 'internal' => 'size'], + 'media_collection' => ['name' => 'media_collection', 'type' => 'int', 'internal' => 'collection'], 'media_created_by' => ['name' => 'media_created_by', 'type' => 'int', 'internal' => 'createdBy', 'readonly' => true], 'media_created_at' => ['name' => 'media_created_at', 'type' => 'DateTimeImmutable', 'internal' => 'createdAt', 'readonly' => true], ]; diff --git a/Theme/Backend/media-single.tpl.php b/Theme/Backend/media-single.tpl.php index 287ceb1..cd1e3b2 100755 --- a/Theme/Backend/media-single.tpl.php +++ b/Theme/Backend/media-single.tpl.php @@ -46,7 +46,9 @@ echo $this->getData('nav')->render(); getHtml('Name'); ?>printHtml($media->getName()); ?> getHtml('Size'); ?>printHtml($media->getSize()); ?> getHtml('Created'); ?>printHtml($media->getCreatedAt()->format('Y-m-d')); ?> - getHtml('Creator'); ?>printHtml($media->getCreatedBy()->getName2() . ', ' . $media->getCreatedBy()->getName1()); ?> + getHtml('Creator'); ?>printHtml( + \ltrim($media->getCreatedBy()->getName2() . ', ' . $media->getCreatedBy()->getName1(), ', ') + ); ?> getHtml('Description'); ?> getDescription(); ?>