1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-12-21 13:00:56 +01:00

Modularize file transforms and provide a "transforms" UI

Summary:
Ref T7707. Available transforms are currently relatively hard-coded and don't really have any support UI.

Modularize them so we can build some support UI.

This doesn't actually //use// any of the new stuff yet: I want to make a clean cutover once I fix the aspect ratio stuff so I can pick up a cachekey/URI change as a side effect.

Test Plan: {F400524}

Reviewers: btrahan

Reviewed By: btrahan

Subscribers: chad, epriestley

Maniphest Tasks: T7707

Differential Revision: https://secure.phabricator.com/D12808
This commit is contained in:
epriestley 2015-05-12 06:16:18 -07:00
parent ae32d1afb8
commit c998e44b5a
9 changed files with 319 additions and 16 deletions

View file

@ -1860,6 +1860,7 @@ phutil_register_library_map(array(
'PhabricatorFileFilePHIDType' => 'applications/files/phid/PhabricatorFileFilePHIDType.php',
'PhabricatorFileHasObjectEdgeType' => 'applications/files/edge/PhabricatorFileHasObjectEdgeType.php',
'PhabricatorFileImageMacro' => 'applications/macro/storage/PhabricatorFileImageMacro.php',
'PhabricatorFileImageTransform' => 'applications/files/transform/PhabricatorFileImageTransform.php',
'PhabricatorFileInfoController' => 'applications/files/controller/PhabricatorFileInfoController.php',
'PhabricatorFileLinkListView' => 'view/layout/PhabricatorFileLinkListView.php',
'PhabricatorFileLinkView' => 'view/layout/PhabricatorFileLinkView.php',
@ -1873,10 +1874,13 @@ phutil_register_library_map(array(
'PhabricatorFileTemporaryGarbageCollector' => 'applications/files/garbagecollector/PhabricatorFileTemporaryGarbageCollector.php',
'PhabricatorFileTestCase' => 'applications/files/storage/__tests__/PhabricatorFileTestCase.php',
'PhabricatorFileTestDataGenerator' => 'applications/files/lipsum/PhabricatorFileTestDataGenerator.php',
'PhabricatorFileThumbnailTransform' => 'applications/files/transform/PhabricatorFileThumbnailTransform.php',
'PhabricatorFileTransaction' => 'applications/files/storage/PhabricatorFileTransaction.php',
'PhabricatorFileTransactionComment' => 'applications/files/storage/PhabricatorFileTransactionComment.php',
'PhabricatorFileTransactionQuery' => 'applications/files/query/PhabricatorFileTransactionQuery.php',
'PhabricatorFileTransform' => 'applications/files/transform/PhabricatorFileTransform.php',
'PhabricatorFileTransformController' => 'applications/files/controller/PhabricatorFileTransformController.php',
'PhabricatorFileTransformListController' => 'applications/files/controller/PhabricatorFileTransformListController.php',
'PhabricatorFileUploadController' => 'applications/files/controller/PhabricatorFileUploadController.php',
'PhabricatorFileUploadDialogController' => 'applications/files/controller/PhabricatorFileUploadDialogController.php',
'PhabricatorFileUploadException' => 'applications/files/exception/PhabricatorFileUploadException.php',
@ -5262,6 +5266,7 @@ phutil_register_library_map(array(
'PhabricatorFlaggableInterface',
'PhabricatorPolicyInterface',
),
'PhabricatorFileImageTransform' => 'PhabricatorFileTransform',
'PhabricatorFileInfoController' => 'PhabricatorFileController',
'PhabricatorFileLinkListView' => 'AphrontView',
'PhabricatorFileLinkView' => 'AphrontView',
@ -5274,10 +5279,13 @@ phutil_register_library_map(array(
'PhabricatorFileTemporaryGarbageCollector' => 'PhabricatorGarbageCollector',
'PhabricatorFileTestCase' => 'PhabricatorTestCase',
'PhabricatorFileTestDataGenerator' => 'PhabricatorTestDataGenerator',
'PhabricatorFileThumbnailTransform' => 'PhabricatorFileImageTransform',
'PhabricatorFileTransaction' => 'PhabricatorApplicationTransaction',
'PhabricatorFileTransactionComment' => 'PhabricatorApplicationTransactionComment',
'PhabricatorFileTransactionQuery' => 'PhabricatorApplicationTransactionQuery',
'PhabricatorFileTransform' => 'Phobject',
'PhabricatorFileTransformController' => 'PhabricatorFileController',
'PhabricatorFileTransformListController' => 'PhabricatorFileController',
'PhabricatorFileUploadController' => 'PhabricatorFileController',
'PhabricatorFileUploadDialogController' => 'PhabricatorFileController',
'PhabricatorFileUploadException' => 'Exception',

View file

@ -91,6 +91,8 @@ final class PhabricatorFilesApplication extends PhabricatorApplication {
'(?P<phid>[^/]+)/'.
'(?P<key>[^/]+)/'
=> 'PhabricatorFileTransformController',
'transforms/(?P<id>[1-9]\d*)/' =>
'PhabricatorFileTransformListController',
'uploaddialog/' => 'PhabricatorFileUploadDialogController',
'download/(?P<phid>[^/]+)/' => 'PhabricatorFileDialogController',
),

View file

@ -170,6 +170,12 @@ final class PhabricatorFileInfoController extends PhabricatorFileController {
->setWorkflow(true)
->setDisabled(!$can_edit));
$view->addAction(
id(new PhabricatorActionView())
->setName(pht('View Transforms'))
->setIcon('fa-crop')
->setHref($this->getApplicationURI("/transforms/{$id}/")));
return $view;
}
@ -267,7 +273,6 @@ final class PhabricatorFileInfoController extends PhabricatorFileController {
$user->renderHandleList($phids));
}
if ($file->isViewableImage()) {
$image = phutil_tag(
'img',

View file

@ -48,21 +48,33 @@ final class PhabricatorFileTransformController
// protection.
$unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
switch ($transform) {
case 'thumb-profile':
$xformed_file = $this->executeThumbTransform($file, 50, 50);
break;
case 'thumb-280x210':
$xformed_file = $this->executeThumbTransform($file, 280, 210);
break;
case 'preview-100':
$xformed_file = $this->executePreviewTransform($file, 100);
break;
case 'preview-220':
$xformed_file = $this->executePreviewTransform($file, 220);
break;
default:
return new Aphront400Response();
$xformed_file = null;
$xforms = PhabricatorFileTransform::getAllTransforms();
if (isset($xforms[$transform])) {
$xform = $xforms[$transform];
if ($xform->canApplyTransform($file)) {
$xformed_file = $xforms[$transform]->applyTransform($file);
}
}
if (!$xformed_file) {
switch ($transform) {
case 'thumb-profile':
$xformed_file = $this->executeThumbTransform($file, 50, 50);
break;
case 'thumb-280x210':
$xformed_file = $this->executeThumbTransform($file, 280, 210);
break;
case 'preview-100':
$xformed_file = $this->executePreviewTransform($file, 100);
break;
case 'preview-220':
$xformed_file = $this->executePreviewTransform($file, 220);
break;
default:
return new Aphront400Response();
}
}
if (!$xformed_file) {

View file

@ -0,0 +1,137 @@
<?php
final class PhabricatorFileTransformListController
extends PhabricatorFileController {
public function shouldAllowPublic() {
return true;
}
public function handleRequest(AphrontRequest $request) {
$viewer = $this->getViewer();
$file = id(new PhabricatorFileQuery())
->setViewer($viewer)
->withIDs(array($request->getURIData('id')))
->executeOne();
if (!$file) {
return new Aphront404Response();
}
$monogram = $file->getMonogram();
$xdst = id(new PhabricatorTransformedFile())->loadAllWhere(
'transformedPHID = %s',
$file->getPHID());
$dst_rows = array();
foreach ($xdst as $source) {
$dst_rows[] = array(
$source->getTransform(),
$viewer->renderHandle($source->getOriginalPHID()),
);
}
$dst_table = id(new AphrontTableView($dst_rows))
->setHeaders(
array(
pht('Key'),
pht('Source'),
))
->setColumnClasses(
array(
'',
'wide',
))
->setNoDataString(
pht(
'This file was not created by transforming another file.'));
$xsrc = id(new PhabricatorTransformedFile())->loadAllWhere(
'originalPHID = %s',
$file->getPHID());
$xsrc = mpull($xsrc, 'getTransformedPHID', 'getTransform');
$src_rows = array();
$xforms = PhabricatorFileTransform::getAllTransforms();
foreach ($xforms as $xform) {
$dst_phid = idx($xsrc, $xform->getTransformKey());
if ($xform->canApplyTransform($file)) {
$can_apply = pht('Yes');
$view_href = $file->getURIForTransform($xform);
if ($dst_phid) {
$view_text = pht('View Transform');
} else {
$view_text = pht('Generate Transform');
}
$view_link = phutil_tag(
'a',
array(
'class' => 'small grey button',
'href' => $view_href,
),
$view_text);
} else {
$can_apply = phutil_tag('em', array(), pht('No'));
$view_link = phutil_tag('em', array(), pht('None'));
}
if ($dst_phid) {
$dst_link = $viewer->renderHandle($dst_phid);
} else {
$dst_link = phutil_tag('em', array(), pht('None'));
}
$src_rows[] = array(
$xform->getTransformName(),
$xform->getTransformKey(),
$can_apply,
$dst_link,
$view_link,
);
}
$src_table = id(new AphrontTableView($src_rows))
->setHeaders(
array(
pht('Name'),
pht('Key'),
pht('Supported'),
pht('Transform'),
pht('View'),
))
->setColumnClasses(
array(
'wide',
'',
'',
'',
'action',
));
$crumbs = $this->buildApplicationCrumbs();
$crumbs->addTextCrumb($monogram, '/'.$monogram);
$crumbs->addTextCrumb(pht('Transforms'));
$dst_box = id(new PHUIObjectBoxView())
->setHeaderText(pht('File Sources'))
->appendChild($dst_table);
$src_box = id(new PHUIObjectBoxView())
->setHeaderText(pht('Available Transforms'))
->appendChild($src_table);
return $this->buildApplicationPage(
array(
$crumbs,
$dst_box,
$src_box,
),
array(
'title' => array(
pht('%s %s', $monogram, $file->getName()),
pht('Tranforms'),
),
));
}
}

View file

@ -760,6 +760,10 @@ final class PhabricatorFile extends PhabricatorFileDAO
return (string) $uri;
}
public function getURIForTransform(PhabricatorFileTransform $transform) {
return $this->getTransformedURI($transform->getTransformKey());
}
private function getTransformedURI($transform) {
$parts = array();
$parts[] = 'file';

View file

@ -0,0 +1,17 @@
<?php
abstract class PhabricatorFileImageTransform extends PhabricatorFileTransform {
public function canApplyTransform(PhabricatorFile $file) {
if (!$file->isViewableImage()) {
return false;
}
if (!$file->isTransformableImage()) {
return false;
}
return true;
}
}

View file

@ -0,0 +1,74 @@
<?php
final class PhabricatorFileThumbnailTransform
extends PhabricatorFileImageTransform {
const TRANSFORM_PROFILE = 'profile';
const TRANSFORM_PINBOARD = 'pinboard';
const TRANSFORM_THUMBGRID = 'thumbgrid';
const TRANSFORM_PREVIEW = 'preview';
private $name;
private $key;
private $dstX;
private $dstY;
public function setName($name) {
$this->name = $name;
return $this;
}
public function setKey($key) {
$this->key = $key;
return $this;
}
public function setDimensions($x, $y) {
$this->dstX = $x;
$this->dstY = $y;
return $this;
}
public function getTransformName() {
return $this->name;
}
public function getTransformKey() {
return $this->key;
}
public function generateTransforms() {
return array(
id(new PhabricatorFileThumbnailTransform())
->setName(pht("Profile (100px \xC3\x97 100px)"))
->setKey(self::TRANSFORM_PROFILE)
->setDimensions(100, 100),
id(new PhabricatorFileThumbnailTransform())
->setName(pht("Pinboard (280px \xC3\x97 210px)"))
->setKey(self::TRANSFORM_PINBOARD)
->setDimensions(280, 210),
id(new PhabricatorFileThumbnailTransform())
->setName(pht('Thumbgrid (100px)'))
->setKey(self::TRANSFORM_THUMBGRID)
->setDimensions(100, null),
id(new PhabricatorFileThumbnailTransform())
->setName(pht('Preview (220px)'))
->setKey(self::TRANSFORM_PREVIEW)
->setDimensions(220, null),
);
}
public function applyTransform(PhabricatorFile $file) {
$x = $this->dstX;
$y = $this->dstY;
$xformer = new PhabricatorImageTransformer();
if ($y === null) {
return $xformer->executePreviewTransform($file, $x);
} else {
return $xformer->executeThumbTransform($file, $x, $y);
}
}
}

View file

@ -0,0 +1,44 @@
<?php
abstract class PhabricatorFileTransform extends Phobject {
abstract public function getTransformName();
abstract public function getTransformKey();
abstract public function canApplyTransform(PhabricatorFile $file);
abstract public function applyTransform(PhabricatorFile $file);
public function generateTransforms() {
return array($this);
}
public static function getAllTransforms() {
static $map;
if ($map === null) {
$xforms = id(new PhutilSymbolLoader())
->setAncestorClass(__CLASS__)
->loadObjects();
$result = array();
foreach ($xforms as $xform_template) {
foreach ($xform_template->generateTransforms() as $xform) {
$key = $xform->getTransformKey();
if (isset($result[$key])) {
throw new Exception(
pht(
'Two %s objects define the same transform key ("%s"), but '.
'each transform must have a unique key.',
__CLASS__,
$key));
}
$result[$key] = $xform;
}
}
$map = $result;
}
return $map;
}
}