Jump to content

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

This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • 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.