From 7430e70d60cba8f3cb4bd6e5880506ab9361c4f0 Mon Sep 17 00:00:00 2001 From: Coleman Watts Date: Tue, 1 Jun 2021 20:23:16 -0400 Subject: [PATCH] APIv4 - Refactor Entity.get and deprecate the includeCustom param This makes Entity.get more efficient - it no longer does a file scan when getting one or more entities by name. Also deprecates the includeCustom param which was redundant with the where clause. This is the first APIv4 param to be deprecated - added handling to emit a warning when using a deprecated param and hide deprecated params in the APIv4 explorer. --- Civi/Api4/Action/Entity/Get.php | 82 ++++++++++++------- Civi/Api4/Entity.php | 1 + .../Subscriber/ValidateFieldsSubscriber.php | 3 + ang/api4Explorer/Explorer.js | 2 +- 4 files changed, 57 insertions(+), 31 deletions(-) diff --git a/Civi/Api4/Action/Entity/Get.php b/Civi/Api4/Action/Entity/Get.php index 765a3703a9..fbfe399e4d 100644 --- a/Civi/Api4/Action/Entity/Get.php +++ b/Civi/Api4/Action/Entity/Get.php @@ -29,54 +29,41 @@ use Civi\Api4\Utils\CoreUtil; * * Scans for api entities in core, enabled components & enabled extensions. * - * Also includes pseudo-entities from multi-record custom groups by default. - * - * @method $this setIncludeCustom(bool $value) - * @method bool getIncludeCustom() + * Also includes pseudo-entities from multi-record custom groups. */ class Get extends \Civi\Api4\Generic\BasicGetAction { /** - * Include custom-field-based pseudo-entities? - * * @var bool + * @deprecated */ - protected $includeCustom = TRUE; + protected $includeCustom; /** * Scan all api directories to discover entities */ protected function getRecords() { $entities = []; - $toGet = $this->_itemsToGet('name'); - $locations = array_merge([\Civi::paths()->getPath('[civicrm.root]/Civi.php')], - array_column(\CRM_Extension_System::singleton()->getMapper()->getActiveModuleFiles(), 'filePath') - ); - $enabledComponents = array_keys(\CRM_Core_Component::getEnabledComponents()); - foreach ($locations as $location) { - $dir = \CRM_Utils_File::addTrailingSlash(dirname($location)) . 'Civi/Api4'; - if (is_dir($dir)) { - foreach (glob("$dir/*.php") as $file) { - $matches = []; - preg_match('/(\w*)\.php$/', $file, $matches); - $className = '\Civi\Api4\\' . $matches[1]; - if (is_a($className, '\Civi\Api4\Generic\AbstractEntity', TRUE)) { - $info = $className::getInfo(); - $entityName = $info['name']; - $daoName = $info['dao'] ?? NULL; - // Only include DAO entities from enabled components - if ((!$toGet || in_array($entityName, $toGet)) && - (!$daoName || !defined("{$daoName}::COMPONENT") || in_array($daoName::COMPONENT, $enabledComponents)) - ) { - $entities[$info['name']] = $info; - } + $namesRequested = $this->_itemsToGet('name'); + + if ($namesRequested) { + foreach ($namesRequested as $entityName) { + if (strpos($entityName, 'Custom_') !== 0) { + $className = CoreUtil::getApiClass($entityName); + if ($className) { + $this->loadEntity($className, $entities); } } } } + else { + foreach ($this->getAllApiClasses() as $className) { + $this->loadEntity($className, $entities); + } + } // Fetch custom entities unless we've already fetched everything requested - if ($this->includeCustom && (!$toGet || array_diff($toGet, array_keys($entities)))) { + if (!$namesRequested || array_diff($namesRequested, array_keys($entities))) { $this->addCustomEntities($entities); } @@ -84,6 +71,41 @@ class Get extends \Civi\Api4\Generic\BasicGetAction { return $entities; } + /** + * @param \Civi\Api4\Generic\AbstractEntity $className + * @param array $entities + */ + private function loadEntity($className, array &$entities) { + $info = $className::getInfo(); + $daoName = $info['dao'] ?? NULL; + // Only include DAO entities from enabled components + if (!$daoName || !defined("{$daoName}::COMPONENT") || array_key_exists($daoName::COMPONENT, \CRM_Core_Component::getEnabledComponents())) { + $entities[$info['name']] = $info; + } + } + + /** + * @return \Civi\Api4\Generic\AbstractEntity[] + */ + private function getAllApiClasses() { + $classNames = []; + $locations = array_merge([\Civi::paths()->getPath('[civicrm.root]/Civi.php')], + array_column(\CRM_Extension_System::singleton()->getMapper()->getActiveModuleFiles(), 'filePath') + ); + foreach ($locations as $location) { + $dir = \CRM_Utils_File::addTrailingSlash(dirname($location)) . 'Civi/Api4'; + if (is_dir($dir)) { + foreach (glob("$dir/*.php") as $file) { + $className = 'Civi\Api4\\' . basename($file, '.php'); + if (is_a($className, 'Civi\Api4\Generic\AbstractEntity', TRUE)) { + $classNames[] = $className; + } + } + } + } + return $classNames; + } + /** * Add custom-field pseudo-entities * diff --git a/Civi/Api4/Entity.php b/Civi/Api4/Entity.php index aa67b99a8a..00a99f6b33 100644 --- a/Civi/Api4/Entity.php +++ b/Civi/Api4/Entity.php @@ -64,6 +64,7 @@ class Entity extends Generic\AbstractEntity { 'options' => [ 'AbstractEntity' => 'AbstractEntity', 'DAOEntity' => 'DAOEntity', + 'CustomValue' => 'CustomValue', 'BasicEntity' => 'BasicEntity', 'EntityBridge' => 'EntityBridge', 'OptionList' => 'OptionList', diff --git a/Civi/Api4/Event/Subscriber/ValidateFieldsSubscriber.php b/Civi/Api4/Event/Subscriber/ValidateFieldsSubscriber.php index e1aaa65216..65b7cc1bdf 100644 --- a/Civi/Api4/Event/Subscriber/ValidateFieldsSubscriber.php +++ b/Civi/Api4/Event/Subscriber/ValidateFieldsSubscriber.php @@ -37,6 +37,9 @@ class ValidateFieldsSubscriber extends Generic\AbstractPrepareSubscriber { if (!empty($info['type']) && !self::checkType($value, $info['type'])) { throw new \API_Exception('Parameter "' . $param . '" is not of the correct type. Expecting ' . implode(' or ', $info['type']) . '.'); } + if (!empty($info['deprecated']) && isset($value)) { + \CRM_Core_Error::deprecatedWarning('APIv4 ' . $apiRequest->getEntityName() . ".$param parameter is deprecated."); + } } } } diff --git a/ang/api4Explorer/Explorer.js b/ang/api4Explorer/Explorer.js index 72cc5c6fa5..5cc419a646 100644 --- a/ang/api4Explorer/Explorer.js +++ b/ang/api4Explorer/Explorer.js @@ -284,7 +284,7 @@ specialParams.push('limit', 'offset'); } return _.transform($scope.availableParams, function(genericParams, param, name) { - if (!_.contains(specialParams, name) && + if (!_.contains(specialParams, name) && !param.deprecated && !(typeof paramType !== 'undefined' && !_.contains(paramType, param.type[0])) && !(typeof defaultNull !== 'undefined' && ((param.default === null) !== defaultNull)) ) { -- 2.25.1