Correct Aphlict websocket URI construction after PHP8 compatibility changes
[phabricator.git] / src / applications / phid / handle / pool / PhabricatorHandleList.php
blob1418a107c03435537649a2925b44df3c5ff3841e
1 <?php
3 /**
4 * A list of object handles.
6 * This is a convenience class which behaves like an array but makes working
7 * with handles more convenient, improves their caching and batching semantics,
8 * and provides some utility behavior.
10 * Load a handle list by calling `loadHandles()` on a `$viewer`:
12 * $handles = $viewer->loadHandles($phids);
14 * This creates a handle list object, which behaves like an array of handles.
15 * However, it benefits from the viewer's internal handle cache and performs
16 * just-in-time bulk loading.
18 final class PhabricatorHandleList
19 extends Phobject
20 implements
21 Iterator,
22 ArrayAccess,
23 Countable {
25 private $handlePool;
26 private $phids;
27 private $count;
28 private $handles;
29 private $cursor;
30 private $map;
32 public function setHandlePool(PhabricatorHandlePool $pool) {
33 $this->handlePool = $pool;
34 return $this;
37 public function setPHIDs(array $phids) {
38 $this->phids = $phids;
39 $this->count = count($phids);
40 return $this;
43 private function loadHandles() {
44 $this->handles = $this->handlePool->loadPHIDs($this->phids);
47 private function getHandle($phid) {
48 if ($this->handles === null) {
49 $this->loadHandles();
52 if (empty($this->handles[$phid])) {
53 throw new Exception(
54 pht(
55 'Requested handle "%s" was not loaded.',
56 $phid));
59 return $this->handles[$phid];
63 /**
64 * Get a handle from this list if it exists.
66 * This has similar semantics to @{function:idx}.
68 public function getHandleIfExists($phid, $default = null) {
69 if ($this->handles === null) {
70 $this->loadHandles();
73 return idx($this->handles, $phid, $default);
77 /**
78 * Create a new list with a subset of the PHIDs in this list.
80 public function newSublist(array $phids) {
81 foreach ($phids as $phid) {
82 if (!isset($this[$phid])) {
83 throw new Exception(
84 pht(
85 'Trying to create a new sublist of an existing handle list, '.
86 'but PHID "%s" does not appear in the parent list.',
87 $phid));
91 return $this->handlePool->newHandleList($phids);
95 /* -( Rendering )---------------------------------------------------------- */
98 /**
99 * Return a @{class:PHUIHandleListView} which can render the handles in
100 * this list.
102 public function renderList() {
103 return id(new PHUIHandleListView())
104 ->setHandleList($this);
107 public function newListView() {
108 return id(new FuelHandleListView())
109 ->addHandleList($this);
113 * Return a @{class:PHUIHandleView} which can render a specific handle.
115 public function renderHandle($phid) {
116 if (!isset($this[$phid])) {
117 throw new Exception(
118 pht('Trying to render a handle which does not exist!'));
121 return id(new PHUIHandleView())
122 ->setHandleList($this)
123 ->setHandlePHID($phid);
126 /* -( Iterator )----------------------------------------------------------- */
129 #[\ReturnTypeWillChange]
130 public function rewind() {
131 $this->cursor = 0;
134 #[\ReturnTypeWillChange]
135 public function current() {
136 return $this->getHandle($this->phids[$this->cursor]);
139 #[\ReturnTypeWillChange]
140 public function key() {
141 return $this->phids[$this->cursor];
144 #[\ReturnTypeWillChange]
145 public function next() {
146 ++$this->cursor;
149 #[\ReturnTypeWillChange]
150 public function valid() {
151 return ($this->cursor < $this->count);
155 /* -( ArrayAccess )-------------------------------------------------------- */
158 #[\ReturnTypeWillChange]
159 public function offsetExists($offset) {
160 // NOTE: We're intentionally not loading handles here so that isset()
161 // checks do not trigger fetches. This gives us better bulk loading
162 // behavior, particularly when invoked through methods like renderHandle().
164 if ($this->map === null) {
165 $this->map = array_fill_keys($this->phids, true);
168 return isset($this->map[$offset]);
171 #[\ReturnTypeWillChange]
172 public function offsetGet($offset) {
173 if ($this->handles === null) {
174 $this->loadHandles();
176 return $this->handles[$offset];
179 #[\ReturnTypeWillChange]
180 public function offsetSet($offset, $value) {
181 $this->raiseImmutableException();
184 #[\ReturnTypeWillChange]
185 public function offsetUnset($offset) {
186 $this->raiseImmutableException();
189 private function raiseImmutableException() {
190 throw new Exception(
191 pht(
192 'Trying to mutate a %s, but this is not permitted; '.
193 'handle lists are immutable.',
194 __CLASS__));
198 /* -( Countable )---------------------------------------------------------- */
201 #[\ReturnTypeWillChange]
202 public function count() {
203 return $this->count;