Add a missing "GROUP BY" to MailQuery when querying for multiple recipients
[phabricator/blender.git] / src / view / AphrontView.php
blob669742f29bede74e42c2e2a89b8563caf2bc05a7
1 <?php
3 /**
4 * @task children Managing Children
5 */
6 abstract class AphrontView extends Phobject
7 implements PhutilSafeHTMLProducerInterface {
9 private $viewer;
10 protected $children = array();
13 /* -( Configuration )------------------------------------------------------ */
16 /**
17 * Set the user viewing this element.
19 * @param PhabricatorUser Viewing user.
20 * @return this
22 public function setViewer(PhabricatorUser $viewer) {
23 $this->viewer = $viewer;
24 return $this;
28 /**
29 * Get the user viewing this element.
31 * Throws an exception if no viewer has been set.
33 * @return PhabricatorUser Viewing user.
35 public function getViewer() {
36 if (!$this->viewer) {
37 throw new PhutilInvalidStateException('setViewer');
40 return $this->viewer;
44 /**
45 * Test if a viewer has been set on this element.
47 * @return bool True if a viewer is available.
49 public function hasViewer() {
50 return (bool)$this->viewer;
54 /**
55 * Deprecated, use @{method:setViewer}.
57 * @task config
58 * @deprecated
60 public function setUser(PhabricatorUser $user) {
61 return $this->setViewer($user);
65 /**
66 * Deprecated, use @{method:getViewer}.
68 * @task config
69 * @deprecated
71 protected function getUser() {
72 if (!$this->hasViewer()) {
73 return null;
75 return $this->getViewer();
79 /* -( Managing Children )-------------------------------------------------- */
82 /**
83 * Test if this View accepts children.
85 * By default, views accept children, but subclases may override this method
86 * to prevent children from being appended. Doing so will cause
87 * @{method:appendChild} to throw exceptions instead of appending children.
89 * @return bool True if the View should accept children.
90 * @task children
92 protected function canAppendChild() {
93 return true;
97 /**
98 * Append a child to the list of children.
100 * This method will only work if the view supports children, which is
101 * determined by @{method:canAppendChild}.
103 * @param wild Something renderable.
104 * @return this
106 final public function appendChild($child) {
107 if (!$this->canAppendChild()) {
108 $class = get_class($this);
109 throw new Exception(
110 pht("View '%s' does not support children.", $class));
113 $this->children[] = $child;
115 return $this;
120 * Produce children for rendering.
122 * Historically, this method reduced children to a string representation,
123 * but it no longer does.
125 * @return wild Renderable children.
126 * @task
128 final protected function renderChildren() {
129 return $this->children;
134 * Test if an element has no children.
136 * @return bool True if this element has children.
137 * @task children
139 final public function hasChildren() {
140 if ($this->children) {
141 $this->children = $this->reduceChildren($this->children);
143 return (bool)$this->children;
148 * Reduce effectively-empty lists of children to be actually empty. This
149 * recursively removes `null`, `''`, and `array()` from the list of children
150 * so that @{method:hasChildren} can more effectively align with expectations.
152 * NOTE: Because View children are not rendered, a View which renders down
153 * to nothing will not be reduced by this method.
155 * @param list<wild> Renderable children.
156 * @return list<wild> Reduced list of children.
157 * @task children
159 private function reduceChildren(array $children) {
160 foreach ($children as $key => $child) {
161 if ($child === null) {
162 unset($children[$key]);
163 } else if ($child === '') {
164 unset($children[$key]);
165 } else if (is_array($child)) {
166 $child = $this->reduceChildren($child);
167 if ($child) {
168 $children[$key] = $child;
169 } else {
170 unset($children[$key]);
174 return $children;
177 public function getDefaultResourceSource() {
178 return 'phabricator';
181 public function requireResource($symbol) {
182 $response = CelerityAPI::getStaticResourceResponse();
183 $response->requireResource($symbol, $this->getDefaultResourceSource());
184 return $this;
187 public function initBehavior($name, $config = array()) {
188 Javelin::initBehavior(
189 $name,
190 $config,
191 $this->getDefaultResourceSource());
192 return $this;
196 /* -( Rendering )---------------------------------------------------------- */
200 * Inconsistent, unreliable pre-rendering hook.
202 * This hook //may// fire before views render. It is not fired reliably, and
203 * may fire multiple times.
205 * If it does fire, views might use it to register data for later loads, but
206 * almost no datasources support this now; this is currently only useful for
207 * tokenizers. This mechanism might eventually see wider support or might be
208 * removed.
210 public function willRender() {
211 return;
215 abstract public function render();
218 /* -( PhutilSafeHTMLProducerInterface )------------------------------------ */
221 public function producePhutilSafeHTML() {
222 return $this->render();