diff --git a/Civi/Api4/Action/Entity/Get.php b/Civi/Api4/Action/Entity/Get.php index 445e962..dcb77c5 100644 --- a/Civi/Api4/Action/Entity/Get.php +++ b/Civi/Api4/Action/Entity/Get.php @@ -29,12 +29,26 @@ use Civi\Api4\Generic\AbstractAction; use Civi\Api4\Generic\Result; +use Civi\Api4\Utils\ReflectionUtils; /** * Get entities + * + * @method $this setSelect(array $value) + * @method $this addSelect(string $value) + * @method array getSelect() */ class Get extends AbstractAction { + /** + * Which attributes of the entities should be returned? + * + * @options name, description, comment + * + * @var array + */ + protected $select = []; + /** * Scan all api directories to discover entities * @@ -48,16 +62,25 @@ public function _run(Result $result) { foreach (glob("$dir/*.php") as $file) { $matches = []; preg_match('/(\w*).php/', $file, $matches); - $entities[$matches[1]] = $matches[1]; + $entity = ['name' => $matches[1]]; + if (!$this->select || $this->select != ['name']) { + $this->addDocs($entity); + } + if ($this->select) { + $entity = array_intersect_key($entity, array_flip($this->select)); + } + $entities[$matches[1]] = $entity; } } } - $entities = array_values($entities); - if (in_array('BaseEntity', $entities)) { - unset($entities[array_search('BaseEntity', $entities)]); - } - sort($entities); - $result->exchangeArray($entities); + ksort($entities); + $result->exchangeArray(array_values($entities)); + } + + private function addDocs(&$entity) { + $reflection = new \ReflectionClass("\\Civi\\Api4\\" . $entity['name']); + $entity += ReflectionUtils::getCodeDocs($reflection); + unset($entity['package'], $entity['method']); } } diff --git a/Civi/Api4/Action/Entity/GetFields.php b/Civi/Api4/Action/Entity/GetFields.php index a62b67f..74806ec 100644 --- a/Civi/Api4/Action/Entity/GetFields.php +++ b/Civi/Api4/Action/Entity/GetFields.php @@ -40,13 +40,25 @@ public function _run(Result $result) { $includeCustom = $this->getIncludeCustom(); $entities = \Civi\Api4\Entity::get()->execute(); foreach ($entities as $entity) { - $data = ['entity' => $entity, 'fields' => []]; + $entity = ((array) $entity) + ['fields' => []]; // Prevent infinite recursion - if ($entity != 'Entity') { - $data['fields'] = (array) civicrm_api4($entity, 'getFields', ['action' => $action, 'includeCustom' => $includeCustom]); + if ($entity['name'] != 'Entity') { + $entity['fields'] = (array) civicrm_api4($entity['name'], 'getFields', ['action' => $action, 'includeCustom' => $includeCustom, 'select' => $this->select]); } - $result[] = $data; + $result[] = $entity; } } + /** + * @inheritDoc + */ + public function getParamInfo($param = NULL) { + $info = parent::getParamInfo($param); + if (!$param) { + // This action doesn't actually let you select fields. + unset($info['fields']); + } + return $info; + } + } diff --git a/Civi/Api4/Action/GetFields.php b/Civi/Api4/Action/GetFields.php index 373aed0..4683f87 100644 --- a/Civi/Api4/Action/GetFields.php +++ b/Civi/Api4/Action/GetFields.php @@ -37,7 +37,15 @@ * * @method $this setIncludeCustom(bool $value) * @method bool getIncludeCustom() + * @method $this setOptions(bool $value) + * @method bool getOptions() * @method $this setAction(string $value) + * @method $this setSelect(array $value) + * @method $this addSelect(string $value) + * @method array getSelect() + * @method $this setFields(array $value) + * @method $this addField(string $value) + * @method array getFields() */ class GetFields extends AbstractAction { @@ -68,7 +76,7 @@ class GetFields extends AbstractAction { * * @var array */ - protected $fields; + protected $fields = []; /** * Which attributes of the fields should be returned? @@ -77,7 +85,7 @@ class GetFields extends AbstractAction { * * @var array */ - protected $select; + protected $select = []; /** * @var string diff --git a/Civi/Api4/Contact.php b/Civi/Api4/Contact.php index 43e00bd..e0cab75 100644 --- a/Civi/Api4/Contact.php +++ b/Civi/Api4/Contact.php @@ -4,7 +4,12 @@ use Civi\Api4\Generic\AbstractEntity; /** - * Contact entity. + * Contacts - Individuals, Organizations, Households. + * + * This is the central entity in the CiviCRM database, and links to + * many other entities (Email, Phone, Participant, etc.). + * + * Creating a new contact requires at minimum a name or email address. * * @package Civi\Api4 */ diff --git a/Civi/Api4/Service/Schema/SchemaMapBuilder.php b/Civi/Api4/Service/Schema/SchemaMapBuilder.php index b2e46da..aeb3f4c 100644 --- a/Civi/Api4/Service/Schema/SchemaMapBuilder.php +++ b/Civi/Api4/Service/Schema/SchemaMapBuilder.php @@ -27,7 +27,7 @@ class SchemaMapBuilder { */ public function __construct(EventDispatcherInterface $dispatcher) { $this->dispatcher = $dispatcher; - $this->apiEntities = (array) Entity::get()->execute(); + $this->apiEntities = array_keys((array) Entity::get()->addSelect('name')->execute()->indexBy('name')); } /** diff --git a/ang/api4/Explorer.html b/ang/api4/Explorer.html index 3d2916f..ca09868 100644 --- a/ang/api4/Explorer.html +++ b/ang/api4/Explorer.html @@ -74,7 +74,9 @@
{{ helpContent.comment }}
+{{ text }}
+{{ key }}: {{ item }}
diff --git a/ang/api4/Explorer.js b/ang/api4/Explorer.js index 223c3f6..d3d415b 100644 --- a/ang/api4/Explorer.js +++ b/ang/api4/Explorer.js @@ -85,7 +85,7 @@ } function entityFields(entity) { - return _.result(_.findWhere(schema, {entity: entity}), 'fields'); + return _.result(_.findWhere(schema, {name: entity}), 'fields'); } function getFieldList() { @@ -326,7 +326,10 @@ if (data.schema) { schema = data.schema; entities.length = 0; - formatForSelect2(schema, entities, 'entity'); + formatForSelect2(schema, entities, 'name', ['description']); + if ($scope.entity && !$scope.action) { + showEntityHelp($scope.entity); + } } if (data.links) { links = data.links; @@ -338,6 +341,16 @@ }); } + // Help for an entity with no action selected + function showEntityHelp(entity) { + var entityInfo = _.findWhere(schema, {name: entity}); + $scope.helpTitle = helpTitle = $scope.entity; + $scope.helpContent = helpContent = { + description: entityInfo.description, + comment: entityInfo.comment + }; + } + if (!$scope.entity) { $scope.helpTitle = helpTitle = ts('Help'); $scope.helpContent = helpContent = {description: ts('Welcome to the api explorer.'), comment: ts('Select an entity to begin.')}; @@ -354,9 +367,8 @@ selectAction(); } - if ($scope.entity) { - $scope.helpTitle = helpTitle = $scope.entity; - $scope.helpContent = helpContent = {description: ts('Welcome to the api explorer.'), comment: ts('Select an action.')}; + if ($scope.entity && schema.length) { + showEntityHelp($scope.entity); } // Update route when changing entity diff --git a/tests/phpunit/Entity/ConformanceTest.php b/tests/phpunit/Entity/ConformanceTest.php index a957faa..edde5a9 100644 --- a/tests/phpunit/Entity/ConformanceTest.php +++ b/tests/phpunit/Entity/ConformanceTest.php @@ -43,8 +43,8 @@ public function getEntities() { $result = []; $entities = Entity::get()->setCheckPermissions(FALSE)->execute(); foreach ($entities as $entity) { - if ($entity != 'Entity') { - $result[] = [$entity]; + if ($entity['name'] != 'Entity') { + $result[] = [$entity['name']]; } } return $result; diff --git a/tests/phpunit/Entity/EntityTest.php b/tests/phpunit/Entity/EntityTest.php index 0e0707d..8f7ecd0 100644 --- a/tests/phpunit/Entity/EntityTest.php +++ b/tests/phpunit/Entity/EntityTest.php @@ -13,10 +13,11 @@ class EntityTest extends UnitTestCase { public function testEntityGet() { $result = Entity::get() ->setCheckPermissions(FALSE) - ->execute(); - $this->assertContains('Entity', $result, + ->execute() + ->indexBy('name'); + $this->assertArrayHasKey('Entity', $result, "Entity::get missing itself"); - $this->assertContains('Participant', $result, + $this->assertArrayHasKey('Participant', $result, "Entity::get missing Participant"); }