Skip to content

Instantly share code, notes, and snippets.

@pixelwhip
Created February 25, 2012 23:44
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save pixelwhip/1911705 to your computer and use it in GitHub Desktop.
Save pixelwhip/1911705 to your computer and use it in GitHub Desktop.
Creates an element object as a basis for a more consistent render array.
<?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