mirror of
https://we.phorge.it/source/phorge.git
synced 2025-01-30 00:18:21 +01:00
Use application PHIDs for application transactions
Summary: Ref T2715. Ref T3578. Load application transactions through application PHID infrastructure. Test Plan: Viewed feed, saw successful loads of application transaction objects and rendered feed stories. Reviewers: btrahan Reviewed By: btrahan CC: aran Maniphest Tasks: T2715, T3578 Differential Revision: https://secure.phabricator.com/D6617
This commit is contained in:
parent
1720d651da
commit
5cc3bbf721
22 changed files with 101 additions and 102 deletions
|
@ -43,7 +43,7 @@ foreach ($comments as $comment) {
|
||||||
$comment_phid = PhabricatorPHID::generateNewPHID(
|
$comment_phid = PhabricatorPHID::generateNewPHID(
|
||||||
PhabricatorPHIDConstants::PHID_TYPE_XCMT);
|
PhabricatorPHIDConstants::PHID_TYPE_XCMT);
|
||||||
$xaction_phid = PhabricatorPHID::generateNewPHID(
|
$xaction_phid = PhabricatorPHID::generateNewPHID(
|
||||||
PhabricatorPHIDConstants::PHID_TYPE_XACT,
|
PhabricatorApplicationTransactionPHIDTypeTransaction::TYPECONST,
|
||||||
PhabricatorSlowvotePHIDTypePoll::TYPECONST);
|
PhabricatorSlowvotePHIDTypePoll::TYPECONST);
|
||||||
|
|
||||||
$source = PhabricatorContentSource::newForSource(
|
$source = PhabricatorContentSource::newForSource(
|
||||||
|
|
|
@ -27,11 +27,11 @@ foreach ($rows as $row) {
|
||||||
}
|
}
|
||||||
|
|
||||||
$comment_phid = PhabricatorPHID::generateNewPHID(
|
$comment_phid = PhabricatorPHID::generateNewPHID(
|
||||||
PhabricatorPHIDConstants::PHID_TYPE_XACT,
|
PhabricatorApplicationTransactionPHIDTypeTransaction::TYPECONST,
|
||||||
$type);
|
$type);
|
||||||
|
|
||||||
$xaction_phid = PhabricatorPHID::generateNewPHID(
|
$xaction_phid = PhabricatorPHID::generateNewPHID(
|
||||||
PhabricatorPHIDConstants::PHID_TYPE_XACT,
|
PhabricatorApplicationTransactionPHIDTypeTransaction::TYPECONST,
|
||||||
$type);
|
$type);
|
||||||
|
|
||||||
queryfx(
|
queryfx(
|
||||||
|
|
|
@ -833,6 +833,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorApplicationTransactionInterface' => 'applications/transactions/interface/PhabricatorApplicationTransactionInterface.php',
|
'PhabricatorApplicationTransactionInterface' => 'applications/transactions/interface/PhabricatorApplicationTransactionInterface.php',
|
||||||
'PhabricatorApplicationTransactionNoEffectException' => 'applications/transactions/exception/PhabricatorApplicationTransactionNoEffectException.php',
|
'PhabricatorApplicationTransactionNoEffectException' => 'applications/transactions/exception/PhabricatorApplicationTransactionNoEffectException.php',
|
||||||
'PhabricatorApplicationTransactionNoEffectResponse' => 'applications/transactions/response/PhabricatorApplicationTransactionNoEffectResponse.php',
|
'PhabricatorApplicationTransactionNoEffectResponse' => 'applications/transactions/response/PhabricatorApplicationTransactionNoEffectResponse.php',
|
||||||
|
'PhabricatorApplicationTransactionPHIDTypeTransaction' => 'applications/transactions/phid/PhabricatorApplicationTransactionPHIDTypeTransaction.php',
|
||||||
'PhabricatorApplicationTransactionQuery' => 'applications/transactions/query/PhabricatorApplicationTransactionQuery.php',
|
'PhabricatorApplicationTransactionQuery' => 'applications/transactions/query/PhabricatorApplicationTransactionQuery.php',
|
||||||
'PhabricatorApplicationTransactionResponse' => 'applications/transactions/response/PhabricatorApplicationTransactionResponse.php',
|
'PhabricatorApplicationTransactionResponse' => 'applications/transactions/response/PhabricatorApplicationTransactionResponse.php',
|
||||||
'PhabricatorApplicationTransactionTextDiffDetailView' => 'applications/transactions/view/PhabricatorApplicationTransactionTextDiffDetailView.php',
|
'PhabricatorApplicationTransactionTextDiffDetailView' => 'applications/transactions/view/PhabricatorApplicationTransactionTextDiffDetailView.php',
|
||||||
|
@ -2844,6 +2845,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorApplicationTransactionFeedStory' => 'PhabricatorFeedStory',
|
'PhabricatorApplicationTransactionFeedStory' => 'PhabricatorFeedStory',
|
||||||
'PhabricatorApplicationTransactionNoEffectException' => 'Exception',
|
'PhabricatorApplicationTransactionNoEffectException' => 'Exception',
|
||||||
'PhabricatorApplicationTransactionNoEffectResponse' => 'AphrontProxyResponse',
|
'PhabricatorApplicationTransactionNoEffectResponse' => 'AphrontProxyResponse',
|
||||||
|
'PhabricatorApplicationTransactionPHIDTypeTransaction' => 'PhabricatorPHIDType',
|
||||||
'PhabricatorApplicationTransactionQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
|
'PhabricatorApplicationTransactionQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
|
||||||
'PhabricatorApplicationTransactionResponse' => 'AphrontProxyResponse',
|
'PhabricatorApplicationTransactionResponse' => 'AphrontProxyResponse',
|
||||||
'PhabricatorApplicationTransactionTextDiffDetailView' => 'AphrontView',
|
'PhabricatorApplicationTransactionTextDiffDetailView' => 'AphrontView',
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
final class PhabricatorAuthProviderConfigTransactionQuery
|
final class PhabricatorAuthProviderConfigTransactionQuery
|
||||||
extends PhabricatorApplicationTransactionQuery {
|
extends PhabricatorApplicationTransactionQuery {
|
||||||
|
|
||||||
protected function getTemplateApplicationTransaction() {
|
public function getTemplateApplicationTransaction() {
|
||||||
return new PhabricatorAuthProviderConfigTransaction();
|
return new PhabricatorAuthProviderConfigTransaction();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
final class PhabricatorConfigTransactionQuery
|
final class PhabricatorConfigTransactionQuery
|
||||||
extends PhabricatorApplicationTransactionQuery {
|
extends PhabricatorApplicationTransactionQuery {
|
||||||
|
|
||||||
protected function getTemplateApplicationTransaction() {
|
public function getTemplateApplicationTransaction() {
|
||||||
return new PhabricatorConfigTransaction();
|
return new PhabricatorConfigTransaction();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
final class ConpherenceTransactionQuery
|
final class ConpherenceTransactionQuery
|
||||||
extends PhabricatorApplicationTransactionQuery {
|
extends PhabricatorApplicationTransactionQuery {
|
||||||
|
|
||||||
protected function getTemplateApplicationTransaction() {
|
public function getTemplateApplicationTransaction() {
|
||||||
return new ConpherenceTransaction();
|
return new ConpherenceTransaction();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
final class LegalpadTransactionQuery
|
final class LegalpadTransactionQuery
|
||||||
extends PhabricatorApplicationTransactionQuery {
|
extends PhabricatorApplicationTransactionQuery {
|
||||||
|
|
||||||
protected function getTemplateApplicationTransaction() {
|
public function getTemplateApplicationTransaction() {
|
||||||
return new LegalpadTransaction();
|
return new LegalpadTransaction();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
final class PhabricatorMacroTransactionQuery
|
final class PhabricatorMacroTransactionQuery
|
||||||
extends PhabricatorApplicationTransactionQuery {
|
extends PhabricatorApplicationTransactionQuery {
|
||||||
|
|
||||||
protected function getTemplateApplicationTransaction() {
|
public function getTemplateApplicationTransaction() {
|
||||||
return new PhabricatorMacroTransaction();
|
return new PhabricatorMacroTransaction();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,6 @@ final class PhabricatorPHIDConstants {
|
||||||
const PHID_TYPE_CART = 'CART';
|
const PHID_TYPE_CART = 'CART';
|
||||||
const PHID_TYPE_LEGB = 'LEGB';
|
const PHID_TYPE_LEGB = 'LEGB';
|
||||||
|
|
||||||
const PHID_TYPE_XACT = 'XACT';
|
|
||||||
const PHID_TYPE_XCMT = 'XCMT';
|
const PHID_TYPE_XCMT = 'XCMT';
|
||||||
|
|
||||||
const PHID_TYPE_BOOK = 'BOOK';
|
const PHID_TYPE_BOOK = 'BOOK';
|
||||||
|
|
|
@ -24,75 +24,10 @@ final class PhabricatorObjectHandleData {
|
||||||
public function loadObjects() {
|
public function loadObjects() {
|
||||||
$phids = array_fuse($this->phids);
|
$phids = array_fuse($this->phids);
|
||||||
|
|
||||||
$objects = id(new PhabricatorObjectQuery())
|
return id(new PhabricatorObjectQuery())
|
||||||
->setViewer($this->viewer)
|
->setViewer($this->viewer)
|
||||||
->withPHIDs($phids)
|
->withPHIDs($phids)
|
||||||
->execute();
|
->execute();
|
||||||
|
|
||||||
// For objects which don't support PhabricatorPHIDType yet, load them the
|
|
||||||
// old way.
|
|
||||||
$phids = array_diff_key($phids, array_keys($objects));
|
|
||||||
$types = phid_group_by_type($phids);
|
|
||||||
foreach ($types as $type => $phids) {
|
|
||||||
$objects += $this->loadObjectsOfType($type, $phids);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $objects;
|
|
||||||
}
|
|
||||||
|
|
||||||
private function loadObjectsOfType($type, array $phids) {
|
|
||||||
if (!$this->viewer) {
|
|
||||||
throw new Exception(
|
|
||||||
"You must provide a viewer to load handles or objects.");
|
|
||||||
}
|
|
||||||
|
|
||||||
switch ($type) {
|
|
||||||
|
|
||||||
case PhabricatorPHIDConstants::PHID_TYPE_XACT:
|
|
||||||
$subtypes = array();
|
|
||||||
foreach ($phids as $phid) {
|
|
||||||
$subtypes[phid_get_subtype($phid)][] = $phid;
|
|
||||||
}
|
|
||||||
$xactions = array();
|
|
||||||
foreach ($subtypes as $subtype => $subtype_phids) {
|
|
||||||
// TODO: Do this magically.
|
|
||||||
// TODO: ^^^ Really do that ^^^
|
|
||||||
switch ($subtype) {
|
|
||||||
case PonderPHIDTypeQuestion::TYPECONST:
|
|
||||||
$results = id(new PonderQuestionTransactionQuery())
|
|
||||||
->setViewer($this->viewer)
|
|
||||||
->withPHIDs($subtype_phids)
|
|
||||||
->execute();
|
|
||||||
$xactions += mpull($results, null, 'getPHID');
|
|
||||||
break;
|
|
||||||
case PonderPHIDTypeAnswer::TYPECONST:
|
|
||||||
$results = id(new PonderAnswerTransactionQuery())
|
|
||||||
->setViewer($this->viewer)
|
|
||||||
->withPHIDs($subtype_phids)
|
|
||||||
->execute();
|
|
||||||
$xactions += mpull($results, null, 'getPHID');
|
|
||||||
break;
|
|
||||||
case PholioPHIDTypeMock::TYPECONST:
|
|
||||||
$results = id(new PholioTransactionQuery())
|
|
||||||
->setViewer($this->viewer)
|
|
||||||
->withPHIDs($subtype_phids)
|
|
||||||
->execute();
|
|
||||||
$xactions += mpull($results, null, 'getPHID');
|
|
||||||
break;
|
|
||||||
case PhabricatorMacroPHIDTypeMacro::TYPECONST:
|
|
||||||
$results = id(new PhabricatorMacroTransactionQuery())
|
|
||||||
->setViewer($this->viewer)
|
|
||||||
->withPHIDs($subtype_phids)
|
|
||||||
->execute();
|
|
||||||
$xactions += mpull($results, null, 'getPHID');
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return mpull($xactions, null, 'getPHID');
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return array();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function loadHandles() {
|
public function loadHandles() {
|
||||||
|
@ -111,15 +46,11 @@ final class PhabricatorObjectHandleData {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$all_objects = $this->loadObjects();
|
|
||||||
$types = phid_group_by_type($phid_map);
|
$types = phid_group_by_type($phid_map);
|
||||||
|
|
||||||
$handles = array();
|
$handles = array();
|
||||||
|
|
||||||
foreach ($types as $type => $phids) {
|
foreach ($types as $type => $phids) {
|
||||||
$objects = array_select_keys($all_objects, $phids);
|
|
||||||
switch ($type) {
|
switch ($type) {
|
||||||
|
|
||||||
case PhabricatorPHIDConstants::PHID_TYPE_MAGIC:
|
case PhabricatorPHIDConstants::PHID_TYPE_MAGIC:
|
||||||
// Black magic!
|
// Black magic!
|
||||||
foreach ($phids as $phid) {
|
foreach ($phids as $phid) {
|
||||||
|
@ -144,18 +75,6 @@ final class PhabricatorObjectHandleData {
|
||||||
$handles[$phid] = $handle;
|
$handles[$phid] = $handle;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
|
||||||
foreach ($phids as $phid) {
|
|
||||||
$handle = new PhabricatorObjectHandle();
|
|
||||||
$handle->setType($type);
|
|
||||||
$handle->setPHID($phid);
|
|
||||||
$handle->setName('Unknown Object');
|
|
||||||
$handle->setFullName('An Unknown Object');
|
|
||||||
$handles[$phid] = $handle;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
final class PhluxTransactionQuery
|
final class PhluxTransactionQuery
|
||||||
extends PhabricatorApplicationTransactionQuery {
|
extends PhabricatorApplicationTransactionQuery {
|
||||||
|
|
||||||
protected function getTemplateApplicationTransaction() {
|
public function getTemplateApplicationTransaction() {
|
||||||
return new PhluxTransaction();
|
return new PhluxTransaction();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
final class PholioTransactionQuery
|
final class PholioTransactionQuery
|
||||||
extends PhabricatorApplicationTransactionQuery {
|
extends PhabricatorApplicationTransactionQuery {
|
||||||
|
|
||||||
protected function getTemplateApplicationTransaction() {
|
public function getTemplateApplicationTransaction() {
|
||||||
return new PholioTransaction();
|
return new PholioTransaction();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
final class PhortuneAccountTransactionQuery
|
final class PhortuneAccountTransactionQuery
|
||||||
extends PhabricatorApplicationTransactionQuery {
|
extends PhabricatorApplicationTransactionQuery {
|
||||||
|
|
||||||
protected function getTemplateApplicationTransaction() {
|
public function getTemplateApplicationTransaction() {
|
||||||
return new PhortuneAccountTransaction();
|
return new PhortuneAccountTransaction();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
final class PhortuneProductTransactionQuery
|
final class PhortuneProductTransactionQuery
|
||||||
extends PhabricatorApplicationTransactionQuery {
|
extends PhabricatorApplicationTransactionQuery {
|
||||||
|
|
||||||
protected function getTemplateApplicationTransaction() {
|
public function getTemplateApplicationTransaction() {
|
||||||
return new PhortuneProductTransaction();
|
return new PhortuneProductTransaction();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
final class PonderAnswerTransactionQuery
|
final class PonderAnswerTransactionQuery
|
||||||
extends PhabricatorApplicationTransactionQuery {
|
extends PhabricatorApplicationTransactionQuery {
|
||||||
|
|
||||||
protected function getTemplateApplicationTransaction() {
|
public function getTemplateApplicationTransaction() {
|
||||||
return new PonderAnswerTransaction();
|
return new PonderAnswerTransaction();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
final class PonderQuestionTransactionQuery
|
final class PonderQuestionTransactionQuery
|
||||||
extends PhabricatorApplicationTransactionQuery {
|
extends PhabricatorApplicationTransactionQuery {
|
||||||
|
|
||||||
protected function getTemplateApplicationTransaction() {
|
public function getTemplateApplicationTransaction() {
|
||||||
return new PonderQuestionTransaction();
|
return new PonderQuestionTransaction();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
final class ReleephRequestTransactionQuery
|
final class ReleephRequestTransactionQuery
|
||||||
extends PhabricatorApplicationTransactionQuery {
|
extends PhabricatorApplicationTransactionQuery {
|
||||||
|
|
||||||
protected function getTemplateApplicationTransaction() {
|
public function getTemplateApplicationTransaction() {
|
||||||
return new ReleephRequestTransaction();
|
return new ReleephRequestTransaction();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
final class PhabricatorRepositoryTransactionQuery
|
final class PhabricatorRepositoryTransactionQuery
|
||||||
extends PhabricatorApplicationTransactionQuery {
|
extends PhabricatorApplicationTransactionQuery {
|
||||||
|
|
||||||
protected function getTemplateApplicationTransaction() {
|
public function getTemplateApplicationTransaction() {
|
||||||
return new PhabricatorRepositoryTransaction();
|
return new PhabricatorRepositoryTransaction();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
final class PhabricatorSlowvoteTransactionQuery
|
final class PhabricatorSlowvoteTransactionQuery
|
||||||
extends PhabricatorApplicationTransactionQuery {
|
extends PhabricatorApplicationTransactionQuery {
|
||||||
|
|
||||||
protected function getTemplateApplicationTransaction() {
|
public function getTemplateApplicationTransaction() {
|
||||||
return new PhabricatorSlowvoteTransaction();
|
return new PhabricatorSlowvoteTransaction();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,79 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorApplicationTransactionPHIDTypeTransaction
|
||||||
|
extends PhabricatorPHIDType {
|
||||||
|
|
||||||
|
const TYPECONST = 'XACT';
|
||||||
|
|
||||||
|
public function getTypeConstant() {
|
||||||
|
return self::TYPECONST;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getTypeName() {
|
||||||
|
return pht('Transaction');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function newObject() {
|
||||||
|
// NOTE: We could produce an object here, but we'd need to take a PHID type
|
||||||
|
// and subtype to do so. Currently, we never write edges to transactions,
|
||||||
|
// so leave this unimplemented for the moment.
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function loadObjects(
|
||||||
|
PhabricatorObjectQuery $object_query,
|
||||||
|
array $phids) {
|
||||||
|
|
||||||
|
static $queries;
|
||||||
|
if ($queries === null) {
|
||||||
|
$objects = id(new PhutilSymbolLoader())
|
||||||
|
->setAncestorClass('PhabricatorApplicationTransactionQuery')
|
||||||
|
->loadObjects();
|
||||||
|
|
||||||
|
$queries = array();
|
||||||
|
foreach ($objects as $object) {
|
||||||
|
$type = $object
|
||||||
|
->getTemplateApplicationTransaction()
|
||||||
|
->getApplicationTransactionType();
|
||||||
|
|
||||||
|
$queries[$type] = $object;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$phid_subtypes = array();
|
||||||
|
foreach ($phids as $phid) {
|
||||||
|
$subtype = phid_get_subtype($phid);
|
||||||
|
if ($subtype) {
|
||||||
|
$phid_subtypes[$subtype][] = $phid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$results = array();
|
||||||
|
foreach ($phid_subtypes as $subtype => $subtype_phids) {
|
||||||
|
$query = idx($queries, $subtype);
|
||||||
|
if (!$query) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$xactions = id(clone $query)
|
||||||
|
->setViewer($object_query->getViewer())
|
||||||
|
->withPHIDs($subtype_phids)
|
||||||
|
->execute();
|
||||||
|
|
||||||
|
$results += mpull($xactions, null, 'getPHID');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $results;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function loadHandles(
|
||||||
|
PhabricatorHandleQuery $query,
|
||||||
|
array $handles,
|
||||||
|
array $objects) {
|
||||||
|
|
||||||
|
// NOTE: We don't produce meaningful handles here because they're
|
||||||
|
// impractical to produce and no application uses them.
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -11,7 +11,7 @@ abstract class PhabricatorApplicationTransactionQuery
|
||||||
private $needComments = true;
|
private $needComments = true;
|
||||||
private $needHandles = true;
|
private $needHandles = true;
|
||||||
|
|
||||||
abstract protected function getTemplateApplicationTransaction();
|
abstract public function getTemplateApplicationTransaction();
|
||||||
|
|
||||||
protected function buildMoreWhereClauses(AphrontDatabaseConnection $conn_r) {
|
protected function buildMoreWhereClauses(AphrontDatabaseConnection $conn_r) {
|
||||||
return array();
|
return array();
|
||||||
|
|
|
@ -47,7 +47,7 @@ abstract class PhabricatorApplicationTransaction
|
||||||
}
|
}
|
||||||
|
|
||||||
public function generatePHID() {
|
public function generatePHID() {
|
||||||
$type = PhabricatorPHIDConstants::PHID_TYPE_XACT;
|
$type = PhabricatorApplicationTransactionPHIDTypeTransaction::TYPECONST;
|
||||||
$subtype = $this->getApplicationTransactionType();
|
$subtype = $this->getApplicationTransactionType();
|
||||||
|
|
||||||
return PhabricatorPHID::generateNewPHID($type, $subtype);
|
return PhabricatorPHID::generateNewPHID($type, $subtype);
|
||||||
|
|
Loading…
Add table
Reference in a new issue