setCheckPermissions($checkPermissions); } /** * @return \Civi\Api4\Generic\BasicGetFieldsAction */ abstract public static function getFields(); /** * @return \Civi\Api4\Generic\CheckAccessAction */ public static function checkAccess() { return new CheckAccessAction(static::getEntityName(), __FUNCTION__); } /** * Returns a list of permissions needed to access the various actions in this api. * * @return array */ public static function permissions() { $permissions = \CRM_Core_Permission::getEntityActionPermissions(); // For legacy reasons the permissions are keyed by lowercase entity name $lcentity = \CRM_Core_DAO_AllCoreTables::convertEntityNameToLower(static::getEntityName()); // Merge permissions for this entity with the defaults return ($permissions[$lcentity] ?? []) + $permissions['default']; } /** * Get entity name from called class * * @return string */ protected static function getEntityName() { return self::stripNamespace(static::class); } /** * Overridable function to return a localized title for this entity. * * @param bool $plural * Whether to return a plural title. * @return string */ protected static function getEntityTitle($plural = FALSE) { $name = static::getEntityName(); $dao = \CRM_Core_DAO_AllCoreTables::getFullName($name); return $dao ? $dao::getEntityTitle($plural) : ($plural ? \CRM_Utils_String::pluralize($name) : $name); } /** * Overridable function to return menu paths related to this entity. * * @return array */ protected static function getEntityPaths() { return []; } /** * Magic method to return the action object for an api. * * @param string $action * @param array $args * @return AbstractAction * @throws NotImplementedException */ public static function __callStatic($action, $args) { $entity = static::getEntityName(); $nameSpace = str_replace('Civi\Api4\\', 'Civi\Api4\Action\\', static::class); // Find class for this action $entityAction = "$nameSpace\\" . ucfirst($action); if (class_exists($entityAction)) { $actionObject = new $entityAction($entity, $action); if (isset($args[0]) && $args[0] === FALSE) { $actionObject->setCheckPermissions(FALSE); } } else { throw new NotImplementedException("Api $entity $action version 4 does not exist."); } return $actionObject; } /** * Reflection function called by Entity::get() * * @see \Civi\Api4\Action\Entity\Get * @return array{name: string, title: string, description: string, title_plural: string, type: string, paths: array, class: string, primary_key: array, searchable: string, dao: string, label_field: string, icon: string} */ public static function getInfo() { $entityName = static::getEntityName(); $info = [ 'name' => $entityName, 'title' => static::getEntityTitle(), 'title_plural' => static::getEntityTitle(TRUE), 'type' => [self::stripNamespace(get_parent_class(static::class))], 'paths' => static::getEntityPaths(), 'class' => static::class, 'primary_key' => ['id'], // Entities without a @searchable annotation will default to secondary, // which makes them visible in SearchKit but not at the top of the list. 'searchable' => 'secondary', ]; // Add info for entities with a corresponding DAO $dao = \CRM_Core_DAO_AllCoreTables::getFullName($info['name']); if ($dao) { $info['paths'] = $dao::getEntityPaths(); $info['primary_key'] = $dao::$_primaryKey; $info['icon'] = $dao::$_icon; $info['label_field'] = $dao::$_labelField; $info['dao'] = $dao; $info['table_name'] = $dao::$_tableName; } foreach (ReflectionUtils::getTraits(static::class) as $trait) { $info['type'][] = self::stripNamespace($trait); } // Get DocBlock from APIv4 Entity class $reflection = new \ReflectionClass(static::class); $docBlock = ReflectionUtils::getCodeDocs($reflection, NULL, ['entity' => $info['name']]); // Convert docblock keys to snake_case foreach ($docBlock as $key => $val) { $docBlock[\CRM_Utils_String::convertStringToSnakeCase($key)] = $val; } // Filter docblock to only declared entity fields foreach (\Civi\Api4\Entity::$entityFields as $field) { if (isset($docBlock[$field['name']])) { $val = $docBlock[$field['name']]; // Convert to array if data_type == Array if (isset($field['data_type']) && $field['data_type'] === 'Array' && is_string($val)) { $val = \CRM_Core_DAO::unSerializeField($val, \CRM_Core_DAO::SERIALIZE_COMMA); } $info[$field['name']] = $val; } } if ($dao) { $info['description'] = $dao::getEntityDescription() ?? $info['description'] ?? NULL; } return $info; } /** * Remove namespace prefix from a class name * * @param string $className * @return string */ private static function stripNamespace($className) { return substr($className, strrpos($className, '\\') + 1); } }