Jump to content

Trying to populate collection only as needed using callback function


AwakenedYes

Recommended Posts

Trying to populate collection only as needed using callback function

 

I am going through WROX Professional PHP5 Chapter 5 - Collections.

 

I am trying to populate a collection from a DB (MSSQL) only as members are called, rather than populate everything, using callback functions as detailed in the book.  I just can't get the result as expected, which is: "Bob Smith is currently enrolled in CS101".  Hopefully the code will explain:

 

//factoryTest.php

<?php

require_once 'class.Collection.php';
require_once 'class.CourseCollection.php';
require_once 'class.Course.php';
require_once 'class.Student.php';
require_once 'class.StudentFactory.php';

$studentID = 1;

try {
$objStudent = StudentFactory::getStudent($studentID);
$objStudent2 = StudentFactory::getCoursesForStudent($studentID, $col);
} catch (Exception $e) {
die("Student #$studentID doesn't exist in the database!");
}

print $objStudent .
	($objStudent->courses->exists("CS101") ? ' is ' : ' is not ').
	'currently enrolled in CS101';
//displays: "Bob Smith is enrolled in CS101"
?>

//class.StudentFactory.php

<?php
class StudentFactory {

public static function getStudent($id) {

	$serverName = "";
	$connectionInfo = array("Database"=>"Registra");
	$con = sqlsrv_connect($serverName, $connectionInfo)
		or die("Failure connecting to database!");

	$sql = "SELECT * FROM \"student\" WHERE \"studentid\" = $id";
	$result = sqlsrv_query($con, $sql);

	if ($result === false) {
		throw new Exception("Student $id does not exit.");
	} else {
		$row = sqlsrv_fetch_array($result, SQLSRV_FETCH_ASSOC);
		return new Student($row['studentid'], $row['name']);
	}
}

public static function getCoursesForStudent($id, $col) {

	$serverName = "";
	$connectionInfo = array("Database"=>"Registra");
	$con = sqlsrv_connect($serverName, $connectionInfo)
		or die("Failure connecting to database!");

	$sql = "SELECT \"course\".\"courseid\",
				   \"course\".\"coursecode\",
				   \"course\".\"name\"
			  FROM \"course\"
			  INNER JOIN \"studentcourse\"
			  ON \"course\".\"courseid\" = \"studentcourse\".\"courseid\"
			  INNER JOIN \"student\"
			  ON \"studentcourse\".\"studentid\" = \"student\".\"studentid\"
			  WHERE
			  	   \"course\".\"courseid\" = 
			  	   \"studentcourse\".\"courseid\" AND
			  	   \"studentcourse\".\"studentid\" = $id";

	$res = sqlsrv_query($con, $sql);

	if (sqlsrv_has_rows($res)) {
		$rowCount = sqlsrv_num_rows($res);

		while ($row = sqlsrv_fetch_array($res, SQLSRV_FETCH_ASSOC)) {

			$objCourse = new Course($row['courseid'], $row['coursecode'],
									$row['name']);
			$col->addItem($objCourse, $objCourse->getCourseCode());

//				echo $row['courseid']." ".$row['coursecode']." ".$row['name'];

		}
		return $col;
	}
}
}
?>

//class.Student.php

<?php
class Student {
private $_id;
private $_name;

public $courses;

public function __construct($id, $name) {
	$this->_id = $id;
	$this->_name = $name;

	$this->courses = new CourseCollection();
	$this->courses->setLoadCallback('_loadCourses', $this);
}

public function getName() {
	return $this->_name;
}

public function getID() {
	return $this->_id;
}

public function _loadCourses(CourseCollection $col) {
	$courses = StudentFactory::getCoursesForStudent($this->_id, $col);
}

public function __toString() {
	return $this->_name;
}
}
?>

//class.CourseCollection.php

<?php
class CourseCollection extends Collection {
public function addItem(Course $obj, $key = null) {
	parent::addItem($obj, $key);
}
}
?>

//class.Course.php

<?php
class Course {
private $_id;
private $_courseCode;
private $_name;

public function __construct($id, $courseCode, $name) {
	$this->_id = $id;
	$this->_courseCode;
	$this->_name;
}

public function getName() {
	return $this->_name;
}

public function getID() {
	return $this->_id;
}

public function getCourseCode() {
	return $this->_courseCode;
}

public function __toString() {
	return $this->_name;
}
}
?>

//class.Collection.php

<?php

class Collection {

private $_members = array();		// Collection members.

private $_onload;					// Holder for callback function

private $_isLoaded = false;			// Flag that indicates whether the
									// has been invoked.

public function addItem($obj, $key = null) {

	$this->_checkCallback();

	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 length() {
	$this->_checkCallback();
	return sizeof($this->_members);
}

public function keys() {
	$this->_checkCallback();
	return array_keys($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 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);
	}
}
}

class KeyInvalidException extends Exception {}
class KeyInUseException extends Exception {}
?>

 

I always get "Bob Smith is not currently enrolled in CS101".

 

Even in a foreach loop:

 

foreach ($objStudent->courses as $objCourse) {
print $objCourse->getCourseCode." - ".$objCourse->getName"
}

 

I don't get anything.  What am I doing wrong?  What am I missing?  Is it going out of scope?

The DB is connecting and returning correctly!

 

Hope you can help - cheers

Archived

This topic is now archived and is closed to further replies.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.