Merge pull request #22957 from colemanw/afformClearCache
[civicrm-core.git] / Civi / Api4 / Generic / Result.php
1 <?php
2 /*
3 +--------------------------------------------------------------------+
4 | Copyright CiviCRM LLC. All rights reserved. |
5 | |
6 | This work is published under the GNU AGPLv3 license with some |
7 | permitted exceptions and without any warranty. For full license |
8 | and copyright information, see https://civicrm.org/licensing |
9 +--------------------------------------------------------------------+
10 */
11
12 namespace Civi\Api4\Generic;
13
14 /**
15 * Container for api results.
16 *
17 * The Result object has three functions:
18 *
19 * 1. Store the results of the API call (accessible via ArrayAccess).
20 * 2. Store metadata like the Entity & Action names.
21 * - Note: some actions extend the Result object to store extra metadata.
22 * For example, BasicReplaceAction returns ReplaceResult which includes the additional $deleted property to list any items deleted by the operation.
23 * 3. Provide convenience methods like `$result->first()` and `$result->indexBy($field)`.
24 */
25 class Result extends \ArrayObject implements \JsonSerializable {
26 /**
27 * @var string
28 */
29 public $entity;
30 /**
31 * @var string
32 */
33 public $action;
34 /**
35 * @var array
36 */
37 public $debug;
38 /**
39 * Api version
40 * @var int
41 */
42 public $version = 4;
43 /**
44 * @var int
45 */
46 public $rowCount;
47
48 private $indexedBy;
49
50 /**
51 * Return first result.
52 * @return array|null
53 */
54 public function first() {
55 foreach ($this as $values) {
56 return $values;
57 }
58 return NULL;
59 }
60
61 /**
62 * Return last result.
63 * @return array|null
64 */
65 public function last() {
66 $items = $this->getArrayCopy();
67 return array_pop($items);
68 }
69
70 /**
71 * Return the one-and-only result record.
72 *
73 * If there are too many or too few results, then throw an exception.
74 *
75 * @return array
76 * @throws \API_Exception
77 */
78 public function single() {
79 $result = NULL;
80 foreach ($this as $values) {
81 if ($result === NULL) {
82 $result = $values;
83 }
84 else {
85 throw new \API_Exception("Expected to find one {$this->entity} record, but there were multiple.");
86 }
87 }
88
89 if ($result === NULL) {
90 throw new \API_Exception("Expected to find one {$this->entity} record, but there were zero.");
91 }
92
93 return $result;
94 }
95
96 /**
97 * @param int $index
98 * @return array|null
99 */
100 public function itemAt($index) {
101 $length = $index < 0 ? 0 - $index : $index + 1;
102 if ($length > count($this)) {
103 return NULL;
104 }
105 return array_slice(array_values($this->getArrayCopy()), $index, 1)[0];
106 }
107
108 /**
109 * Re-index the results array (which by default is non-associative)
110 *
111 * Drops any item from the results that does not contain the specified key
112 *
113 * @param string $key
114 * @return $this
115 * @throws \API_Exception
116 */
117 public function indexBy($key) {
118 $this->indexedBy = $key;
119 if (count($this)) {
120 $newResults = [];
121 foreach ($this as $values) {
122 if (isset($values[$key])) {
123 $newResults[$values[$key]] = $values;
124 }
125 }
126 if (!$newResults) {
127 throw new \API_Exception("Key $key not found in api results");
128 }
129 $this->exchangeArray($newResults);
130 }
131 return $this;
132 }
133
134 /**
135 * Returns the number of results
136 *
137 * @return int
138 */
139 public function count() {
140 return $this->rowCount ?? parent::count();
141 }
142
143 /**
144 * Reduce each result to one field
145 *
146 * @param $name
147 * @return array
148 */
149 public function column($name) {
150 return array_column($this->getArrayCopy(), $name, $this->indexedBy);
151 }
152
153 /**
154 * @return array
155 */
156 public function jsonSerialize() {
157 return $this->getArrayCopy();
158 }
159
160 }