OOP forum

Not for 'how-to' coding questions but PHP theory instead, this forum is here for those of us who wish to learn about design aspects of programming with PHP.

Moderator: General Moderators

Post Reply
josh
DevNet Master
Posts: 4872
Joined: Wed Feb 11, 2004 3:23 pm
Location: Palm beach, Florida

OOP forum

Post by josh »

First of I am already aware of the other OOP thread similar to this but my question is specifically about forums.

I've told myself over and over "don't worry you'll learn OOP someday", but I've finally decided to stop procrastinating, I taught myself the basics of writing classes. I understand the technical aspects of writing them and using them, don't get me wrong, I'm just not sure about 'how' to implement them, so on a task to master the world of OOP I'm going to convert my current forum software I wrote into OOP. What do you think are important classes to write for a forum software, obviously the template system will use classes, and my pagination script will be converted to a class, but I honestly cannot think of anything else I could convert into a class that will 'clean up' my code or help in any way. Could some one suggest some features of forums that would do well in OOP and a few examples of functions the classes would perform?
User avatar
nielsene
DevNet Resident
Posts: 1834
Joined: Fri Aug 16, 2002 8:57 am
Location: Watertown, MA

Post by nielsene »

Well a Rich Domain Model would probably call for :

A Post Class
A (Forum)Thread Class
A Forum Class (especially if you have sub-forums)

A User Class
josh
DevNet Master
Posts: 4872
Joined: Wed Feb 11, 2004 3:23 pm
Location: Palm beach, Florida

Post by josh »

Ok thanks, also how would a 'cliche' or I should say 'standard' API go for class's like these?

Code: Select all

$forum = new forum();
$database = new dbClass();
$database -> connect('host', 'user', 'pass');
$database -> query('SELECT `forum`, `description`, `id` FROM `forums` WHERE `active` = 1 ; ');
foreach ($database -> result as $id) {
     $name = $database -> result[$id]['forum'];
     $description = $database -> result[$id]['description']
     $forum_id = $database -> result[$id]['id']
     $forum -> addforum ($forum_id, $description, $name);
}
$forum -> output();
How about something along the lines of that to display the different forums, and something similiar for the threads? Or should all my classes extend the database class and have the list of forums populate from within the class itself so it goes like this:

Code: Select all

$forum = new forum();
$forum -> populate();
$forum -> output();
What about hierarchy?
forum->thread->post ?
Should I just write classes that extend eachother starting at the DB class?
This would be my first OOP so I'm not familiar with the planning process in an OOP app, so I'm just trying to figure it all out.
User avatar
nielsene
DevNet Resident
Posts: 1834
Joined: Fri Aug 16, 2002 8:57 am
Location: Watertown, MA

Post by nielsene »

I think I would suggest something like:

Code: Select all

$db = new DB($dbname,$user,$pass); // Move the connection/selection into the constructor
$forumKeys = $db->getForums(); // For smallish applications I'd put some of the "stock" queries into the DB class, this returns a list of IDs
$forumList = new ForumList();
foreach ($forumKeys as $anID) {
   $forumsList->add(new Forum($db,$anId));
}
$forumList->display();
I would probably make the new Forum constructor, with $anID, use lazy loading, to not actually load the data until something calls for it.

Or alternatively:

Code: Select all

$db = new DB($dbname,$user,$pass); // Move the connection/selection into the constructor
$forumList = new ForumList($db);
$forumList->loadAllForums();
$forumList->display();
josh
DevNet Master
Posts: 4872
Joined: Wed Feb 11, 2004 3:23 pm
Location: Palm beach, Florida

Post by josh »

Thanks for the help, wish me luck with my first OOP project :-)
Ree
Forum Regular
Posts: 592
Joined: Fri Jun 10, 2005 1:43 am
Location: LT

Post by Ree »

good luck :wink:
josh
DevNet Master
Posts: 4872
Joined: Wed Feb 11, 2004 3:23 pm
Location: Palm beach, Florida

Post by josh »

Well after thinking about how long it would take to convert the entire forum script to OOP I decided to start with something smaller, a class that will allow me to prompt the user for an arbitrary amount of times and/or dates using drop down lists, and then convert the times into timestamps....

It turned out quite well, and I figured I'd celebrate my first 'object' by releasing it as open source, (if anyones crazy enough to run my code that is) :-D

Feel free to use it for whatever you want, although credit is always nice :-)

index.php

Code: Select all

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<title>Date selector class</title>
</head>
<body>
<form action="?" method="post">
<?php
require_once("class.php");
/*
SYNTAX: selectorMaker (selector_number, [hours, [minutes, [pm, [month, [day, [year]]]]]])
selector_numer: You must assign a number for each selector, starting with 1,
increasing by 1 for each new selector you create
(this is to keep the drop down's names apart in the html form)

All the other paramaters are optional, they are booleans that allow you to set which form elements to display
by default all will be displayed, if you set one you must set all the ones before it atleast (obviously)
i.e. selectorMaker (1, false, false, false) to display just the data
i.e. selectorMaker (1, true, false, false) to display the hours portion of the time, and the date

NOTICE:
If you set any of the booleans to false, you might want to change the default setSeperator() function below
*/
$selector = new selectorMaker(1);
/*
SYNTAX: setSeperator([mixed, [mixed, [mixed]]])
This method is optional, it allows you to output a string after each item, by default it is:
' : ', ' ', ' <br /> ', ' / ', ' / '

Accepts arbitrary number of arguments but it'd be pointless as only a maximum of 5 will be used,
if you turned off any of the booleans when calling selectorMaker, the corresponding 'seperator' will be thrown out, just pass NULL

ie:
selectorMaker (1, false, false, false)
setSeperator(NULL, NULL, NULL, '-', '/');
*/

// setSeperator([string, [string, [string]]]);
$selector -> generate();
$selector -> output();

$selector = new selectorMaker(2, false, false, false);
$selector -> setSeperator(NULL, NULL, NULL, ' - ', ' - ');
$selector -> generate();
$selector -> output();

?>
<br />
<input name="submit" type="submit" id="submit" value="Submit" />
</form>
<?php
/*
SYNTAX: selectorParser(dataToParse, amntOfSelectorsToParse)
Note: You must specify how many selectors, if you specify too many the array returned by parse()
will contain a value of -1 for any selectors it couldn't find
*/
$parser = new selectorParser($_POST, 2);
/*
SYNTAX: array = parse(VOID)
*/
$array = $parser -> parse();

// Do whatever you want with the array of timestamps returned

echo ("<table border=1>");
foreach ($array as $timestamp) {
	echo ("<tr><td>$timestamp</td><td>").date('r',$timestamp).("</td></tr>");
}
echo ("</table>");

?>
</body>
</html>
class.php (the class, hence the name)

Code: Select all

<?php
class selector {
	var $fieldNames;
	var $start_year;
	var $end_year;
	var $fieldFlags;
	
	function selector () {
		// Set the fieldNames array
		$this -> fieldNames['keys'] = array('hours' => 0, 'minutes' => 1, 'pm' => 2, 'month' => 3, 'day' => 4, 'year' => 5);
		foreach ($this -> fieldNames['keys'] as $key => $value) {
			$this -> fieldNames['values'][$value] = $key; 
		}
		$this -> start_year = (int)date('Y') - (5); 
		$this -> end_year = (int)date('Y') + (5); 
	}
	
	function getId ($name) {
		return ( $this -> fieldNames['keys'][$name] );
	}
	
	function getName ($id) {
		return ( $this -> fieldNames['values'][$id] );
	}
}


class selectorMaker extends selector {
	var $selectorNumber;
	var $page;
	var $seperator;
	var $defaults;
	
	function selectorMaker ($selector_number, $hours=1, $minutes=1, $pm=1, $month=1, $day=1, $year=1) {
		$this -> selector();
		$this -> setFlags($hours, $minutes, $pm, $month, $day, $year);
		$this -> page = '';
		// Set the defaults for each field to the current time
		$this -> setDefaults();
		// Set the selector_number
		$this -> selectorNumber = $selector_number;
		$this -> setSeperator(' : ', ' ', ' <br /> ', ' / ', ' / ');
	}
	
	function setFlags($hours, $minutes, $pm, $month, $day, $year) {
		// Set all the field flags
		$this -> fieldFlags = array($hours, $minutes, $pm, $month, $day, $year);
	}
	
	function setSeperator () {
		$this -> seperator = array () ;
		foreach (func_get_args() as $value) {
			$this -> seperator[] = $value;
		}
	}
	
	function setDefaults ($time = NULL, $fieldFlags = NULL) {
		if ($time==NULL) {
			$time = time();
		}
		if ($fieldFlags==NULL) {
			$fieldFlags=$this -> fieldFlags;
		}
		// Parse the timestamp
		$time = date('h-i-a-n-j-Y',$time);
		// Build an array
		$time = split('-', $time);
		foreach ($time as $key => $value) {
			$this -> defaults[$key] = $value;
		}
	}
	
	function createFormField ($type, $name, $values=NULL) {
		switch ($type) {
			case 'dropdown':
				return ($this -> buildDropDown($name, $values) );
			break;
			case 'hidden':
				return ($this -> buildHidden($name, $values) );
			break;
		}
	}
	
	function buildHidden($name, $value) {
		return ("<input name=\"$name\" type=\"hidden\" value=\"$value\" />\n");
	}
	
	function buildDropDown ($name, $values) {
		$id = $this -> getId($name);		
		$default = $this -> defaults[$id];
		$data = '';
		$data .= "<select name=\"";
		$data .= $name . '_' . $this -> selectorNumber;
		$data .="\">\n";
		if (is_array($values)) {
			$count = count($values);
			for ($x=0; $x<$count; $x++) {
				$data .= "\t<option value=\"";
				$data .= $values[$x];
				$data .= "\"";
				if ($default == $values[$x]) {
					$data .= ' selected="selected"';
				}
				$data .= ">";
				$data .= $values[$x];
				$data .= "</option>\n";
			}
		}
		$data .= "</select>\n";
		return($data);
	}
	
	function listValues ($value) {
		$return=array();
		switch ($value) {
			case 'hours':
				for ($x=1; $x<=12; $x++) {
					$return[] = sprintf("%02d", $x);
				}
			break;
			case 'minutes':
				for ($x=1; $x<=59; $x++) {
					$return[] = sprintf("%02d", $x);
				}
			break;
			case 'pm':
				$return=array('am','pm');
			break;
			case 'month':
				for ($x=1; $x<=12; $x++) {
					$return[] = sprintf("%02d", $x);
				}
			break;
			case 'day':
				$month = $this -> defaults[3];
				$year = $this -> defaults[5];
				$days = $this -> getDaysInMonth($year, $month) ;
				for ($x=1; $x<=$days; $x++) {
					$return[] = sprintf("%02d", $x);
				}
			break;
			case 'year':
				for ($x = $this -> start_year; $x <= $this -> end_year; $x++) {
					$return[]=$x;
				}
			break;
		}
		return($return);
	}
	
	function getDaysInMonth ( $Year, $MonthInYear ) {
	   if ( in_array ( $MonthInYear, array ( 1, 3, 5, 7, 8, 10, 12 ) ) )
		   return 31;
	
	   if ( in_array ( $MonthInYear, array ( 4, 6, 9, 11 ) ) )
		   return 30;
	
	   if ( $MonthInYear == 2 )
		   return ( checkdate ( 2, 29, $Year ) ) ? 29 : 28;
	  
	   return false;
	}
	
	function generate() {
		foreach ( $this -> fieldNames['values'] as $key => $value ) {
			if ( $this -> fieldFlags[$key] ) {
				$array = $this -> listValues( $value );
				$this -> page .= $this -> createFormField('dropdown', $value, $array);
				$this -> page .= $this -> seperator[$key];
			}
		}
		$this -> page .= $this -> createFormField('hidden', 'posting_a_date_selector_form', 1);
		$this -> page .= "<br />\n<br />\n";
	}
	
	function output() {
		echo ( $this -> page );
	}
}


class selectorParser extends selector {
	var $countSelectors;
	var $data;
	function selectorParser($data, $amnt) {
		$this -> selector();
		$this -> data = $data;
		$this -> countSelectors = (int)$amnt;
	}
	function parse() {
		$arr = array();
		for ($x = 0; $x < $this -> countSelectors; $x++) {
			$arr[] = $this -> deflate($x+1);
		}
		return ($arr);
	}
	
	function deflate ($id) {
		$data = array();
		foreach ( $this -> fieldNames['values'] as $value) {
			$data[] = $this -> data[ $value . '_' . $id ];
		}
		$time = mktime($data[ $this -> getId('hours') ], $data[ $this -> getId('minutes') ], 0, $data[ $this -> getId('month') ], $data[ $this -> getId('day') ], $data[ $this -> getId('year') ]);
		if ($data[ $this -> getId('pm') ] == 'pm') {
			$time+=(3600*12);
		}
		return($time);
	}
}
?>
Post Reply