Use trait instead of class for Entity Bridges; add OptionList trait
[civicrm-core.git] / Civi / Api4 / Generic / AbstractEntity.php
CommitLineData
19b53e5b 1<?php
380f3545
TO
2
3/*
4 +--------------------------------------------------------------------+
41498ac5 5 | Copyright CiviCRM LLC. All rights reserved. |
380f3545 6 | |
41498ac5
TO
7 | This work is published under the GNU AGPLv3 license with some |
8 | permitted exceptions and without any warranty. For full license |
9 | and copyright information, see https://civicrm.org/licensing |
380f3545
TO
10 +--------------------------------------------------------------------+
11 */
12
13/**
14 *
15 * @package CRM
ca5cec67 16 * @copyright CiviCRM LLC https://civicrm.org/licensing
380f3545
TO
17 */
18
19b53e5b
C
19namespace Civi\Api4\Generic;
20
21use Civi\API\Exception\NotImplementedException;
449c4e6b 22use Civi\Api4\Utils\ReflectionUtils;
19b53e5b
C
23
24/**
25 * Base class for all api entities.
26 *
9bafff7c
CW
27 * This is the most generic of 3 possible base classes for an APIv4 Entity
28 * (the other 2, which extend this class, are `BasicEntity` and `DAOEntity`).
19b53e5b 29 *
9bafff7c
CW
30 * Implementing an API by extending this class directly is appropriate when it does not implement
31 * all of the CRUD actions, or only a subset like `get` without `create`, `update` or `delete`;
32 * for example the RelationshipCache entity.
19b53e5b 33 *
9bafff7c
CW
34 * For all other APIs that do implement CRUD it is recommended to use:
35 * 1. `DAOEntity` for all entities with a DAO (sql table).
36 * 2. `BasicEntity` for all others, e.g. file-based entities.
37 *
38 * An entity which extends this class directly must, at minimum, implement the `getFields` action.
c2adedc1
CW
39 *
40 * @see https://lab.civicrm.org/extensions/api4example
19b53e5b
C
41 */
42abstract class AbstractEntity {
43
44 /**
6764a9d3 45 * @param bool $checkPermissions
19b53e5b
C
46 * @return \Civi\Api4\Action\GetActions
47 */
6764a9d3
CW
48 public static function getActions($checkPermissions = TRUE) {
49 return (new \Civi\Api4\Action\GetActions(self::getEntityName(), __FUNCTION__))
50 ->setCheckPermissions($checkPermissions);
19b53e5b
C
51 }
52
53 /**
c0c668ce 54 * @return \Civi\Api4\Generic\BasicGetFieldsAction
19b53e5b 55 */
c0c668ce 56 abstract public static function getFields();
19b53e5b
C
57
58 /**
59 * Returns a list of permissions needed to access the various actions in this api.
60 *
61 * @return array
62 */
63 public static function permissions() {
64 $permissions = \CRM_Core_Permission::getEntityActionPermissions();
65
66 // For legacy reasons the permissions are keyed by lowercase entity name
74c303ca 67 $lcentity = \CRM_Core_DAO_AllCoreTables::convertEntityNameToLower(self::getEntityName());
19b53e5b 68 // Merge permissions for this entity with the defaults
74c303ca 69 return ($permissions[$lcentity] ?? []) + $permissions['default'];
19b53e5b
C
70 }
71
72 /**
73 * Get entity name from called class
74 *
75 * @return string
76 */
77 protected static function getEntityName() {
90908aac 78 return self::stripNamespace(static::class);
19b53e5b
C
79 }
80
449c4e6b
CW
81 /**
82 * Overridable function to return a localized title for this entity.
83 *
7b66c3b5
AH
84 * @param bool $plural
85 * Whether to return a plural title.
449c4e6b
CW
86 * @return string
87 */
7b66c3b5 88 protected static function getEntityTitle($plural = FALSE) {
449c4e6b
CW
89 return static::getEntityName();
90 }
91
a7bd99ff
CW
92 /**
93 * Overridable function to return menu paths related to this entity.
94 *
95 * @return array
96 */
97 protected static function getEntityPaths() {
98 return [];
99 }
100
19b53e5b
C
101 /**
102 * Magic method to return the action object for an api.
103 *
104 * @param string $action
6764a9d3 105 * @param array $args
19b53e5b
C
106 * @return AbstractAction
107 * @throws NotImplementedException
108 */
109 public static function __callStatic($action, $args) {
110 $entity = self::getEntityName();
111 // Find class for this action
112 $entityAction = "\\Civi\\Api4\\Action\\$entity\\" . ucfirst($action);
113 if (class_exists($entityAction)) {
114 $actionObject = new $entityAction($entity, $action);
6764a9d3
CW
115 if (isset($args[0]) && $args[0] === FALSE) {
116 $actionObject->setCheckPermissions(FALSE);
117 }
19b53e5b
C
118 }
119 else {
120 throw new NotImplementedException("Api $entity $action version 4 does not exist.");
121 }
122 return $actionObject;
123 }
124
449c4e6b
CW
125 /**
126 * Reflection function called by Entity::get()
127 *
128 * @see \Civi\Api4\Action\Entity\Get
129 * @return array
130 */
131 public static function getInfo() {
132 $info = [
133 'name' => static::getEntityName(),
134 'title' => static::getEntityTitle(),
9813ae79 135 'title_plural' => static::getEntityTitle(TRUE),
465bc32a 136 'type' => [self::stripNamespace(get_parent_class(static::class))],
a7bd99ff 137 'paths' => static::getEntityPaths(),
449c4e6b 138 ];
465bc32a
CW
139 foreach (ReflectionUtils::getTraits(static::class) as $trait) {
140 $info['type'][] = self::stripNamespace($trait);
141 }
449c4e6b
CW
142 $reflection = new \ReflectionClass(static::class);
143 $info += ReflectionUtils::getCodeDocs($reflection, NULL, ['entity' => $info['name']]);
144 unset($info['package'], $info['method']);
145 return $info;
146 }
147
90908aac
CW
148 /**
149 * Remove namespace prefix from a class name
150 *
151 * @param string $className
152 * @return string
153 */
154 private static function stripNamespace($className) {
155 return substr($className, strrpos($className, '\\') + 1);
156 }
157
19b53e5b 158}