Create your own HTML widgets with PHP
(Page 3 out of 4)Creating the Repeater Control
Our repeater control will be used to display all the items of an array, without having to use any PHP code in the page. First, create a new file called 'repeater_control.php' which will hold all the code for our control. Then create a second file called 'repeater_demo.php', and have it include repeater_control.php.
Let's start by setting up the basics. Unlike the previous examples where we used a simple callback function, we'll now be using a class method as a callback. See the code below for the first step of our repeater control.
include ('htmlparser.php');
// Create instance of our Repeater Control
$_Repeater = new Repeater_Control();
// Add callback
ob_start(array(&$_Repeater, 'process'));
Class Repeater_Control {
function process($content) {
return $content;
}
}
?>
The above code should be fairly self-explanatory, and it's quite similar to the previous examples. Let's also create a sample data array, so put the following code in repeater_demo.php:
include ('repeater_control.php');
$data = array(
'Dennis' => 'Pallett',
'John' => 'Smith',
'James' => 'Williams',
'David' => 'Moore',
'Paul' => 'Wilson',
'Mark' => 'Jones',
'George' => 'Allen',
'Brian' => 'Hall',
'Will' => 'Carter',
'Ronald' => 'Scott'
);
?>
What our Repeater Control has to do is take in an array, and loop through it. Our tag will look like this:
This should be repeated
</php:repeater>
Let's add some PHP code to our class so we can start using our repeater control. First, we have to get all the tags, using a regular expression:
// Find the tags
preg_match_all('/\<php:repeater([^>]*)\>(.*?)\<\/php:repeater\>/is', $content, $matches);
// Loop through each tag
for ($i=0; $i < count($matches['0']); $i++) {
$html = $matches['0'][$i];
$this->_process_tag(&$content, $html);
}
return $content;
}
After which, we process each tag using the _process_tag() method of the class, which looks like this so far:
// Parse tag
$parser = new HTML_Parser();
$output = $parser->parse($tag_html);
// XML Error?
if ($parser->xml_error == true) {
$error = 'XML Error: ' . $parser->xml_error_string . ' on line ' . $parser->xml_error_line_number;
$content = str_replace($html, $error, $content);
return false;
}
// Get tag structure and innerHTML
$tag = $output['0'];
$innerHTML = $tag['innerhtml'];
// Check array attribute
if (empty($tag['attr']['ARRAY'])) {
// No array, return error
$error = 'Array attribute not set - unable to use Repeater Control';
$content = str_replace($tag_html, $error, $content);
return false;
}
$array = $tag['attr']['ARRAY'];
// TODO: loop through the array
}
It's all fairly standard stuff which I've already covered, and it should be easy to understand. All we have to do now is loop through the array, but there's a problem. An array name is passed through the attribute name, but how does the repeater control know which array we mean? Sure, it could look for variables with the same name, but that's a very cumbersome way, and could lead to other problems as well.
A better solution would be to create a bind() method where our PHP script can pass the array to the repeater control. Something like this:
// Make sure arrays property exists
if (!isset($this->_arrays) OR !is_array($this->_arrays)) {
$this->_arrays = array();
}
// Check if another array with this name doesn't already exist
if (isset($this->_arrays[$name]) AND is_array($this->_arrays[$name])) {
trigger_error ('Unable to bind array `' . htmlentities($name) . '`, already exists.');
return false;
}
// Save array
$this->_arrays[$name] = $data;
return true;
}
All this function does is save the data under the name passed to the function, which can then be used by the _process_tag function.
Now that we have a bind() function, you will have to add the following line to repeater_demo.php:
$_Repeater->bind('data', $data);
Let's finish the _process_tag() function by adding the code that loops through the array:
if (!isset($this->_arrays[$array]) OR !is_array($this->_arrays[$array])) {
// No array, return error
$error = 'Invalid array, not binded - unable to use Repeater Control';
$content = str_replace($tag_html, $error, $content);
return false;
}
// Loop through array
$new_html = '';
foreach ($this->_arrays[$array] as $val) {
$new_html .= $innerHTML;
}
// Replace custom tag with new HTML
$content = str_replace($tag_html, $new_html, $content);
And there you have it, a simple repeater control. But we're not there yet, because we can only repeat static text at the moment, which means it's not possible to use the values of the array yet. Let's fix that by introducing two sub tags:
June 20th, 2006 at 2:41 pm
[…] HTML * that contains the subtags and * It replaces the subtags with the key & value from an associative array. * You must bind the widget to the array through * Example: * ’Elijah Wood’,’Aragorn’=>’Viggo Mortensen’) * $repeaterWidget->bind(’cast’,$array))?> * * * : *
* * * Will output the html: * Frodo:: Elijah Wood *
* Aragorn:: Viggo Mortensen *
* * @author RosSoft * @version 0.1 * @license MIT * * @link http://phpit.net/article/create-html-widgets-php/4/ */require_once(dirname(__FILE__) . DS . ‘widget_helper.php’);class RepeaterWidgetHelper extends WidgetHelper{ //main tags name => array subtags var $tag=array( ‘repeater:repeater’=>array(’repeater:key’,’repeater:value’) ); function tag_repeater_repeater($attr,$inner_html) { $array=$this->_get_bound($attr[’array’]); […]