diff --git a/Admin/Installer.php b/Admin/Installer.php index 8de2f8b..f69d6dc 100644 --- a/Admin/Installer.php +++ b/Admin/Installer.php @@ -16,6 +16,11 @@ namespace Modules\Media\Admin; use phpOMS\Module\InstallerAbstract; +use phpOMS\DataStorage\Database\DatabasePool; +use phpOMS\System\File\PathException; +use Modules\Media\Models\Collection; +use Modules\Media\Models\CollectionMapper; + /** * Installer class. * @@ -26,4 +31,61 @@ use phpOMS\Module\InstallerAbstract; */ class Installer extends InstallerAbstract { + /** + * Install data from providing modules. + * + * @param DatabasePool $dbPool Database pool + * @param array $data Module info + * + * @return void + * + * @throws PathException This exception is thrown if the Navigation install file couldn't be found + * @throws \Exception This exception is thrown if the Navigation install file is invalid json + * + * @since 1.0.0 + */ + public static function installExternal(DatabasePool $dbPool, array $data) : void + { + try { + $dbPool->get()->con->query('select 1 from `' . $dbPool->get()->prefix . 'media`'); + } catch (\Exception $e) { + return; + } + + $mediaFile = \file_get_contents($data['path'] ?? ''); + + if ($mediaFile === false) { + throw new PathException($data['path'] ?? ''); + } + + $mediaData = \json_decode($mediaFile, true); + + if ($mediaData === false) { + throw new \Exception(); + } + + foreach ($mediaData as $media) { + self::installMedia($dbPool, $media); + } + } + + /** + * Install media element. + * + * @param DatabasePool $dbPool Database instance + * @param array $data Media info + * + * @return void + * + * @since 1.0.0 + */ + private static function installMedia($dbPool, $data) : void + { + $collection = new Collection(); + $collection->setName((string) $data['name'] ?? ''); + $collection->setVirtualPath((string) $data['virtualPath'] ?? '/'); + $collection->setCreatedBy((int) $data['user'] ?? 1); + + CollectionMapper::create($collection); + } } diff --git a/Admin/Routes/Web/Api.php b/Admin/Routes/Web/Api.php index fd07fdc..034ddcb 100644 --- a/Admin/Routes/Web/Api.php +++ b/Admin/Routes/Web/Api.php @@ -6,7 +6,7 @@ use phpOMS\Account\PermissionType; use phpOMS\Router\RouteVerb; return [ - '^.*/media$' => [ + '^.*/media(\?+.*|$)' => [ [ 'dest' => '\Modules\Media\Controller\ApiController:apiMediaUpload', 'verb' => RouteVerb::SET, diff --git a/Controller.js b/Controller.js index 3c57d82..1cc7e0e 100644 --- a/Controller.js +++ b/Controller.js @@ -1,9 +1,7 @@ import { Autoloader } from '../../jsOMS/Autoloader.js'; -import { Application } from '../../Web/Backend/js/backend.js'; -import { Upload } from './Models/Upload.js'; import { NotificationMessage } from '../../jsOMS/Message/Notification/NotificationMessage.js'; -import { NotificationLevel } from '../../jsOMS/Message/Notification/NotificationLevel.js'; import { NotificationType } from '../../jsOMS/Message/Notification/NotificationType.js'; +import { Upload } from './Models/Upload.js'; Autoloader.defineNamespace('jsOMS.Modules'); @@ -50,7 +48,7 @@ jsOMS.Modules.Media = class { /** global: jsOMS */ const fileFields = document.querySelectorAll( '#' + e.id + ' input[type=file], ' - + 'input[form=' + e.id + '][type=file]' + + 'input[form="' + e.id + '"][type=file]' ); const uploader = new Upload(self.app.responseManager); @@ -62,12 +60,17 @@ jsOMS.Modules.Media = class { document.querySelector( '#' + e.id + ' input[type=file]+input[type=hidden], ' - + 'input[form=' + e.id + '][type=file]+input[type=hidden]' + + 'input[form="' + e.id + '"][type=file]+input[type=hidden]' ).value = response[0].response; self.app.eventManager.trigger(form.id, requestId); }); - uploader.setUri('api/media'); + const virtualPath = document.querySelector('input[form="' + e.id + '"][name="virtualPath"]'); + if (virtualPath !== null) { + uploader.setUri('api/media?virtualPath=' + virtualPath.value); + } else { + uploader.setUri('api/media'); + } const length = fileFields.length; let fileLength = 0; diff --git a/Controller/ApiController.php b/Controller/ApiController.php index b8bd4ae..8fe1a7d 100644 --- a/Controller/ApiController.php +++ b/Controller/ApiController.php @@ -79,7 +79,8 @@ final class ApiController extends Controller $request->getData('name') ?? '', $request->getFiles(), $request->getHeader()->getAccount(), - (string) ($request->getData('path') ?? __DIR__ . '/../../../Modules/Media/Files') + (string) ($request->getData('path') ?? __DIR__ . '/../../../Modules/Media/Files'), + (string) ($request->getData('virtualPath') ?? '/') ); $ids = []; @@ -100,7 +101,13 @@ final class ApiController extends Controller * * @since 1.0.0 */ - public function uploadFiles(string $name, array $files, int $account, string $basePath = 'Modules/Media/Files') : array + public function uploadFiles( + string $name, + array $files, + int $account, + string $basePath = 'Modules/Media/Files', + string $virtualPath = '/' + ) : array { $mediaCreated = []; @@ -109,7 +116,7 @@ final class ApiController extends Controller $upload->setOutputDir(self::createMediaPath($basePath)); $status = $upload->upload($files, $name); - $mediaCreated = self::createDbEntries($status, $account); + $mediaCreated = self::createDbEntries($status, $account, $virtualPath); } return $mediaCreated; @@ -138,12 +145,12 @@ final class ApiController extends Controller * * @since 1.0.0 */ - public static function createDbEntries(array $status, int $account) : array + public static function createDbEntries(array $status, int $account, string $virtualPath = '/') : array { $mediaCreated = []; foreach ($status as $uFile) { - if (($created = self::createDbEntry($uFile, $account)) !== null) { + if (($created = self::createDbEntry($uFile, $account, $virtualPath)) !== null) { $mediaCreated[] = $created; } } @@ -151,7 +158,7 @@ final class ApiController extends Controller return $mediaCreated; } - public static function createDbEntry(array $status, int $account) : ?Media + public static function createDbEntry(array $status, int $account, string $virtualPath = '/') : ?Media { $media = null; @@ -163,6 +170,7 @@ final class ApiController extends Controller $media->setSize($status['size']); $media->setCreatedBy($account); $media->setExtension($status['extension']); + $media->setVirtualPath($virtualPath); MediaMapper::create($media); } diff --git a/Controller/BackendController.php b/Controller/BackendController.php index a20f716..3c4197e 100644 --- a/Controller/BackendController.php +++ b/Controller/BackendController.php @@ -117,7 +117,7 @@ final class BackendController extends Controller $view->setTemplate('/Modules/Media/Theme/Backend/media-list'); $view->addData('nav', $this->app->moduleManager->get('Navigation')->createNavigationMid(1000401001, $request, $response)); - $media = MediaMapper::getNewest(25); + $media = MediaMapper::getByVirtualPath('/'); $view->addData('media', $media); return $view; @@ -139,9 +139,18 @@ final class BackendController extends Controller $view->setTemplate('/Modules/Media/Theme/Backend/media-single'); $view->addData('nav', $this->app->moduleManager->get('Navigation')->createNavigationMid(1000401001, $request, $response)); - $media = MediaMapper::get($request->getData('id')); + $media = MediaMapper::get((int) $request->getData('id')); if ($media->getExtension() === 'collection') { - $media = CollectionMapper::get($media->getId()); + //$media = CollectionMapper::get($media->getId()); + $media = MediaMapper::getByVirtualPath( + $media->getVirtualPath() . ($media->getVirtualPath() !== '/' ? '/' : '') . $media->getName() + ); + + $view->setTemplate('/Modules/Media/Theme/Backend/media-list'); + + // todo: currently the $media list only contains elements from the path but it should also include all + // the collection elements which might be the same but maybe some are not in the same virtualPath!!! + // the *unique* merge should be done through the ids! } $view->addData('media', $media); diff --git a/Models/MediaMapper.php b/Models/MediaMapper.php index 56866b5..b9375fd 100644 --- a/Models/MediaMapper.php +++ b/Models/MediaMapper.php @@ -86,4 +86,33 @@ class MediaMapper extends DataMapperAbstract * @since 1.0.0 */ protected static $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 + * + * @return array + * + * @since 1.0.0 + */ + public static function getByVirtualPath(string $virtualPath = '/') : array + { + $query = self::getQuery(); + $query->where(self::$table . '.media_virtual', '=', $virtualPath); + + return self::getAllByQuery($query); + } } diff --git a/Theme/Backend/Components/Upload/BaseView.php b/Theme/Backend/Components/Upload/BaseView.php index 0dd3ed6..8ed8cad 100644 --- a/Theme/Backend/Components/Upload/BaseView.php +++ b/Theme/Backend/Components/Upload/BaseView.php @@ -32,6 +32,8 @@ class BaseView extends View { protected $form = ''; + protected $virtualPath = ''; + /** * {@inheritdoc} */ @@ -46,7 +48,8 @@ class BaseView extends View */ public function render(...$data) : string { - $this->form = $data[0]; + $this->form = $data[0]; + $this->virtualPath = $data[1] ?? '/'; return parent::render(); } } diff --git a/Theme/Backend/Components/Upload/upload.tpl.php b/Theme/Backend/Components/Upload/upload.tpl.php index 94f0351..0b65502 100644 --- a/Theme/Backend/Components/Upload/upload.tpl.php +++ b/Theme/Backend/Components/Upload/upload.tpl.php @@ -38,6 +38,7 @@ +