@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.)
hq.recaptime.dev/wiki/Phorge
phorge
phabricator
1<?php
2
3abstract class PhabricatorFileTransform extends Phobject {
4
5 abstract public function getTransformName();
6 abstract public function getTransformKey();
7 abstract public function canApplyTransform(PhabricatorFile $file);
8 abstract public function applyTransform(PhabricatorFile $file);
9
10 public function getDefaultTransform(PhabricatorFile $file) {
11 return null;
12 }
13
14 public function generateTransforms() {
15 return array($this);
16 }
17
18 /**
19 * Get an existing transformed file, or create a new transformed file if no
20 * transformed file already exists.
21 * If a new file is produced, it is connected to the original file
22 * in an explicit way, so, persisting a new 'PhabricatorTransformedFile' row.
23 *
24 * @param PhabricatorFile $file Original file.
25 * You must check yourself if the viewer has
26 * sufficient permissions to see this file.
27 * @return PhabricatorFile Transformed file
28 */
29 public function getOrExecuteTransformExplicit(PhabricatorFile $file) {
30 // Use of omnipotent user is okay here because the assume
31 // the user can see the input $file, and so, its transforms.
32 // See PhabricatorFile::hasAutomaticCapability().
33 $xformed_file = id(new PhabricatorFileQuery())
34 ->setViewer(PhabricatorUser::getOmnipotentUser())
35 ->withTransforms(
36 array(
37 array(
38 'originalPHID' => $file->getPHID(),
39 'transform' => $this->getTransformKey(),
40 ),
41 ))
42 ->executeOne();
43
44 if ($xformed_file) {
45 return $xformed_file;
46 }
47
48 return $this->executeTransformExplicit($file);
49 }
50
51 /**
52 * Create a new transformed file.
53 * This usually causes the creation of a new 'PhabricatorFile'.
54 *
55 * @param PhabricatorFile $file Original file
56 * @return PhabricatorFile Transformed file
57 */
58 public function executeTransform(PhabricatorFile $file) {
59 if ($this->canApplyTransform($file)) {
60 try {
61 return $this->applyTransform($file);
62 } catch (Exception $ex) {
63 // Ignore.
64 }
65 }
66
67 return $this->getDefaultTransform($file);
68 }
69
70 /**
71 * Wrapper of executeTransform() that also persists the relationship
72 * between the original file and the transform, if it makes sense to do so.
73 *
74 * @param PhabricatorFile $file Original file
75 * @return PhabricatorFile Transformed file
76 */
77 public function executeTransformExplicit(PhabricatorFile $file) {
78 // This can be NULL.
79 $xform = $this->executeTransform($file);
80
81 // Connect the original file to its transform, if any.
82 // Skip transforms that are derived from a builtin as cautionary measure:
83 // - Builtins may have a lot of transforms. We don't know if the UX scales.
84 // Example page: /file/transforms/1/
85 // - Tracking builtins gives unclear benefits.
86 if ($xform && !$file->isBuiltin()) {
87 id(new PhabricatorTransformedFile())
88 ->setOriginalPHID($file->getPHID())
89 ->setTransformedPHID($xform->getPHID())
90 ->setTransform($this->getTransformKey())
91 ->save();
92 }
93
94 return $xform;
95 }
96
97 public static function getAllTransforms() {
98 return id(new PhutilClassMapQuery())
99 ->setAncestorClass(self::class)
100 ->setExpandMethod('generateTransforms')
101 ->setUniqueMethod('getTransformKey')
102 ->execute();
103 }
104
105 public static function getTransformByKey($key) {
106 $all = self::getAllTransforms();
107
108 $xform = idx($all, $key);
109 if (!$xform) {
110 throw new Exception(
111 pht(
112 'No file transform with key "%s" exists.',
113 $key));
114 }
115
116 return $xform;
117 }
118
119}