4 * @task children Managing Children
6 abstract class AphrontView
extends Phobject
7 implements PhutilSafeHTMLProducerInterface
{
10 protected $children = array();
13 /* -( Configuration )------------------------------------------------------ */
17 * Set the user viewing this element.
19 * @param PhabricatorUser Viewing user.
22 public function setViewer(PhabricatorUser
$viewer) {
23 $this->viewer
= $viewer;
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() {
37 throw new PhutilInvalidStateException('setViewer');
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
;
55 * Deprecated, use @{method:setViewer}.
60 public function setUser(PhabricatorUser
$user) {
61 return $this->setViewer($user);
66 * Deprecated, use @{method:getViewer}.
71 protected function getUser() {
72 if (!$this->hasViewer()) {
75 return $this->getViewer();
79 /* -( Managing Children )-------------------------------------------------- */
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.
92 protected function canAppendChild() {
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.
106 final public function appendChild($child) {
107 if (!$this->canAppendChild()) {
108 $class = get_class($this);
110 pht("View '%s' does not support children.", $class));
113 $this->children
[] = $child;
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.
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.
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.
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);
168 $children[$key] = $child;
170 unset($children[$key]);
177 public function getDefaultResourceSource() {
178 return 'phabricator';
181 public function requireResource($symbol) {
182 $response = CelerityAPI
::getStaticResourceResponse();
183 $response->requireResource($symbol, $this->getDefaultResourceSource());
187 public function initBehavior($name, $config = array()) {
188 Javelin
::initBehavior(
191 $this->getDefaultResourceSource());
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
210 public function willRender() {
215 abstract public function render();
218 /* -( PhutilSafeHTMLProducerInterface )------------------------------------ */
221 public function producePhutilSafeHTML() {
222 return $this->render();