Implemented virtual path for media module.

First test implementation done in the Helper module.
The upload component is using a bad workaround where the virtual path is defined
in the uri as ?virutalPath= because we are not uploading media files AND form data
at the same time. Therefore the virtualPath can currently only be passed in the get/uri data.
This commit is contained in:
Dennis Eichhorn 2019-05-30 19:13:11 +02:00
parent 753b37b0b8
commit 70fdff2302
8 changed files with 132 additions and 17 deletions

View File

@ -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);
}
}

View File

@ -6,7 +6,7 @@ use phpOMS\Account\PermissionType;
use phpOMS\Router\RouteVerb;
return [
'^.*/media$' => [
'^.*/media(\?+.*|$)' => [
[
'dest' => '\Modules\Media\Controller\ApiController:apiMediaUpload',
'verb' => RouteVerb::SET,

View File

@ -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;

View File

@ -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);
}

View File

@ -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);

View File

@ -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);
}
}

View File

@ -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();
}
}

View File

@ -38,6 +38,7 @@
</div>
<tr><td><label for="iUpload"><?= $this->getHtml('Upload', 'Media') ?></label>
<tr><td>
<input type="hidden" name="virtualPath" form="<?= $this->form; ?>" value="<?= $this->virtualPath; ?>">
<input type="file" id="iUpload" name="upload" form="<?= $this->form; ?>" multiple>
<input form="<?= $this->form; ?>" type="hidden" name="media-list"><td>
</table>