@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
fork

Configure Feed

Select the types of activity you want to include in your feed.

Support export engine extensions and implement an extension for custom fields

Summary:
Depends on D18953. Ref T13049. Allow applications and infrastructure to supplement exportable fields for objects.

Then, implement an extension for custom fields. Only a couple field types (int, string) are supported for now.

Test Plan: Added some custom fields to Users, populated them, exported users. Saw custom fields in the export.

Reviewers: amckinley

Reviewed By: amckinley

Maniphest Tasks: T13049

Differential Revision: https://secure.phabricator.com/D18954

+233
+4
src/__phutil_library_map__.php
··· 2583 2583 'PhabricatorCustomFieldEditEngineExtension' => 'infrastructure/customfield/engineextension/PhabricatorCustomFieldEditEngineExtension.php', 2584 2584 'PhabricatorCustomFieldEditField' => 'infrastructure/customfield/editor/PhabricatorCustomFieldEditField.php', 2585 2585 'PhabricatorCustomFieldEditType' => 'infrastructure/customfield/editor/PhabricatorCustomFieldEditType.php', 2586 + 'PhabricatorCustomFieldExportEngineExtension' => 'infrastructure/export/PhabricatorCustomFieldExportEngineExtension.php', 2586 2587 'PhabricatorCustomFieldFulltextEngineExtension' => 'infrastructure/customfield/engineextension/PhabricatorCustomFieldFulltextEngineExtension.php', 2587 2588 'PhabricatorCustomFieldHeraldAction' => 'infrastructure/customfield/herald/PhabricatorCustomFieldHeraldAction.php', 2588 2589 'PhabricatorCustomFieldHeraldActionGroup' => 'infrastructure/customfield/herald/PhabricatorCustomFieldHeraldActionGroup.php', ··· 2847 2848 'PhabricatorEventType' => 'infrastructure/events/constant/PhabricatorEventType.php', 2848 2849 'PhabricatorExampleEventListener' => 'infrastructure/events/PhabricatorExampleEventListener.php', 2849 2850 'PhabricatorExecFutureFileUploadSource' => 'applications/files/uploadsource/PhabricatorExecFutureFileUploadSource.php', 2851 + 'PhabricatorExportEngineExtension' => 'infrastructure/export/PhabricatorExportEngineExtension.php', 2850 2852 'PhabricatorExportField' => 'infrastructure/export/PhabricatorExportField.php', 2851 2853 'PhabricatorExportFormat' => 'infrastructure/export/PhabricatorExportFormat.php', 2852 2854 'PhabricatorExtendedPolicyInterface' => 'applications/policy/interface/PhabricatorExtendedPolicyInterface.php', ··· 7991 7993 'PhabricatorCustomFieldEditEngineExtension' => 'PhabricatorEditEngineExtension', 7992 7994 'PhabricatorCustomFieldEditField' => 'PhabricatorEditField', 7993 7995 'PhabricatorCustomFieldEditType' => 'PhabricatorEditType', 7996 + 'PhabricatorCustomFieldExportEngineExtension' => 'PhabricatorExportEngineExtension', 7994 7997 'PhabricatorCustomFieldFulltextEngineExtension' => 'PhabricatorFulltextEngineExtension', 7995 7998 'PhabricatorCustomFieldHeraldAction' => 'HeraldAction', 7996 7999 'PhabricatorCustomFieldHeraldActionGroup' => 'HeraldActionGroup', ··· 8280 8283 'PhabricatorEventType' => 'PhutilEventType', 8281 8284 'PhabricatorExampleEventListener' => 'PhabricatorEventListener', 8282 8285 'PhabricatorExecFutureFileUploadSource' => 'PhabricatorFileUploadSource', 8286 + 'PhabricatorExportEngineExtension' => 'Phobject', 8283 8287 'PhabricatorExportField' => 'Phobject', 8284 8288 'PhabricatorExportFormat' => 'Phobject', 8285 8289 'PhabricatorExtendingPhabricatorConfigOptions' => 'PhabricatorApplicationConfigOptions',
+58
src/applications/search/engine/PhabricatorApplicationSearchEngine.php
··· 1483 1483 $fields[$key] = $export_field; 1484 1484 } 1485 1485 1486 + $extensions = $this->newExportExtensions(); 1487 + foreach ($extensions as $extension) { 1488 + $extension_fields = $extension->newExportFields(); 1489 + foreach ($extension_fields as $extension_field) { 1490 + $key = $extension_field->getKey(); 1491 + 1492 + if (isset($fields[$key])) { 1493 + throw new Exception( 1494 + pht( 1495 + 'Export engine extension ("%s") defines an export field with '. 1496 + 'a key ("%s") that collides with another field. Each field '. 1497 + 'must have a unique key.', 1498 + get_class($extension_field), 1499 + $key)); 1500 + } 1501 + 1502 + $fields[$key] = $extension_field; 1503 + } 1504 + } 1505 + 1486 1506 return $fields; 1487 1507 } 1488 1508 ··· 1514 1534 $maps[$ii] += $export_data[$ii]; 1515 1535 } 1516 1536 1537 + $extensions = $this->newExportExtensions(); 1538 + foreach ($extensions as $extension) { 1539 + $extension_data = $extension->newExportData($objects); 1540 + $extension_data = array_values($extension_data); 1541 + if (count($export_data) !== count($objects)) { 1542 + throw new Exception( 1543 + pht( 1544 + 'Export engine extension ("%s") exported the wrong number of '. 1545 + 'objects, expected %s but got %s.', 1546 + get_class($extension), 1547 + phutil_count($objects), 1548 + phutil_count($export_data))); 1549 + } 1550 + 1551 + for ($ii = 0; $ii < $n; $ii++) { 1552 + $maps[$ii] += $extension_data[$ii]; 1553 + } 1554 + } 1555 + 1517 1556 return $maps; 1518 1557 } 1519 1558 ··· 1523 1562 1524 1563 protected function newExportData(array $objects) { 1525 1564 throw new PhutilMethodNotImplementedException(); 1565 + } 1566 + 1567 + private function newExportExtensions() { 1568 + $object = $this->newResultObject(); 1569 + $viewer = $this->requireViewer(); 1570 + 1571 + $extensions = PhabricatorExportEngineExtension::getAllExtensions(); 1572 + 1573 + $supported = array(); 1574 + foreach ($extensions as $extension) { 1575 + $extension = clone $extension; 1576 + $extension->setViewer($viewer); 1577 + 1578 + if ($extension->supportsObject($object)) { 1579 + $supported[] = $extension; 1580 + } 1581 + } 1582 + 1583 + return $supported; 1526 1584 } 1527 1585 1528 1586 }
+43
src/infrastructure/customfield/field/PhabricatorCustomField.php
··· 35 35 const ROLE_HERALD = 'herald'; 36 36 const ROLE_EDITENGINE = 'EditEngine'; 37 37 const ROLE_HERALDACTION = 'herald.action'; 38 + const ROLE_EXPORT = 'export'; 38 39 39 40 40 41 /* -( Building Applications with Custom Fields )--------------------------- */ ··· 299 300 case self::ROLE_EDITENGINE: 300 301 return $this->shouldAppearInEditView() || 301 302 $this->shouldAppearInEditEngine(); 303 + case self::ROLE_EXPORT: 304 + return $this->shouldAppearInDataExport(); 302 305 case self::ROLE_DEFAULT: 303 306 return true; 304 307 default: ··· 1359 1362 return $this->proxy->updateAbstractDocument($document); 1360 1363 } 1361 1364 return $document; 1365 + } 1366 + 1367 + 1368 + /* -( Data Export )-------------------------------------------------------- */ 1369 + 1370 + 1371 + public function shouldAppearInDataExport() { 1372 + if ($this->proxy) { 1373 + return $this->proxy->shouldAppearInDataExport(); 1374 + } 1375 + 1376 + try { 1377 + $this->newExportFieldType(); 1378 + return true; 1379 + } catch (PhabricatorCustomFieldImplementationIncompleteException $ex) { 1380 + return false; 1381 + } 1382 + } 1383 + 1384 + public function newExportField() { 1385 + if ($this->proxy) { 1386 + return $this->proxy->newExportField(); 1387 + } 1388 + 1389 + return $this->newExportFieldType() 1390 + ->setLabel($this->getFieldName()); 1391 + } 1392 + 1393 + public function newExportData() { 1394 + if ($this->proxy) { 1395 + return $this->proxy->newExportData(); 1396 + } 1397 + throw new PhabricatorCustomFieldImplementationIncompleteException($this); 1398 + } 1399 + 1400 + protected function newExportFieldType() { 1401 + if ($this->proxy) { 1402 + return $this->proxy->newExportFieldType(); 1403 + } 1404 + throw new PhabricatorCustomFieldImplementationIncompleteException($this); 1362 1405 } 1363 1406 1364 1407
+3
src/infrastructure/customfield/standard/PhabricatorStandardCustomField.php
··· 496 496 return $this->getFieldValue(); 497 497 } 498 498 499 + public function newExportData() { 500 + return $this->getFieldValue(); 501 + } 499 502 500 503 }
+4
src/infrastructure/customfield/standard/PhabricatorStandardCustomFieldInt.php
··· 124 124 return new ConduitIntParameterType(); 125 125 } 126 126 127 + protected function newExportFieldType() { 128 + return new PhabricatorIntExportField(); 129 + } 130 + 127 131 }
+4
src/infrastructure/customfield/standard/PhabricatorStandardCustomFieldText.php
··· 76 76 return new ConduitStringParameterType(); 77 77 } 78 78 79 + protected function newExportFieldType() { 80 + return new PhabricatorStringExportField(); 81 + } 82 + 79 83 }
+86
src/infrastructure/export/PhabricatorCustomFieldExportEngineExtension.php
··· 1 + <?php 2 + 3 + final class PhabricatorCustomFieldExportEngineExtension 4 + extends PhabricatorExportEngineExtension { 5 + 6 + const EXTENSIONKEY = 'custom-field'; 7 + 8 + private $object; 9 + 10 + public function supportsObject($object) { 11 + $this->object = $object; 12 + return ($object instanceof PhabricatorCustomFieldInterface); 13 + } 14 + 15 + public function newExportFields() { 16 + $prototype = $this->object; 17 + 18 + $fields = $this->newCustomFields($prototype); 19 + 20 + $results = array(); 21 + foreach ($fields as $field) { 22 + $field_key = $field->getModernFieldKey(); 23 + 24 + $results[] = $field->newExportField() 25 + ->setKey($field_key); 26 + } 27 + 28 + return $results; 29 + } 30 + 31 + public function newExportData(array $objects) { 32 + $viewer = $this->getViewer(); 33 + 34 + $field_map = array(); 35 + foreach ($objects as $object) { 36 + $object_phid = $object->getPHID(); 37 + 38 + $fields = PhabricatorCustomField::getObjectFields( 39 + $object, 40 + PhabricatorCustomField::ROLE_EXPORT); 41 + 42 + $fields 43 + ->setViewer($viewer) 44 + ->readFieldsFromObject($object); 45 + 46 + $field_map[$object_phid] = $fields; 47 + } 48 + 49 + $all_fields = array(); 50 + foreach ($field_map as $field_list) { 51 + foreach ($field_list->getFields() as $field) { 52 + $all_fields[] = $field; 53 + } 54 + } 55 + 56 + id(new PhabricatorCustomFieldStorageQuery()) 57 + ->addFields($all_fields) 58 + ->execute(); 59 + 60 + $results = array(); 61 + foreach ($objects as $object) { 62 + $object_phid = $object->getPHID(); 63 + $object_fields = $field_map[$object_phid]; 64 + 65 + $map = array(); 66 + foreach ($object_fields->getFields() as $field) { 67 + $key = $field->getModernFieldKey(); 68 + $map[$key] = $field->newExportData(); 69 + } 70 + 71 + $results[] = $map; 72 + } 73 + 74 + return $results; 75 + } 76 + 77 + private function newCustomFields($object) { 78 + $fields = PhabricatorCustomField::getObjectFields( 79 + $object, 80 + PhabricatorCustomField::ROLE_EXPORT); 81 + $fields->setViewer($this->getViewer()); 82 + 83 + return $fields->getFields(); 84 + } 85 + 86 + }
+31
src/infrastructure/export/PhabricatorExportEngineExtension.php
··· 1 + <?php 2 + 3 + abstract class PhabricatorExportEngineExtension extends Phobject { 4 + 5 + private $viewer; 6 + 7 + final public function getExtensionKey() { 8 + return $this->getPhobjectClassConstant('EXTENSIONKEY'); 9 + } 10 + 11 + final public function setViewer($viewer) { 12 + $this->viewer = $viewer; 13 + return $this; 14 + } 15 + 16 + final public function getViewer() { 17 + return $this->viewer; 18 + } 19 + 20 + abstract public function supportsObject($object); 21 + abstract public function newExportFields(); 22 + abstract public function newExportData(array $objects); 23 + 24 + final public static function getAllExtensions() { 25 + return id(new PhutilClassMapQuery()) 26 + ->setAncestorClass(__CLASS__) 27 + ->setUniqueMethod('getExtensionKey') 28 + ->execute(); 29 + } 30 + 31 + }