Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F2680339
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Award Token
Flag For Later
Advanced/Developer...
View Handle
View Hovercard
Size
33 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/src/controller/DiagramController.php b/src/controller/DiagramController.php
index ac466e8..f068dcd 100644
--- a/src/controller/DiagramController.php
+++ b/src/controller/DiagramController.php
@@ -1,509 +1,546 @@
<?php
final class DiagramController extends PhabricatorController {
/**
* Processes incoming HTTP requests from Diagram application
*/
public function handleRequest(AphrontRequest $request) {
$this->setRequest($request);
// detetermine if GET or POST HTTP call
if ($request->isHTTPPost()) {
// process POST calls (like save action)
return $this->handleHttpPostCall($request);
}
// determine type of URL by means of DiagramApplication route parameters
$diagramphid = $request->getURIData('diagramphid');
$diagramid = $request->getURIData('diagramid');
$versioneddiagramid = $request->getURIData('versioneddiagramid');
$version = $request->getURIData('version');
$route = $request->getURIData('route');
$versioninfoDiagramID = $request->getURIData('versioninfodiagram');
$versioninfoPage = $request->getURIData('versioninfopage');
if (isset($diagramphid) && !empty(trim($diagramphid))) {
// return PNG image data
$diagram = id(new DiagramVersion())->loadByDiagramPHID($diagramphid);
if ($diagram !== null) {
$response = new AphrontFileResponse();
$response->setMimeType('image/png');
$response->setContent($diagram->getData());
return $response;
}
}
if (isset($versioninfoDiagramID) && !empty(trim($versioninfoDiagramID))) {
// return diagram version info
if (!isset($versioninfoPage) || empty(trim($versioninfoPage))) {
// versioninfoPage was dismissed -> initialize to 1
$versioninfoPage = "1";
}
$diagramVersions = id(new DiagramVersion())->loadByDiagramID($versioninfoDiagramID);
if ($diagramVersions !== null) {
$result = [];
$viewer = $request->getViewer();
// determine total count of versions
$totalcount = count($diagramVersions);
// filter out some of the versions we want to show
$pageSize = 10;
- $diagramVersions = array_slice($diagramVersions,
+ $diagramVersions = array_slice($diagramVersions,
($versioninfoPage - 1) * $pageSize,
$pageSize
);
// calculate number of pages
$totalpages = ceil($totalcount / $pageSize);
// create menu-items
foreach ($diagramVersions as $diagramVersion) {
$author = $diagramVersion->getAuthorPHID();
$user = id(new PhabricatorPeopleQuery())
->setViewer($viewer)
->withPHIDs(array(
$author
))
->executeOne();
$dateModified = $diagramVersion->getDateModified();
$result[] = array(
"id" => $diagramVersion->getVersion(),
"datetime" => phabricator_datetime($dateModified, $viewer),
"author" => $user->getUsername()
);
}
// reply back
$response = id(new AphrontJSONResponse())->setAddJSONShield(false)
->setContent(array(
"data" => $result,
"pagecount" => $totalpages,
"nopager" => $totalcount <= $pageSize
));
return $response;
} else {
// version info requested for inexistant diagram
$response = id(new AphrontJSONResponse())->setAddJSONShield(false)
->setContent(array(
"data" => array(),
"pagecount" => 0
));
return $response;
}
}
$root = '';
$file = rtrim($request->getPath(), '/');
$root = dirname(phutil_get_library_root('diagram'));
// determine from which application area the file should be loaded:
// 1) Phorge extension source
// or 2) drawio source
if ($route == 'iframe') {
// load from drawio source
if ($file == '/diagram/iframe')
$file .= '/index.html';
if ($versioneddiagramid != null && $version != null) {
$file = preg_replace("/^\/diagram\/" . $versioneddiagramid . "\/" . $version ."iframe\//",
"data/drawio/src/main/webapp/",
$file);
} else {
$file = preg_replace("/^\/diagram\/(" . $diagramid . "\/?)?iframe\//",
"data/drawio/src/main/webapp/",
$file);
}
} else {
// load from extension source
if (rtrim($file, '/') == '/diagram') {
return $this->showApplication($request);
}
if ($versioneddiagramid !== null && $version !== null) {
- $file = preg_replace('/^\/diagram\/' . $versioneddiagramid . '\/'. $version . '\/?/',
- 'data/',
+ $file = preg_replace('/^\/diagram\/' . $versioneddiagramid . '\/'. $version . '\/?/',
+ 'data/',
$file
);
$file = rtrim($file, '/') . '/' . $versioneddiagramid;
} else {
- $file = preg_replace('/^\/diagram\/(' . $diagramid . '\/)?/',
- 'data/',
+ $file = preg_replace('/^\/diagram\/(' . $diagramid . '\/)?/',
+ 'data/',
$file
);
}
}
// determine full path
$path = $root . '/' . $file;
if (file_exists($path) == false || is_readable($path) == false) {
if (preg_match('/^data\/DIAG(\d+)$/', $file, $matches)) {
$diagram_id = (int) $matches[1];
if ($version === null) {
$diagram = id(new DiagramVersion())->loadLatestByDiagramID($diagram_id);
} else {
$diagram = id(new DiagramVersion())->loadByVersionedDiagramID($diagram_id, $version);
}
if ($diagram) {
$data = $diagram->getData();
$base64_data = base64_encode($data);
return $this->showApplication(
$request,
'DIAG' . $diagram_id,
- $version ?? "",
+ $version ?? "",
$base64_data
);
}
}
// Invalid URL
$response = id(new Aphront404Response());
return $response;
} else {
// process Iframe content
switch (pathinfo($file, PATHINFO_EXTENSION)) {
case 'html':
$response = id(new PlainHtmlWebpageResponse())
->setFrameable(true)
->setContent(file_get_contents($path));
break;
case 'js':
$response = new AphrontFileResponse();
$response->setMimeType('application/javascript');
break;
case 'css':
$response = new AphrontFileResponse();
$response->setMimeType('text/css');
break;
case 'txt':
$response = new AphrontFileResponse();
$response->setMimeType('text/plain');
break;
case 'png':
$response = new AphrontFileResponse();
$response->setMimeType('image/png');
break;
case 'gif':
$response = new AphrontFileResponse();
$response->setMimeType('image/gif');
break;
case 'jpg':
case 'jpeg':
$response = new AphrontFileResponse();
$response->setMimeType('image/jpeg');
break;
default:
$response = new AphrontFileResponse();
$response->setMimeType('application/octet-stream');
break;
}
try {
$response->setContent(file_get_contents($path));
} catch (Exception $e) {
$response->setContent($route);
}
return $response;
}
}
/**
* Compares the draw.io tEXt metadata from 2 PNG base64 strings.
* The content looks like this:
* <mxfile host="..." modified="..." agent="..." etag="..." version="..."...>
* <diagram id="O253AQcHVgjdl_wygdBA" name="Page-1">
* <mxGraphModel ...>
* <root>
* ...
* </mxCell>
* </root>
* </mxGraphModel>
* </diagram>
* </mxfile>
- *
+ *
* The modified and etag attributes of mxfile will always be different.
* They are cut out before the 2 strings are compared.
*/
- private function equalPngMetaData($base64_1, $base64_2) {
+ public static function equalPngMetaData($base64_1, $base64_2) {
$base64 = array($base64_1, $base64_2);
$textData = array();
for ($i = 0; $i < 2; $i++) {
$data = base64_decode($base64[$i]);
$fp = fopen('data://text/plain;base64,' . base64_encode($data), 'rb');
$sig = fread($fp, 8);
if ($sig != "\x89PNG\x0d\x0a\x1a\x0a") {
fclose($fp);
return false;
}
$textData[$i] = array();
while (!feof($fp)) {
- $chunk = unpack('Nlength/a4type', fread($fp, 8));
+ try {
+ $chunk = unpack('Nlength/a4type', fread($fp, 8));
+ } catch (Exception $e) {
+ // invalid base64 data
+ return false;
+ }
if ($chunk['type'] == 'IEND') break;
if ($chunk['type'] == 'tEXt') {
list($key, $val) = explode("\0", fread($fp, $chunk['length']));
if ($key == 'mxfile') {
// Decode the URL-encoded XML data
$decodedVal = urldecode($val);
// Load the XML and remove the modified and etag attributes
$xml = simplexml_load_string($decodedVal);
unset($xml->attributes()->modified);
unset($xml->attributes()->etag);
// Save the modified XML as the value
$val = $xml->asXML();
}
$textData[$i][$key] = $val;
fseek($fp, 4, SEEK_CUR);
} else {
fseek($fp, $chunk['length'] + 4, SEEK_CUR);
}
}
fclose($fp);
}
if (isset($textData[0]['mxfile']) && isset($textData[1]['mxfile'])) {
// Both arrays contain the mxfile key, compare their values
return $textData[0]['mxfile'] == $textData[1]['mxfile'];
} else {
// At least one of the arrays does not contain the mxfile key, return false
return false;
}
}
/**
* Processes HTTP POST calls from Diagram application, like 'Save' action
*/
private function handleHttpPostCall(AphrontRequest $request) {
$base64_data = $request->getStr("data");
$diagram_id = $request->getStr("diagramID");
// cut off "data:image/png;base64,"
$base64_data = substr($base64_data, strpos($base64_data, ',') + 1);
if ($diagram_id != "") {
// check if we are trying to save the same data as the current data
$diagram = id(new DiagramVersion())->loadLatestByDiagramID($diagram_id);
if ($diagram !== null) {
$data = $diagram->getData();
- $old_base64_data = base64_encode($data);
+ $old_data = base64_encode($data);
- if ($this->equalPngMetaData($base64_data, $old_base64_data)) {
+ if (DiagramController::equalPngMetaData($base64_data, $old_data)) {
// data hasn't been modified
// => do not create new version
$response = id(new AphrontJSONResponse())->setAddJSONShield(false)
->setContent(array(
"Status" => "OK",
"DiagramID" => $diagram->getDiagramID(),
"Version" => $diagram->getVersion()
));
return $response;
}
}
}
-
+
// Set the options for the new file
$options = array(
'name' => 'diagram.png',
'viewPolicy' => PhabricatorPolicies::POLICY_USER,
'mime-type' => 'image/png',
'actor' => $this->getViewer(),
'diagramID' => $diagram_id
);
try {
// Create the new file object
$diagram = DiagramVersion::newFromFileData($base64_data, $options);
$response = id(new AphrontJSONResponse())->setAddJSONShield(false)
->setContent(array(
"Status" => "OK",
"DiagramID" => $diagram->getDiagramID(),
"Version" => $diagram->getVersion()
));
return $response;
} catch (Exception $e) {
$response = id(new AphrontJSONResponse())->setAddJSONShield(false)
->setContent(array(
"Status" => "ERROR",
"Error" => $e->getMessage(),
));
return $response;
}
}
+ /**
+ * Verifies if the given base64 data is draw.io compatible
+ */
+ public static function isDrawioPngBase64($base64) {
+ $data = base64_decode($base64);
+ $fp = fopen('data://text/plain;base64,' . base64_encode($data), 'rb');
+ $sig = fread($fp, 8);
+ if ($sig != "\x89PNG\x0d\x0a\x1a\x0a") {
+ fclose($fp);
+ return false;
+ }
+ while (!feof($fp)) {
+ try {
+ $chunk = unpack('Nlength/a4type', fread($fp, 8));
+ } catch (Exception $e) {
+ // invalid base64 data
+ return false;
+ }
+ if ($chunk['type'] == 'IEND') break;
+ if ($chunk['type'] == 'tEXt') {
+ list($key, $val) = explode("\0", fread($fp, $chunk['length']));
+ if ($key == 'mxfile') {
+ fclose($fp);
+ return true;
+ }
+ fseek($fp, 4, SEEK_CUR);
+ } else {
+ fseek($fp, $chunk['length'] + 4, SEEK_CUR);
+ }
+ }
+ fclose($fp);
+ return false;
+ }
+
/**
* Shows the draw.io application integrated in Phorge's layout
*/
private function showApplication(
AphrontRequest $request,
string $diagramName = null,
string $diagramVersion = null,
string $diagramBase64 = null
) {
$content = phutil_tag(
'div',
array(),
array(
phutil_tag(
'div',
array(
'id' => 'mainScreen',
)),
phutil_tag('div',
array(),
array(
phutil_tag(
'img',
array(
'class' => 'drawio',
)),
phutil_tag('div',
array(
'id' => 'loadingtext',
'class' => 'geBlock',
'style' => 'margin-top:80px;'
. 'text-align:center;'
. 'min-width:50%;'
. 'height:100vh;',
),
array(
phutil_tag('h1',
array(),
'Flowchart Maker and Online Diagram Software'
),
phutil_tag('p',
array(
'style' => 'width: 800px;'
. 'position: sticky;'
. 'left: calc(50% - 400px);',
),
'draw.io is free online diagram software. '
. 'You can use it as a flowchart maker, network diagram '
. 'software, to create UML online, as an ER diagram tool, '
. 'to design database schema, to build BPMN online, as a '
. 'circuit diagram maker, and more. draw.io can import '
. '.vsdx, Gliffy™ and Lucidchart™ files . '
),
phutil_tag(
'h2',
array(
'id' => 'geStatus',
),
'Loading...'
),
phutil_tag(
'div',
array(
'id' => 'spinnerLoading',
)),
phutil_tag(
'script',
array(),
'var spinnerOpts = {'
. 'hwaccel: false,'
. 'length: 24,'
. 'radius: 12,'
. 'shadow: false,'
. 'speed: 1.5,'
. 'trail: 60,'
. 'width: 8};'
)
))
)),
phutil_tag(
'script',
array(
'src' => 'phorge_extension.js'
),
''
),
phutil_tag(
'script',
array(),
phutil_safe_html('loadJsExtension("'
. $diagramName
. '", "'
. $diagramVersion
. '", "'
. $diagramBase64
. '");')
),
phutil_tag(
'div',
array(
'class' => 'crumbs',
'style' => 'top:48px;'
. 'margin-left: 4px;'
. 'position: fixed;'
. 'font-weight: bold;'
),
array(
phutil_tag(
'a',
array(
'href' => '.'
),
array(
phutil_tag(
'span',
array(
'class' => 'phui-font-fa fa-sitemap',
'style' => 'padding-right:5px;'
))
)),
phutil_tag(
'a',
array(
'href' => '.'
),
'Diagram'
),
phutil_tag(
'span',
array(
'class' => 'diagramName',
'style' => 'display:none'
),
array(
phutil_tag(
'span',
array(
'style' => 'margin: 5px;'
. 'opacity: .5;'
),
'>'
),
phutil_tag(
'a',
array(),
''
),
phutil_tag(
'span',
array(
'class' => 'version',
'style' => 'margin-left: 8px;'
- . 'color: #999;'
- ),
- '',
- ),
+ . 'color: #999;'),
+ ''),
))
))
));
$view = id(new PhabricatorStandardPageView())
->setRequest($request)
->setController($this)
->setDeviceReady(true)
->setTitle("Diagrams")
->appendChild($content);
$response = id(new AphrontWebpageResponse())
->setContent($view->render());
return $response;
}
-}
\ No newline at end of file
+}
diff --git a/src/query/PhabricatorDiagramQuery.php b/src/query/PhabricatorDiagramQuery.php
index 8302219..c3627c3 100644
--- a/src/query/PhabricatorDiagramQuery.php
+++ b/src/query/PhabricatorDiagramQuery.php
@@ -1,73 +1,108 @@
<?php
final class PhabricatorDiagramQuery
extends PhabricatorCursorPagedPolicyAwareQuery {
protected $diagramIDs;
+ protected $modifiedAfter;
+ protected $modifiedBefore;
public function withDiagramIDs(array $diagram_ids) {
$this->diagramIDs = $diagram_ids;
return $this;
}
+ public function withIDs(array $diagram_ids) {
+ return $this->withDiagramIDs($diagram_ids);
+ }
+
+ public function withModifiedAfter($datetime) {
+ $this->modifiedAfter = $datetime;
+ return $this;
+ }
+
+ public function withModifiedBefore($datetime) {
+ $this->modifiedBefore = $datetime;
+ return $this;
+ }
+
protected function loadPage() {
$table = new DiagramVersion();
$conn_r = $table->establishConnection('r');
// we return a DiagramVersion object which has a different id
// than the one we mention in the Remarkup code.
// E.g. {DIAG1} may point to the 2nd version of the object.
// Diagram's id is 1, but DiagramVersion's id is 2.
// Because of this we abuse the id in the resultset a little bit
$data = queryfx_all(
$conn_r,
- "SELECT result.diagramID AS id, /* abuse */
- result.diagramID,
- result.version,
- result.phid,
- result.authorPHID,
- result.dateCreated,
- result.dateModified,
- result.byteSize,
- result.data,
- result.viewPolicy,
- result.editPolicy
+ 'SELECT *
FROM (
- SELECT data.*
- FROM %T data
- INNER JOIN (
- SELECT MAX(id) AS id,
- diagramid
- FROM %T
- GROUP BY diagramid HAVING MAX(id)
- ) filter
- ON data.id = filter.id
- ) result %Q %Q %Q",
+ SELECT result.diagramID AS id, /* abuse */
+ result.diagramID,
+ result.version,
+ result.phid,
+ result.authorPHID,
+ result.dateCreated,
+ result.dateModified,
+ result.byteSize,
+ result.data,
+ result.viewPolicy,
+ result.editPolicy
+ FROM (
+ SELECT data.*
+ FROM %T data
+ INNER JOIN (
+ SELECT MAX(id) AS id,
+ diagramid
+ FROM %T
+ GROUP BY diagramid HAVING MAX(id)
+ ) filter
+ ON data.id = filter.id
+ ) result
+ ) r %Q %Q %Q',
$table->getTableName(),
$table->getTableName(),
$this->buildWhereClause($conn_r),
$this->buildOrderClause($conn_r),
$this->buildLimitClause($conn_r));
return $table->loadAllFromArray($data);
}
protected function buildWhereClause(AphrontDatabaseConnection $conn_r) {
$where = array();
+ $where[] = $this->buildPagingClause($conn_r);
+
if ($this->diagramIDs !== null) {
$where[] = qsprintf(
$conn_r,
'diagramID IN (%Ld)',
$this->diagramIDs);
}
+ if ($this->modifiedAfter !== null) {
+ $where[] = qsprintf(
+ $conn_r,
+ 'dateModified >= %d',
+ $this->modifiedAfter);
+ }
+
+ if ($this->modifiedBefore !== null) {
+ $where[] = qsprintf(
+ $conn_r,
+ 'dateModified <= %d',
+ $this->modifiedBefore);
+ }
+
return $this->formatWhereClause($conn_r, $where);
}
public function getQueryApplicationClass() {
return DiagramApplication::class;
}
}
diff --git a/src/storage/DiagramVersion.php b/src/storage/DiagramVersion.php
index be98448..e896141 100644
--- a/src/storage/DiagramVersion.php
+++ b/src/storage/DiagramVersion.php
@@ -1,342 +1,371 @@
<?php
final class DiagramVersion extends DiagramDAO implements
PhabricatorDestructibleInterface,
PhabricatorPolicyInterface {
/**
* List of properties mapped to database table columns
*/
protected $phid;
protected $diagramID;
protected $version;
protected $authorPHID;
protected $byteSize;
protected $data;
protected $viewPolicy;
protected $editPolicy;
+ /**
+ * returns base64 of $data
+ */
+ public function getBase64Data() {
+ if ($this->data === null) {
+ return null;
+ }
+ return base64_encode($this->data);
+ }
+
+ /**
+ * returns the URL which links to the diagram PNG data
+ */
+ public function getDataURI() {
+ return PhabricatorEnv::getCDNURI(
+ '/diagram/data/'
+ .$this->getPHID());
+ }
+
/**
* Return an array of capabilities that this object type supports.
* See PhabricatorPolicyCapability for a list of available capabilities.
- *
+ *
* Interface: PhabricatorPolicyInterface
*/
public function getCapabilities() {
return array(
PhabricatorPolicyCapability::CAN_VIEW,
PhabricatorPolicyCapability::CAN_EDIT,
);
}
/**
* Return the policy for the given capability.
- *
+ *
* Interface: PhabricatorPolicyInterface
*/
public function getPolicy($capability) {
switch ($capability) {
case PhabricatorPolicyCapability::CAN_VIEW:
return $this->viewPolicy;
case PhabricatorPolicyCapability::CAN_EDIT:
return $this->editPolicy;
default:
return PhabricatorPolicies::POLICY_NOONE;
}
}
/**
* Return the URL which links to the diagram PNG image
*/
public function getViewURI() {
if (!$this->getPHID()) {
throw new Exception(
pht('You must save a diagram before you can generate a view URI.')
);
}
$uri = '/diagram/data/'
- . $this->getPHID();
+ .$this->getPHID();
return $uri;
}
/**
* Configures application-wide storage settings.
* This creates a mapping of the corresponding database table.
*/
public function getConfiguration() {
return array(
self::CONFIG_AUX_PHID => true,
self::CONFIG_COLUMN_SCHEMA => array(
'diagramID' => 'uint32',
'version' => 'uint32',
'authorPHID' => 'phid',
'byteSize' => 'uint64',
'data' => 'bytes',
'viewPolicy' => 'policy',
'editPolicy' => 'policy',
),
self::CONFIG_KEY_SCHEMA => array(
'key_phid' => null,
'key_diagramID_version' => array(
'columns' => array('diagramID', 'version'),
'unique' => true,
),
'key_authorPHID' => array(
'columns' => array('authorPHID'),
),
),
) +
array(
self::CONFIG_IDS => self::IDS_AUTOINCREMENT,
self::CONFIG_TIMESTAMPS => true,
);
}
/**
* Return the name of the database table that is represented by this class
*/
public function getTableName() {
return 'diagram_version';
}
/**
* Return a string that uniquely identifies the PHID type for this object
* type. This is used by the PHID system to generate and manage PHIDs for
* this object type.
*/
public function getPHIDType() {
return 'DGVN';
}
/**
* Return true if the given user has the given capability automatically,
* without needing to check the object's policy. For example, you might
* return true here if the user is an administrator or if they own the
* object.
- *
+ *
* Interface: PhabricatorPolicyInterface
*/
public function hasAutomaticCapability(
$capability,
- PhabricatorUser $viewer
- ) {
+ PhabricatorUser $viewer) {
return false;
}
+ /**
+ * Creates and initializes a new DiagramVersion object
+ */
public static function initializeNewDiagram(PhabricatorUser $actor) {
- return id(new DiagramVersion())
+ return id(new self())
->setViewPolicy(PhabricatorPolicies::getMostOpenPolicy())
->setEditPolicy($actor->getPHID())
->setAuthorPHID($actor->getPHID())
->setVersion(1)
->setDateCreated(time())
->setDateModified(time());
}
+ /**
+ * Creates a new DiagramVersion object and loads the given base64 data in it
+ */
public static function newFromFileData(
$base64_data,
- array $params = array()
- ) {
+ array $params = array()) {
$actor = idx($params, 'actor');
if (!$actor) {
throw new Exception(pht('Missing required actor for new file data.'));
}
$diagramID = idx($params, 'diagramID');
if (!is_numeric($diagramID)) {
$diagramID = null;
}
$data = base64_decode($base64_data);
$diagram = self::initializeNewDiagram($actor);
$diagram->setByteSize(strlen($data));
$diagram->setData($data);
$diagram->setDiagramID($diagramID);
$diagram->save();
return $diagram;
}
- public function attachProjectPHIDs(array $phids) {
- // Attach an array of project PHIDs to this object. This is used by the
- // project system to manage project membership and visibility for this
- // object.
- }
-
+ /**
+ * Permanently destroy this object. This is used by the destructible
+ * interface to allow administrators to permanently delete objects from
+ * the system.
+ */
public function destroyObjectPermanently(
- PhabricatorDestructionEngine $engine
- ) {
- // Permanently destroy this object. This is used by the destructible
- // interface to allow administrators to permanently delete objects from
- // the system.
+ PhabricatorDestructionEngine $engine) {
$this->openTransaction();
$this->delete();
$this->saveTransaction();
}
+ /**
+ * Returns an ID which can be used for a newly created Diagram object
+ */
public function generateDiagramID() {
$conn_r = $this->establishConnection('r');
$table_name = $this->getTableName();
$max_diagram_id = queryfx_one(
$conn_r,
'SELECT MAX(diagramID) max_diagram_id FROM %T',
- $table_name
- )['max_diagram_id'];
- return (int) $max_diagram_id + 1;
+ $table_name)['max_diagram_id'];
+ return (int)$max_diagram_id + 1;
}
+ /**
+ * Returns all DiagramVersion objects for a given diagram
+ */
public function loadByDiagramID($diagramID) {
if (is_object($diagramID)) {
- $diagramID = (string) $diagramID;
+ $diagramID = (string)$diagramID;
}
if (!$diagramID || (!is_int($diagramID) && !ctype_digit($diagramID))) {
return null;
}
return $this->loadAllWhere(
'diagramID = %d ORDER BY version DESC',
- $diagramID
- );
+ $diagramID);
}
+ /**
+ * Returns the latest version of the given diagram
+ */
public function loadLatestByDiagramID($diagramID) {
if (is_object($diagramID)) {
- $diagramID = (string) $diagramID;
+ $diagramID = (string)$diagramID;
}
if (!$diagramID || (!is_int($diagramID) && !ctype_digit($diagramID))) {
return null;
}
return $this->loadOneWhere(
'diagramID = %d ORDER BY version DESC LIMIT 1',
- $diagramID
- );
+ $diagramID);
}
- public function loadByDiagramPHID($diagramPHID) {
- if (is_object($diagramPHID)) {
- $diagramPHID = (string) $diagramPHID;
+ /**
+ * Returns a specific DiagramVersion object
+ */
+ public function loadByDiagramPHID($diagramVersionPHID) {
+ if (is_object($diagramVersionPHID)) {
+ $diagramVersionPHID = (string)$diagramVersionPHID;
}
return $this->loadOneWhere(
'phid = %s ORDER BY version DESC LIMIT 1',
- $diagramPHID
- );
+ $diagramVersionPHID);
}
+ /**
+ * Returns a specific DiagramVersion object for a given diagram and
+ * version number
+ */
public function loadByVersionedDiagramID($diagramID, $version) {
if (is_object($diagramID)) {
- $diagramID = (string) $diagramID;
+ $diagramID = (string)$diagramID;
}
if (is_object($version)) {
- $version = (string) $version;
+ $version = (string)$version;
}
if (!$diagramID || (!is_int($diagramID) && !ctype_digit($diagramID))) {
return null;
}
if (!$version || (!is_int($version) && !ctype_digit($version))) {
return null;
}
return $this->loadOneWhere(
'diagramID = %d AND version = %d',
$diagramID,
- $version
- );
+ $version);
}
+ /**
+ * Stores a new diagram (version)
+ */
public function save() {
// Load the last record with the same PHID.
$last_record = null;
if ($this->getDiagramID() !== null) {
$last_record = id(new PhabricatorDiagramQuery())
->setViewer(PhabricatorUser::getOmnipotentUser())
->withDiagramIDs(array($this->getDiagramID()))
->setLimit(1)
->executeOne();
}
if ($last_record === null) {
// If there is no last record, this is a new diagram object.
$this->setVersion(1);
$newDiagram = new Diagram();
$newDiagram->createNewDiagram();
$this->setDiagramID($newDiagram->getID());
} else {
// If there is a last record, this is a new version of an existing
// diagram object.
$this->setVersion($last_record->getVersion() + 1);
$this->setDateCreated($last_record->getDateCreated());
}
// Check if a row with the same PHID and version already exists
$existing_record = null;
if ($this->getPHID() !== null && $this->getVersion() !== null) {
$existing_record = id(new PhabricatorDiagramQuery())
->setViewer(PhabricatorUser::getOmnipotentUser())
->withPHIDs(array($this->getPHID()))
->withWhere(
array(
array('version', '=', $this->getVersion()),
- )
- )
+ ))
->setLimit(1)
->executeOne();
}
if ($existing_record === null) {
// If there is no existing record, create a new row in the table.
$conn_w = $this->establishConnection('w');
$table_name = $this->getTableName();
$this->phid = $this->generatePHID();
if ($this->diagramID === null) {
$this->diagramID = $this->generateDiagramID();
}
$record = array(
'phid' => $this->getPHID(),
'diagramID' => $this->getDiagramID(),
'version' => $this->getVersion(),
'authorPHID' => $this->getAuthorPHID(),
'dateCreated' => $this->getDateCreated(),
'dateModified' => $this->getDateModified(),
'byteSize' => $this->getByteSize(),
'viewPolicy' => $this->getViewPolicy(),
'editPolicy' => $this->getEditPolicy(),
'data' => $this->getData(),
);
if ($this->getID() !== null) {
// If the ID property is set, include it in the data to insert.
$record['id'] = $this->getID();
}
queryfx(
$conn_w,
'INSERT INTO %T (%Q) VALUES (%Ls, %B)',
$table_name,
implode(', ', array_keys($record)),
array_values(array_slice($record, 0, -1)),
- end($record)
- );
+ end($record));
$this->id = $conn_w->getInsertID();
} else {
// If there is an existing record, throw an exception.
throw new Exception(
pht('A diagram with PHID "%s" and version "%s" already exists.',
$this->getPHID(),
- $this->getVersion()
- )
+ $this->getVersion())
);
}
return $this;
}
-}
\ No newline at end of file
+}
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Thu, Dec 19, 16:28 (18 h, 52 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1014820
Default Alt Text
(33 KB)
Attached To
Mode
R5 Diagrams
Attached
Detach File
Event Timeline
Log In to Comment