So here's my problem, to those are quick-witted enough to tell me what's wrong:
I have a Collection class (and further a UserCollection class) to store none other but a collection of users. As well, I have a UserFactory class which I'm trying to use to build and return a collection of ALL users (simple, for now). However, when I return the UserCollection, it won't iterate through with this code and print the user names (test.php):
require_once("lib/class.User.php");
require_once("lib/class.UserCollection.php");
require_once("lib/class.UserFactory.php");
$users = new Collection();
$users = UserFactory::getAll();
foreach ($users as $objUser)
{
echo $objUser->GetField("username");
}
Here are the quick files for the Collection, UserCollection and UserFactory respectively (the User class and GenericObject class work fine from my testing, so I won't post them):
<?php
class Collection {
private $_members = array(); //collection members
private $_onload; //holder for callback function
private $_isLoaded = false; //flag that indicates whether the callback
//has been invoked
public function addItem($obj, $key = null) {
$this->_checkCallback(); //_checkCallback is defined a little later
if($key) {
if(isset($this->_members[$key])) {
throw new KeyInUseException("Key \"$key\" already in use!");
} else {
$this->_members[$key] = $obj;
}
} else {
$this->_members[] = $obj;
}
}
public function removeItem($key) {
$this->_checkCallback();
if(isset($this->_members[$key])) {
unset($this->_members[$key]);
} else {
throw new KeyInvalidException("Invalid key \"$key\"!");
}
}
public function getItem($key) {
$this->_checkCallback();
if(isset($this->_members[$key])) {
return $this->_members[$key];
} else {
throw new KeyInvalidException("Invalid key \"$key\"!");
}
}
public function keys() {
$this->_checkCallback();
return array_keys($this->_members);
}
public function length() {
$this->_checkCallback();
return sizeof($this->_members);
}
public function exists($key) {
$this->_checkCallback();
return (isset($this->_members[$key]));
}
/**
* Use this method to define a function to be
* invoked prior to accessing the collection.
* The function should take a collection as a
* its sole parameter.
*/
public function setLoadCallback($functionName, $objOrClass = null) {
if($objOrClass) {
$callback = array($objOrClass, $functionName);
} else {
$callback = $functionName;
}
//make sure the function/method is valid
if(!is_callable($callback, false, $callableName)) {
throw new Exception("$callableName is not callable " .
"as a parameter to onload");
return false;
}
$this->_onload = $callback;
}
/**
* Check to see if a callback has been defined and if so,
* whether or not it has already been called. If not,
* invoke the callback function.
*/
private function _checkCallback() {
if(isset($this->_onload) && !$this->_isLoaded) {
$this->_isLoaded = true;
call_user_func($this->_onload, $this);
}
}
}
?>
<?php
require_once("class.Collection.php");
class UserCollection extends Collection
{
public function addItem(User $obj, $key = null)
{
parent::addItem($obj, $key);
}
}
?>
<?php
require_once("lib/class.User.php");
require_once("lib/class.Database.php");
require_once("lib/class.Collection.php");
class UserFactory
{
public static function getAll()
{
global $cfg;
$db = Database::instance();
$result_fields = $db->getAll("SELECT id FROM " . $cfg["tbl_users"]);
$users = new Collection();
foreach($result_fields as $result => $field)
{
$users->addItem(new User($field["id"]), $field["id"]);
}
return $users;
}
}
?>
Any help would be much appreciated.
As a note: I've found that if I make $_members PUBLIC rather than PRIVATE in the Collection class, I can specifically use it to iterate through, but this isn't ideal. I'd really like to just iterate through as objects.
Hopefully someone understands this. (P.S. sorry for the large amounts of code)