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 public function rewind() {
133 public function current() {
134 return $this->getHandle($this->phids
[$this->cursor
]);
137 public function key() {
138 return $this->phids
[$this->cursor
];
141 public function next() {
145 public function valid() {
146 return ($this->cursor
< $this->count
);
150 /* -( ArrayAccess )-------------------------------------------------------- */
153 public function offsetExists($offset) {
154 // NOTE: We're intentionally not loading handles here so that isset()
155 // checks do not trigger fetches. This gives us better bulk loading
156 // behavior, particularly when invoked through methods like renderHandle().
158 if ($this->map
=== null) {
159 $this->map
= array_fill_keys($this->phids
, true);
162 return isset($this->map
[$offset]);
165 public function offsetGet($offset) {
166 if ($this->handles
=== null) {
167 $this->loadHandles();
169 return $this->handles
[$offset];
172 public function offsetSet($offset, $value) {
173 $this->raiseImmutableException();
176 public function offsetUnset($offset) {
177 $this->raiseImmutableException();
180 private function raiseImmutableException() {
183 'Trying to mutate a %s, but this is not permitted; '.
184 'handle lists are immutable.',
189 /* -( Countable )---------------------------------------------------------- */
192 public function count() {