-
-
Save mrsinguyen/1921442 to your computer and use it in GitHub Desktop.
Creates an element object as a basis for a more consistent render array.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* @file | |
* Creates an element object as a basis for a more consistent render array. | |
* | |
* The current Drupal 7 render array is very powerful but hard to manage due to | |
* inconsistencies and information overload. This proof of concept aims to | |
* create a better separation between what is meant to be rendered and what is | |
* extra contextual information used by module developers. It tries to strike | |
* a balance between flexibility and discoverability. The general idea is | |
* developers and themers have a simple and consistent way to alter markup, | |
* while beginners have a simple way to display content in a template. | |
* Example: <?php render($element); ?> | |
* Example: <?php $element->add_class('clearfix'); ?> | |
* Example: <?php $element->strip_classes(); ?> | |
* Example: <?php $element->set_tag('h1'); ?> | |
* | |
*/ | |
class element | |
{ | |
public $content; // String or Array: Contents defined as an array of strings or elements. | |
public $tag; // String: A markup tag. ex. 'h1' or 'div' | |
public $attributes; // Array: Attributes to be added to the tag. ex. 'href' or 'class' | |
public $wrappers; // Array: Markup elements the wrap this element. | |
public $context; // Array: Additional information to be passed along with the element that may be helpful in altering it. | |
/** | |
* Constructs a render element. | |
* @param string or array $content Contents defined as a string or an array of strings or elements. | |
* @param string $tag A markup tag. ex. 'h1' or 'div' | |
* @param array $attributes Attributes to be added to the tag. ex. 'href' or 'class' | |
* @param array $wrappers An array of elements to wrap around this element. | |
* @param array $context Additional information to be passed along with the element that may be helpful in altering it. | |
*/ | |
public function __construct($content = NULL, $tag = NULL, $attributes = array(), $wrappers = array(), $context = array()) { | |
$this->content = $content; | |
$this->tag = $tag; | |
$this->attributes = $attributes; | |
$this->wrappers = $wrappers; | |
$this->context = $context; | |
} | |
/** | |
* Renders this element from the inside out. | |
* @return string | |
*/ | |
public function render_element() { | |
$output = ''; | |
// If there is content, render it and add it to the output. | |
if (!empty($this->content)) { | |
$output .= $this->render_content(); | |
} | |
// If a tag is set, wrap it around the content. | |
if ($this->tag) { | |
$output = $this->render_tag($output); | |
} | |
// If wrappers are set, wrap them around the tag. | |
if ($this->wrappers) { | |
$output = $this->render_wrappers($output); | |
} | |
return PHP_EOL . $output; | |
} | |
/** | |
* Renders this element's content into a string. | |
* @return string | |
*/ | |
public function render_content() { | |
$output = ''; | |
// If content is a string, add it to the output. | |
if (gettype($this->content) == 'string') { | |
$output = $this->content; | |
} | |
// If content is an array, add each element to the output. | |
elseif (gettype($this->content) == 'array') { | |
foreach ($this->content as $key => $element) { | |
if (gettype($element) == 'object') | |
$output .= $element->render_element(); | |
else { | |
$output .= $element; | |
} | |
} | |
} | |
return $output; | |
} | |
/** | |
* Renders a tag and its attributes, wrapping it around content if needed. | |
* @param string $content Optional content to wrap this tag around. | |
* @return string | |
*/ | |
public function render_tag($content = NULL) { | |
$prefix = '<' . $this->tag . $this->render_attributes(); | |
// If there is content, wrap it. Otherwise close the tag. | |
if ($content) { | |
$prefix .= '>'; | |
$suffix = '</' . $this->tag . '>'; | |
} | |
else { | |
$suffix = ' />'; | |
} | |
$output = $prefix . $content . $suffix; | |
return $output; | |
} | |
/** | |
* Renders the wrappers around some content. | |
* @param string $content The content to add wrappers to. | |
* @return string | |
*/ | |
public function render_wrappers($content = NULL) { | |
$output = $content; | |
// If a tag is set, wrap it around the content. | |
if (!empty($this->wrappers)) { | |
foreach ($this->wrappers as $key => $wrapper) { | |
$output = PHP_EOL . $wrapper->render_tag($output); | |
} | |
} | |
return $output; | |
} | |
/** | |
* Renders this element's attributes to a string. | |
* @return string | |
*/ | |
public function render_attributes() { | |
// Check to see if we have attributes, if so, return them as a string. | |
if (!empty($this->attributes)) { | |
return drupal_attributes($this->attributes); | |
} | |
} | |
/** | |
* Sets the tag of the element. | |
* @param string $tag A markup tag to add to the element. | |
*/ | |
public function set_tag($tag) { | |
$this->tag = $tag; | |
} | |
/** | |
* Removes the tag from the element. | |
* @param object $element An element object to use as the wrapper. | |
*/ | |
public function strip_tag() { | |
$this->tag = NULL; | |
} | |
/** | |
* Removes all classes from the element. | |
*/ | |
public function strip_classes() { | |
unset($this->attributes['class']); | |
} | |
/** | |
* Adds a CSS class to the element. | |
*/ | |
public function add_class($class) { | |
$this->attributes['class'][] = $class; | |
} | |
/** | |
* Removes all wrappers from the element. | |
*/ | |
public function strip_wrappers() { | |
$this->wrappers = array(); | |
} | |
/** | |
* Adds a wrapper to the element. | |
* @param object $element An element object to use as the wrapper | |
*/ | |
public function add_wrapper($element) { | |
$this->wrappers[] = $element; | |
} | |
} | |
/** | |
* Prints a rendered element to the screen. | |
* @param object $element The element to be printed. | |
*/ | |
function render($element = NULL) { | |
if ($element) { | |
print $element->render_element(); | |
} | |
} | |
function drupal_attributes(array $attributes = array()) { | |
foreach ($attributes as $attribute => &$data) { | |
$data = implode(' ', (array) $data); | |
$data = $attribute . '="' . /*check_plain(*/$data/*)*/ . '"'; | |
} | |
return $attributes ? ' ' . implode(' ', $attributes) : ''; | |
} | |
/** | |
* A new implementation of theme_link which returns an element object | |
* instead of a string. All theme functions should return an element object. | |
* @param string or Array $content The content to display within the a tag. | |
* This can be NULL if the returned element is intended to be a wrapper. | |
* @param string $path The Drupal path for the link | |
* @param array $attributes The attributes to add to the a tag | |
* @param array $context The contextual information to be used when creating the path. See url(); | |
* @return element | |
*/ | |
function theme_link($content = NULL, $path, $attributes = array(), $context = array()) { | |
$attributes['href'] = check_plain(url($path), $context); | |
return new element($content, 'a', $attributes, array(), $context); | |
} | |
render(new element('Render Element Test', 'h1')); | |
print '<h3>Element with no content</h3>'; | |
$soft_return = new element(NULL, 'br'); | |
render($soft_return); | |
render($non_existent_element); // This logs a PHP Notice. Anyway around that? | |
print '<pre>'; | |
print_r($soft_return); | |
print '</pre>'; | |
print '<h3>Element with no tag</h3>'; | |
$plain_text = new element('This is just a string of content'); | |
render($plain_text); | |
print '<pre>'; | |
print_r($plain_text); | |
print '</pre>'; | |
print '<h3>Element with attributes but no content</h3>'; | |
$anchor = new element( | |
NULL, | |
'a', | |
array( | |
'id' => 'top', | |
'class' => array( | |
'super', | |
'element-invisible', | |
) | |
) | |
); | |
render($anchor); | |
print '<pre>'; | |
print_r($anchor); | |
print '</pre>'; | |
print '<h3>Element with nested content</h3>'; | |
$list = new element( | |
array ( | |
new element('List Item 1', 'li'), | |
new element('List Item 2', 'li'), | |
new element('List Item 3', 'li'), | |
'How did this get there?', | |
), | |
'ul', | |
array( | |
'class' => array( | |
'menu', | |
'inline', | |
) | |
) | |
); | |
render($list); | |
print '<pre>'; | |
print_r($list); | |
print '</pre>'; | |
print '<h3>Element with wrappers</h3>'; | |
$block = new element( | |
array ( | |
'This is an awesome heading', | |
new element('with a fancy subheading', 'small'), | |
), | |
'h2', | |
array( | |
'class' => array( | |
'block-title', | |
) | |
), | |
array( | |
new element(NULL, 'div'), | |
new element(NULL, 'header'), | |
new element(NULL, 'section'), | |
) | |
); | |
render($block); | |
print '<pre>'; | |
print_r($block); | |
print '</pre>'; | |
print '<h3>Nuke the wrappers</h3>'; | |
$block->strip_wrappers(); | |
render($block); | |
print '<h3>Nuke the classes</h3>'; | |
$block->strip_classes(); | |
render($block); | |
print '<h3>Change the tag to an h1</h3>'; | |
$block->set_tag('h1'); | |
render($block); | |
print '<h3>Remove the tag</h3>'; | |
$block->strip_tag(); | |
render($block); | |
?> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment