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
32 public function setHandlePool(PhabricatorHandlePool
$pool) {
33 $this->handlePool
= $pool;
37 public function setPHIDs(array $phids) {
38 $this->phids
= $phids;
39 $this->count
= count($phids);
43 private function loadHandles() {
44 $this->handles
= $this->handlePool
->loadPHIDs($this->phids
);
47 private function getHandle($phid) {
48 if ($this->handles
=== null) {
52 if (empty($this->handles
[$phid])) {
55 'Requested handle "%s" was not loaded.',
59 return $this->handles
[$phid];
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) {
73 return idx($this->handles
, $phid, $default);
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])) {
85 'Trying to create a new sublist of an existing handle list, '.
86 'but PHID "%s" does not appear in the parent list.',
91 return $this->handlePool
->newHandleList($phids);
95 /* -( Rendering )---------------------------------------------------------- */
99 * Return a @{class:PHUIHandleListView} which can render the handles in
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])) {
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() {
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() {
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() {
192 'Trying to mutate a %s, but this is not permitted; '.
193 'handle lists are immutable.',
198 /* -( Countable )---------------------------------------------------------- */
201 #[\ReturnTypeWillChange]
202 public function count() {