Correct a parameter order swap in "diffusion.historyquery" for Mercurial
[phabricator.git] / src / applications / phid / handle / pool / PhabricatorHandleList.php
blobc3c6f40324e54cebc64b4ed8e494deea03c32016
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 public function rewind() {
130 $this->cursor = 0;
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() {
142 ++$this->cursor;
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() {
181 throw new Exception(
182 pht(
183 'Trying to mutate a %s, but this is not permitted; '.
184 'handle lists are immutable.',
185 __CLASS__));
189 /* -( Countable )---------------------------------------------------------- */
192 public function count() {
193 return $this->count;