Page 1 of 1

OOP forum

Posted: Sat Jul 30, 2005 11:17 am
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?

Posted: Sat Jul 30, 2005 12:12 pm
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

Posted: Sat Jul 30, 2005 12:30 pm
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.

Posted: Sat Jul 30, 2005 12:44 pm
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();

Posted: Sat Jul 30, 2005 2:35 pm
by josh
Thanks for the help, wish me luck with my first OOP project :-)

Posted: Sat Jul 30, 2005 3:33 pm
by Ree
good luck :wink:

Posted: Sun Jul 31, 2005 12:21 am
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);
	}
}
?>