1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-11-13 02:12:41 +01:00
phorge-phorge/src/view/AphrontView.php
epriestley 8ac2da9850 Provide hasChildren() to replace isEmptyContent()
Summary:
Fixes T3698. Sometimes views need to render differently depending on whether they contain content or not. The existing approach for this is `isEmptyContent()`, which doesn't work well and is sort of hacky (it implies double-rendering content, which is not always free or side-effect free).

Instead, provide a test for an element without children. This test is powerful enough to catch the easy cases of `null`, etc., and just do the expected thing, but will not catch a View which is reduced upon rendering. Since this is rare and we have no actual need for it today, just accept that as a limitation.

Test Plan:
Viewed Timeline and Feed UI examples. Viewed Feed (feed), Pholio (timelineview), and Differential (old transactionview).

{F53915}

Reviewers: chad, btrahan

Reviewed By: chad

CC: aran

Maniphest Tasks: T3698

Differential Revision: https://secure.phabricator.com/D6718
2013-08-12 07:51:01 -07:00

145 lines
3.3 KiB
PHP

<?php
/**
* @task children Managing Children
*/
abstract class AphrontView extends Phobject
implements PhutilSafeHTMLProducerInterface {
protected $user;
protected $children = array();
/* -( Configuration )------------------------------------------------------ */
/**
* @task config
*/
public function setUser(PhabricatorUser $user) {
$this->user = $user;
return $this;
}
/**
* @task config
*/
protected function getUser() {
return $this->user;
}
/* -( Managing Children )-------------------------------------------------- */
/**
* Test if this View accepts children.
*
* By default, views accept children, but subclases may override this method
* to prevent children from being appended. Doing so will cause
* @{method:appendChild} to throw exceptions instead of appending children.
*
* @return bool True if the View should accept children.
* @task children
*/
protected function canAppendChild() {
return true;
}
/**
* Append a child to the list of children.
*
* This method will only work if the view supports children, which is
* determined by @{method:canAppendChild}.
*
* @param wild Something renderable.
* @return this
*/
final public function appendChild($child) {
if (!$this->canAppendChild()) {
$class = get_class($this);
throw new Exception(
pht("View '%s' does not support children.", $class));
}
$this->children[] = $child;
return $this;
}
/**
* Produce children for rendering.
*
* Historically, this method reduced children to a string representation,
* but it no longer does.
*
* @return wild Renderable children.
* @task
*/
final protected function renderChildren() {
return $this->children;
}
/**
* Test if an element has no children.
*
* @return bool True if this element has children.
* @task children
*/
final public function hasChildren() {
if ($this->children) {
$this->children = $this->reduceChildren($this->children);
}
return (bool)$this->children;
}
/**
* Reduce effectively-empty lists of children to be actually empty. This
* recursively removes `null`, `''`, and `array()` from the list of children
* so that @{method:hasChildren} can more effectively align with expectations.
*
* NOTE: Because View children are not rendered, a View which renders down
* to nothing will not be reduced by this method.
*
* @param list<wild> Renderable children.
* @return list<wild> Reduced list of children.
* @task children
*/
private function reduceChildren(array $children) {
foreach ($children as $key => $child) {
if ($child === null) {
unset($children[$key]);
} else if ($child === '') {
unset($children[$key]);
} else if (is_array($child)) {
$child = $this->reduceChildren($child);
if ($child) {
$children[$key] = $child;
} else {
unset($children[$key]);
}
}
}
return $children;
}
/* -( Rendering )---------------------------------------------------------- */
abstract public function render();
/* -( PhutilSafeHTMLProducerInterface )------------------------------------ */
public function producePhutilSafeHTML() {
return $this->render();
}
}