Data Object that is a multi-dimensional Array and Iterable
Posted: Sat Apr 29, 2006 7:31 pm
I've been pounding my head recently on how to create a system where I don't have to rewrite a ton of code over and over again that does the same thing. The concept of Data Objects is new to me, I've always encapulated functionality in a single class design pattern. Recently, I've been doing the whole Factory thing and loving it.
My thoughts however are if something of this complexity can be done in a better way.
I've yet to add the Iterator functionality, my question is should I? I mean, there is ArrayObject, which would probably do a better job of it, but then I would have to recode the class to use ArrayObject and I just can't do that since the documentation on why you would extend it isn't yet out there.
The second question is that I've been banging my head against the wall trying to figure out an intelligent way to return either the name or section without seeking ahead. The issue that in the multi-dimensional array is that the sections don't know what is in the subsections or what I mean is.
For instance if you add
Then try to access $sections['race'], then do I return 2 or Section? There is no possible way to know if they are assigning $sections['race'] to a variable or if they want to access $sections['race']['lap1'].
The issue is solved in the class by creating an array if both the name and section exist.
The next issue is that they may end up with something such as this:
$section['race']['section']['lap1']['section']['subsection']['section']['subsection']
and that defeats the purpose of the class.
My thoughts however are if something of this complexity can be done in a better way.
Code: Select all
class Section implements ArrayAccess, Iterator
{
/**
* Stores the Section Name for Iterator
* @name array $section
* @access private
*/
private $section = '';
/**
* Stores the Name Data
* @name array $nameStorage
* @access private
*/
private $nameStorage = array();
/**
* Stores the Section DataStore
* @name array $subsectionStorage
* @access private
*/
private $subsectionStorage = array();
/**
* Stores the Visibility DataStore
* @name array $visibilityStorage
* @access private
*/
private $visibilityStorage = array();
/**
* Stores the Restictions DataStore
* @name array $restrictionsStorage
* @access private
*/
private $restrictionsStorage = array();
function __construct($section)
{
$this->section = $section;
}
public function name($name, $value = false)
{
if($value !== false)
{
// Test Restrictions
$restrictions = $this->restrictions($name);
if($restrictions !== false)
{
$accessdenied = false;
if(array_search($value, $restrictions) === false)
{
$accessdenied = true;
}
// @todo Filters should use Security Filters Factory
if(array_search('alpha_filter', $restrictions) !== false)
{
if(ctype_alpha($value) == false)
{
throw new RestrictedValueException();
}
else
{
$accessdenied = false;
}
}
if(array_search('alnum_filter', $restrictions) !== false)
{
if(ctype_alnum($value) == false)
{
throw new RestrictedValueException();
}
else
{
$accessdenied = false;
}
}
if(array_search('hex_filter', $restrictions) !== false)
{
if(ctype_xdigit($value) == false)
{
throw new RestrictedValueException();
}
else
{
$accessdenied = false;
}
}
if(array_search('num_filter', $restrictions) !== false)
{
if(ctype_digit($value) == false)
{
throw new RestrictedValueException();
}
else
{
$accessdenied = false;
}
}
if($accessdenied === true)
{
throw new RestrictedValueException();
}
}
// If Restrictions past, then update value.
if(array_key_exists($name, $this->nameStorage) and ($value != NULL))
{
$count = count($this->nameStorage[$name]);
if($count > 1)
{
$this->nameStorage[$name][] = $value;
}
else if($count == 1)
{
$this->nameStorage[$name] = array($this->nameStorage[$name], $value);
}
}
else if(array_key_exists($name, $this->nameStorage) and ($value == NULL))
{
unset($this->nameStorage[$name]);
}
else
{
$this->nameStorage[$name] = $value;
}
}
else if(array_key_exists($name, $this->nameStorage) and $value === false)
{
return $this->nameStorage[$name];
}
return false;
}
public function section($section)
{
if(array_key_exists($section, $this->subsectionStorage))
{
return $this->subsectionStorage[$section];
}
else
{
$this->subsectionStorage[$section] = new ConfigurationSection;
return $this->subsectionStorage[$section];
}
}
public function restrictions($name, $value = false)
{
if($value !== false)
{
if(array_key_exists($name, $this->restrictionsStorage))
{
$count = count($this->restrictionsStorage[$name]);
if($count > 1)
{
$this->restrictionsStorage[$name][] = $value;
}
else if($count == 1)
{
$this->restrictionsStorage[$name][] = $this->restrictionsStorage[$name];
$this->restrictionsStorage[$name][] = $value;
}
}
else
{
$this->restrictionsStorage[$name] = $value;
}
}
else if(array_key_exists($name, $this->restrictionsStorage) and $value === false)
{
return $this->restrictionsStorage[$name];
}
return false;
}
public function visiblity($name, $value = false)
{
if($value !== false)
{
switch($value)
{
case 'show': break;
case 'hide': break;
default: $value = 'show'; break;
}
$this->restrictionsStorage[$name] = $value;
}
else if(array_key_exists($name, $this->visibilityStorage) and $value === false)
{
return $this->visibilityStorage[$name];
}
return false;
}
public function isUnique($name)
{
if(($this->nameExists($name) === true) and ($this->sectionExists($name) === true))
{
return false;
}
return true;
}
public function sectionExists($section)
{
if(array_key_exists($section, $this->subsectionStorage))
{
return true;
}
return false;
}
public function sectionUnset($section)
{
if(array_key_exists($section, $this->subsectionStorage))
{
unset($this->subsectionStorage[$section]);
}
}
public function nameExists($name)
{
if(array_key_exists($name, $this->nameStorage))
{
return true;
}
return false;
}
// ArrayAccess
public function offsetExists($name)
{
if(($this->sectionExists($name) === true) or ($this->nameExists($name) === true))
{
return true;
}
return false;
}
public function offsetUnset($name)
{
if(($this->offsetExists($name) === true) and ($this->isUnique($name) === true))
{
if($this->nameExists($name) === true)
{
$this->name($name, NULL);
return true;
}
else if($this->sectionExists($name) === true)
{
$this->sectionUnset($name);
return true;
}
}
return false;
}
public function offsetSet($name, $value)
{
try
{
return $this->name($name, $value);
}
catch(RestrictedValueException $r)
{
throw $r;
}
}
public function offsetGet($name)
{
if($this->isUnique($name) === false)
{
$array = array();
$array['name'] = $this->name($name);
$array['section'] = $this->section($name);
$restrictions = $this->restrictions($name);
if(is_array($restrictions))
{
$array['restrictions'] = &$restrictions;
}
$visibility = $this->visibility($name);
if($visibility !== false)
{
$array['visibility'] = $visibility;
}
}
else if($this->nameExists($name) === true)
{
return $this->name($name);
}
else if($this->sectionExists($name) === true)
{
return $this->section($name);
}
else
{
return new ConfigurationSection;
}
}
// End ArrayAccess
}
?>The second question is that I've been banging my head against the wall trying to figure out an intelligent way to return either the name or section without seeking ahead. The issue that in the multi-dimensional array is that the sections don't know what is in the subsections or what I mean is.
Code: Select all
$section = new Section('start');
$section['score'] = 0;
$section['players'] = 8;
// Lap 1
$section['race']['lap1']['score'] = 4;
$section['race']['lap1']['players'] = 6;
// Lap 2
$section['race']['lap2']['score'] = 8;
$section['race']['lap2']['players'] = 4;Code: Select all
$section['race'] = 2; // amount of laps in exampleThe issue is solved in the class by creating an array if both the name and section exist.
Code: Select all
// To access name
$laps = $section['race']['name'];
// To access the subsection
$section['race']['section']['lap1']$section['race']['section']['lap1']['section']['subsection']['section']['subsection']
and that defeats the purpose of the class.
Code: Select all