Page MenuHomePhabricator

D12808.id30829.diff
No OneTemporary

D12808.id30829.diff

diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php
--- a/src/__phutil_library_map__.php
+++ b/src/__phutil_library_map__.php
@@ -1860,6 +1860,7 @@
'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 @@
'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 @@
'PhabricatorFlaggableInterface',
'PhabricatorPolicyInterface',
),
+ 'PhabricatorFileImageTransform' => 'PhabricatorFileTransform',
'PhabricatorFileInfoController' => 'PhabricatorFileController',
'PhabricatorFileLinkListView' => 'AphrontView',
'PhabricatorFileLinkView' => 'AphrontView',
@@ -5274,10 +5279,13 @@
'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',
diff --git a/src/applications/files/application/PhabricatorFilesApplication.php b/src/applications/files/application/PhabricatorFilesApplication.php
--- a/src/applications/files/application/PhabricatorFilesApplication.php
+++ b/src/applications/files/application/PhabricatorFilesApplication.php
@@ -91,6 +91,8 @@
'(?P<phid>[^/]+)/'.
'(?P<key>[^/]+)/'
=> 'PhabricatorFileTransformController',
+ 'transforms/(?P<id>[1-9]\d*)/' =>
+ 'PhabricatorFileTransformListController',
'uploaddialog/' => 'PhabricatorFileUploadDialogController',
'download/(?P<phid>[^/]+)/' => 'PhabricatorFileDialogController',
),
diff --git a/src/applications/files/controller/PhabricatorFileInfoController.php b/src/applications/files/controller/PhabricatorFileInfoController.php
--- a/src/applications/files/controller/PhabricatorFileInfoController.php
+++ b/src/applications/files/controller/PhabricatorFileInfoController.php
@@ -170,6 +170,12 @@
->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 @@
$user->renderHandleList($phids));
}
-
if ($file->isViewableImage()) {
$image = phutil_tag(
'img',
diff --git a/src/applications/files/controller/PhabricatorFileTransformController.php b/src/applications/files/controller/PhabricatorFileTransformController.php
--- a/src/applications/files/controller/PhabricatorFileTransformController.php
+++ b/src/applications/files/controller/PhabricatorFileTransformController.php
@@ -48,21 +48,33 @@
// 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) {
diff --git a/src/applications/files/controller/PhabricatorFileTransformListController.php b/src/applications/files/controller/PhabricatorFileTransformListController.php
new file mode 100644
--- /dev/null
+++ b/src/applications/files/controller/PhabricatorFileTransformListController.php
@@ -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'),
+ ),
+ ));
+ }
+}
diff --git a/src/applications/files/storage/PhabricatorFile.php b/src/applications/files/storage/PhabricatorFile.php
--- a/src/applications/files/storage/PhabricatorFile.php
+++ b/src/applications/files/storage/PhabricatorFile.php
@@ -760,6 +760,10 @@
return (string) $uri;
}
+ public function getURIForTransform(PhabricatorFileTransform $transform) {
+ return $this->getTransformedURI($transform->getTransformKey());
+ }
+
private function getTransformedURI($transform) {
$parts = array();
$parts[] = 'file';
diff --git a/src/applications/files/transform/PhabricatorFileImageTransform.php b/src/applications/files/transform/PhabricatorFileImageTransform.php
new file mode 100644
--- /dev/null
+++ b/src/applications/files/transform/PhabricatorFileImageTransform.php
@@ -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;
+ }
+
+}
diff --git a/src/applications/files/transform/PhabricatorFileThumbnailTransform.php b/src/applications/files/transform/PhabricatorFileThumbnailTransform.php
new file mode 100644
--- /dev/null
+++ b/src/applications/files/transform/PhabricatorFileThumbnailTransform.php
@@ -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);
+ }
+ }
+
+}
diff --git a/src/applications/files/transform/PhabricatorFileTransform.php b/src/applications/files/transform/PhabricatorFileTransform.php
new file mode 100644
--- /dev/null
+++ b/src/applications/files/transform/PhabricatorFileTransform.php
@@ -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;
+ }
+
+}

File Metadata

Mime Type
text/plain
Expires
Fri, Oct 25, 8:06 AM (3 w, 3 d ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
6716487
Default Alt Text
D12808.id30829.diff (15 KB)

Event Timeline