KevinM1 Posted July 17, 2007 Share Posted July 17, 2007 It is my hope that this thread can help illustrate the process of migrating one's thinking from a pure procedural point-of-view to one that is more OOP-oriented. In particular, I hope newbies will read this thread and see, through the successes and failures that will be put on display, what benefits can be gained by using OOP methodology in their projects. I am by no means an OOP master. In fact, I haven't really tried any of the patterns I've read about. The aim of this thread is to change that, as I will (with, hopefully, the help of some of the OOP veterans on here) change two working procedural scripts into OOP scripts. I feel that using real-world scripts that I've written in the past will lend OOP a sense of tangiblity that most examples seem to lack. Mods, please feel free (like I have any say in the matter ) to move this thread to application design if necessary. I put it here as I'd like for drive-bye OOP hopefuls to see and even partake in the discussion. Now, onto the show! This project is about changing my registration_viewer and registration_controller scripts from the PHP-Fusion site I just finished into OOP scripts. I have several reasons for wanting this change: 1. I want to learn OOP in practice, so I figured this would be a good place to start. 2. My scripts desperately need help as there are conditionals everywhere. 3. There is no 3. The most logical place to start is at the beginning: My PHP-Fusion project entailed me installing a 3rd party event calendar, then creating a custom registration script for it, allowing users to register for events. The scripts I show below control the edit/delete process. registration_viewer polls the database and returns a dropdown menu of registrations that a user has created, with the added caveat that site administrators can view ALL event registrations as well as their own. Registration_controller pulls up the registration(s) the user chose, and gives them the option to edit (only one) or delete them (multiple). Administrators, when viewing ALL registrations, can only delete them. The code -- registration_viewer.php <?php require_once "maincore.php"; require_once "subheader.php"; require_once "side_left.php"; if(!iMEMBER){ fallback(); } echo "<span style='font-weight: bold; font-size: 1.25em;'>Edit/Delete Registrations</span><br /><br />\n"; if(iADMIN){ //if ADMIN: two lists, one for the events ADMIN registered to, one for ALL events $personalQuery = "SELECT * FROM ". DB_PREFIX ."aflac WHERE user_id = '". $userdata['user_id'] ."'"; $personalResult = dbquery($personalQuery); $adminQuery = "SELECT * FROM ". DB_PREFIX ."aflac"; $adminResult = dbquery($adminQuery); echo "<form method='post' action='registration_controller.php'>\n<br />\n"; echo "Your registrations: <br /><br />\n"; echo "<select name='personalEvents[]'>\n<br />\n"; echo "<option value='*'>All</option>\n<br />\n"; while($row = mysql_fetch_assoc($personalResult)){ echo "<option value='{$row['user_id']}, {$row['ev_id']}, {$row['login_timestamp']}'>{$row['ev_title']} -- ". date('M j, Y', $row['login_timestamp']) ."</option>\n<br />\n"; } echo "</select>\n"; echo "<input type='submit' name='personalSubmit' value='Go' />\n<br />\n<br /><br /><br /><br />\n"; echo "All registrations: <br /><br />\n"; echo "<select name='adminEvents[]'>\n<br />\n"; echo "<option value='*'>All</option>\n<br />\n"; while($row = mysql_fetch_assoc($adminResult)){ echo "<option value='{$row['user_id']}, {$row['ev_id']}, {$row['login_timestamp']}'>{$row['registering_agent']}: {$row['ev_title']} -- ". date('M j, Y', $row['login_timestamp']) ."</option>\n<br />\n"; } echo "</select>\n"; echo "<input type='submit' name='adminSubmit' value='Go' />\n<br />\n<br />\n</form>\n"; } if(iMEMBER && !iADMIN){ //if MEMBER && !ADMIN: one list of events MEMBER registered for $query = "SELECT * FROM ". DB_PREFIX ."aflac WHERE user_id = '". $userdata['user_id'] ."'"; $result = dbquery($query); echo "<form method='post' action='registration_controller.php'>\n<br />\n"; echo "Your registrations:<br /><br />\n"; echo "<select name='events[]'>\n<br />\n"; echo "<option value='*'>All</option>\n<br />\n"; while($row = mysql_fetch_assoc($result)){ echo "<option value='{$row['user_id']}, {$row['ev_id']}, {$row['login_timestamp']}'>{$row['ev_title']} -- ". date('M j, Y', $row['login_timestamp']) ."</option>\n<br />\n"; } echo "</select>\n"; echo "<input type='submit' name='submit' value='Go' />\n<br />\n</form>\n<br />\n"; } require_once "side_right.php"; require_once "footer.php"; ?> registration_controller.php <?php require_once "maincore.php"; require_once "subheader.php"; require_once "side_left.php"; if(!iMEMBER){ fallback(); } if(isset($_POST['edit'])){ //for editing registrations. only 1 registration can be edited at a time if(isset($_POST['events'])){ //MEMBER $event = explode(", ", $_POST['events'][0]); $user_id = $event[0]; $ev_id = $event[1]; $login_timestamp = $event[2]; $query = "SELECT * FROM ". DB_PREFIX ."aflac WHERE user_id = '$user_id' AND ev_id = '$ev_id' AND login_timestamp = '$login_timestamp'"; $result = dbquery($query); $row = mysql_fetch_assoc($result); header("Location: ". BASEDIR ."registration.php?evid={$row['ev_id']}®Agent={$row['registering_agent']}&agentWritingNum={$row['agent_writing_number']}&phone={$row['phone']}&email={$row['email']}®Sales={$row['regional_sales_coordinator']}&disSales={$row['district_sales_coordinator']}"); } else if(isset($_POST['personalEvents'])){ //ADMIN $event = explode(", ", $_POST['personalEvents'][0]); $user_id = $event[0]; $ev_id = $event[1]; $login_timestamp = $event[2]; $query = "SELECT * FROM ". DB_PREFIX ."aflac WHERE user_id = '$user_id' AND ev_id = '$ev_id' AND login_timestamp = '$login_timestamp'"; $result = dbquery($query); $row = mysql_fetch_assoc($result); header("Location: ". BASEDIR ."registration.php?evid={$row['ev_id']}®Agent={$row['registering_agent']}&agentWritingNum={$row['agent_writing_number']}&phone={$row['phone']}&email={$row['email']}®Sales={$row['regional_sales_coordinator']}&disSales={$row['district_sales_coordinator']}"); } } else if(isset($_POST['delete'])){ //for deleting events. multiple events can be deleted if(isset($_POST['events'])){ //MEMBER's personal registrations foreach($_POST['events'] as $value){ $event = explode(", ", $value); $user_id = $event[0]; $ev_id = $event[1]; $login_timestamp = $event[2]; $deleteTextQuery = "SELECT * FROM ". DB_PREFIX ."aflac WHERE user_id = '$user_id' AND ev_id = '$ev_id' AND login_timestamp = '$login_timestamp'"; $deleteTextResults[] = dbquery($deleteTextQuery); $deleteAflacQuery = "DELETE FROM ". DB_PREFIX ."aflac WHERE user_id = '$user_id' AND ev_id = '$ev_id' AND login_timestamp = '$login_timestamp'"; $deleteLoginsQuery = "DELETE FROM ". DB_PREFIX ."aw_ec_logins WHERE user_id = '$user_id' AND ev_id = '$ev_id' AND login_timestamp = '$login_timestamp'"; $deleteAflacResult = dbquery($deleteAflacQuery); $deleteLoginsResult = dbquery($deleteLoginsQuery); } if($deleteAflacResult && $deleteLoginsResult){ $deleteText = "The following registration(s) have been deleted:\n<br />\n<br />\n"; $deleteText .= "<table cellspacing='0'>\n\t<tr>\n\t\t<th>Registering Agent</th><th>Event</th><th>Agent Writing Number</th><th>Phone Number</th><th>E-mail Address</th><th>Regional Sales Coordinator</th><th>District Sales Coordinator</th>\n\t</tr>"; foreach($deleteTextResults as $queryResult){ while($row = mysql_fetch_assoc($queryResult)){ $deleteText .= "\n\t<tr class='regtbl1'>\n\t\t<td>{$row['registering_agent']}</td><td>{$row['ev_title']}</td><td>{$row['agent_writing_number']}</td><td>{$row['phone']}</td><td>{$row['email']}</td><td>{$row['regional_sales_coordinator']}</td><td>{$row['district_sales_coordinator']}</td>\n\t</tr>"; } } $deleteText .= "\n</table>\n\n"; $deleteText .= "<br /><br />\n\n<a href='news.php'>Return home</a> or <a href='registration_viewer.php'>modify another registration</a>"; echo $deleteText; } } else if(isset($_POST['personalEvents'])){ //ADMIN's personal registrations foreach($_POST['personalEvents'] as $value){ $event = explode(", ", $value); $user_id = $event[0]; $ev_id = $event[1]; $login_timestamp = $event[2]; $deleteTextQuery = "SELECT * FROM ". DB_PREFIX ."aflac WHERE user_id = '$user_id' AND ev_id = '$ev_id' AND login_timestamp = '$login_timestamp'"; $deleteTextResults[] = dbquery($deleteTextQuery); $deleteAflacQuery = "DELETE FROM ". DB_PREFIX ."aflac WHERE user_id = '$user_id' AND ev_id = '$ev_id' AND login_timestamp = '$login_timestamp'"; $deleteLoginsQuery = "DELETE FROM ". DB_PREFIX ."aw_ec_logins WHERE user_id = '$user_id' AND ev_id = '$ev_id' AND login_timestamp = '$login_timestamp'"; $deleteAflacResult = dbquery($deleteAflacQuery); $deleteLoginsResult = dbquery($deleteLoginsQuery); } if($deleteAflacResult && $deleteLoginsResult){ $deleteText = "The following registration(s) have been deleted:\n<br />\n<br />\n"; $deleteText .= "<table cellspacing='0'>\n\t<tr>\n\t\t<th>Registering Agent</th><th>Event</th><th>Agent Writing Number</th><th>Phone Number</th><th>E-mail Address</th><th>Regional Sales Coordinator</th><th>District Sales Coordinator</th>\n\t</tr>"; foreach($deleteTextResults as $queryResult){ while($row = mysql_fetch_assoc($queryResult)){ $deleteText .= "\n\t<tr class='regtbl1'>\n\t\t<td>{$row['registering_agent']}</td><td>{$row['ev_title']}</td><td>{$row['agent_writing_number']}</td><td>{$row['phone']}</td><td>{$row['email']}</td><td>{$row['regional_sales_coordinator']}</td><td>{$row['district_sales_coordinator']}</td>\n\t</tr>"; } } $deleteText .= "\n</table>\n\n"; $deleteText .= "<br /><br />\n\n<a href='news.php'>Return home</a> or <a href='registration_viewer.php'>modify another registration</a>"; echo $deleteText; } } else if(isset($_POST['adminEvents'])){ //ADMIN: ALL possible registrations foreach($_POST['adminEvents'] as $value){ $event = explode(", ", $value); $user_id = $event[0]; $ev_id = $event[1]; $login_timestamp = $event[2]; $deleteTextQuery = "SELECT * FROM ". DB_PREFIX ."aflac WHERE user_id = '$user_id' AND ev_id = '$ev_id' AND login_timestamp = '$login_timestamp'"; $deleteTextResults[] = dbquery($deleteTextQuery); $deleteAflacQuery = "DELETE FROM ". DB_PREFIX ."aflac WHERE user_id = '$user_id' AND ev_id = '$ev_id' AND login_timestamp = '$login_timestamp'"; $deleteLoginsQuery = "DELETE FROM ". DB_PREFIX ."aw_ec_logins WHERE user_id = '$user_id' AND ev_id = '$ev_id' AND login_timestamp = '$login_timestamp'"; $deleteAflacResult = dbquery($deleteAflacQuery); $deleteLoginsResult = dbquery($deleteLoginsQuery); } if($deleteAflacResult && $deleteLoginsResult){ $deleteText = "The following registration(s) have been deleted:\n<br />\n<br />\n"; $deleteText .= "<table cellspacing='0'>\n\t<tr>\n\t\t<th>Registering Agent</th><th>Event</th><th>Agent Writing Number</th><th>Phone Number</th><th>E-mail Address</th><th>Regional Sales Coordinator</th><th>District Sales Coordinator</th>\n\t</tr>"; foreach($deleteTextResults as $queryResult){ while($row = mysql_fetch_assoc($queryResult)){ $deleteText .= "\n\t<tr class='regtbl1'>\n\t\t<td>{$row['registering_agent']}</td><td>{$row['ev_title']}</td><td>{$row['agent_writing_number']}</td><td>{$row['phone']}</td><td>{$row['email']}</td><td>{$row['regional_sales_coordinator']}</td><td>{$row['district_sales_coordinator']}</td>\n\t</tr>"; } } $deleteText .= "\n</table>\n\n"; $deleteText .= "<br /><br />\n\n<a href='news.php'>Return home</a> or <a href='registration_viewer.php'>modify another registration</a>"; echo $deleteText; } } } if(isset($_POST['personalSubmit'])){ //ADMIN's personal registrations if(isset($_POST['personalEvents']) && $_POST['personalEvents'][0] == '*'){ //if ALL personal registrations are selected $personalQuery = "SELECT * FROM ". DB_PREFIX ."aflac WHERE user_id = '". $userdata['user_id'] ."' ORDER BY login_timestamp DESC"; $personalResult = dbquery($personalQuery); echo "<span style='font-weight: bold; font-size: 1.35em;'>Your Registrations:</span><br /><br /><br />\n\n"; echo "<form method='post' id='registrationForm' action='{$_SERVER['PHP_SELF']}'>\n"; echo "<table cellspacing='0' cellpadding='5' class='tbl'>\n\t<tr class='regtbl2'>\n\t\t<th></th><th>Registering Agent</th><th>Event</th><th>Agent Writing Number</th><th>Phone Number</th><th>E-mail Address</th><th>Regional Sales Coordinator</th><th>District Sales Coordinator</th>\n\t</tr>"; $count = 0; while($row = mysql_fetch_assoc($personalResult)){ if($count % 2 == 0){ echo "\n\t<tr class='regtbl1'>\n\t\t<td><input type='checkbox' name='personalEvents[]' value='{$row['user_id']}, {$row['ev_id']}, {$row['login_timestamp']}' /></td><td>{$row['registering_agent']}</td><td>{$row['ev_title']}</td><td>{$row['agent_writing_number']}</td><td>{$row['phone']}</td><td>{$row['email']}</td><td>{$row['regional_sales_coordinator']}</td><td>{$row['district_sales_coordinator']}</td>\n\t</tr>"; } else{ echo "\n\t<tr class='regtbl2'>\n\t\t<td><input type='checkbox' name='personalEvents[]' value='{$row['user_id']}, {$row['ev_id']}, {$row['login_timestamp']}' /></td><td>{$row['registering_agent']}</td><td>{$row['ev_title']}</td><td>{$row['agent_writing_number']}</td><td>{$row['phone']}</td><td>{$row['email']}</td><td>{$row['regional_sales_coordinator']}</td><td>{$row['district_sales_coordinator']}</td>\n\t</tr>"; } $count++; } echo "</table>\n<input type='submit' name='edit' value='Edit' /><input type='submit' name='delete' value='Delete' />\n</form>"; } else if(isset($_POST['personalEvents']) && $_POST['personalEvents'][0] != '*'){ //for singular personal registrations $event = explode(", ", $_POST['personalEvents'][0]); $user_id = $event[0]; $ev_id = $event[1]; $login_timestamp = $event[2]; $personalQuery = "SELECT * FROM ". DB_PREFIX ."aflac WHERE user_id = '$user_id' AND ev_id = '$ev_id' AND login_timestamp = '$login_timestamp' ORDER BY login_timestamp DESC"; $personalResult = dbquery($personalQuery); echo "<span style='font-weight: bold; font-size: 1.35em;'>Your Registrations:</span><br /><br /><br />\n\n"; echo "<form method='post' id='registrationForm' action='{$_SERVER['PHP_SELF']}'>\n"; echo "<table cellspacing='0' cellpadding='5' class='tbl'>\n\t<tr class='regtbl2'>\n\t\t<th></th><th>Registering Agent</th><th>Event</th><th>Agent Writing Number</th><th>Phone Number</th><th>E-mail Address</th><th>Regional Sales Coordinator</th><th>District Sales Coordinator</th>\n\t</tr>"; while($row = mysql_fetch_assoc($personalResult)){ echo "\n\t<tr class='regtbl1'>\n\t\t<td><input type='checkbox' name='personalEvents[]' value='{$row['user_id']}, {$row['ev_id']}, {$row['login_timestamp']}' /></td><td>{$row['registering_agent']}</td><td>{$row['ev_title']}</td><td>{$row['agent_writing_number']}</td><td>{$row['phone']}</td><td>{$row['email']}</td><td>{$row['regional_sales_coordinator']}</td><td>{$row['district_sales_coordinator']}</td>\n\t</tr>"; } echo "</table>\n<input type='submit' name='edit' value='Edit' /><input type='submit' name='delete' value='Delete' />\n</form>"; } } if(isset($_POST['submit'])){ //non-ADMIN's personal registrations if(isset($_POST['events']) && $_POST['events'][0] == '*'){ //if ALL personal registrations are selected $personalQuery = "SELECT * FROM ". DB_PREFIX ."aflac WHERE user_id = '". $userdata['user_id'] ."' ORDER BY login_timestamp DESC"; $personalResult = dbquery($personalQuery); echo "<span style='font-weight: bold; font-size: 1.35em;'>Your Registrations:</span><br /><br /><br />\n\n"; echo "<form method='post' id='registrationForm' action='{$_SERVER['PHP_SELF']}'>\n"; echo "<table cellspacing='0' cellpadding='5' class='tbl'>\n\t<tr class='regtbl2'>\n\t\t<th></th><th>Registering Agent</th><th>Event</th><th>Agent Writing Number</th><th>Phone Number</th><th>E-mail Address</th><th>Regional Sales Coordinator</th><th>District Sales Coordinator</th>\n\t</tr>"; $count = 0; while($row = mysql_fetch_assoc($personalResult)){ if($count % 2 == 0){ echo "\n\t<tr class='regtbl1'>\n\t\t<td><input type='checkbox' name='events[]' value='{$row['user_id']}, {$row['ev_id']}, {$row['login_timestamp']}' /></td><td>{$row['registering_agent']}</td><td>{$row['ev_title']}</td><td>{$row['agent_writing_number']}</td><td>{$row['phone']}</td><td>{$row['email']}</td><td>{$row['regional_sales_coordinator']}</td><td>{$row['district_sales_coordinator']}</td>\n\t</tr>"; } else{ echo "\n\t<tr class='regtbl2'>\n\t\t<td><input type='checkbox' name='events[]' value='{$row['user_id']}, {$row['ev_id']}, {$row['login_timestamp']}' /></td><td>{$row['registering_agent']}</td><td>{$row['ev_title']}</td><td>{$row['agent_writing_number']}</td><td>{$row['phone']}</td><td>{$row['email']}</td><td>{$row['regional_sales_coordinator']}</td><td>{$row['district_sales_coordinator']}</td>\n\t</tr>"; } $count++; } echo "</table>\n<input type='submit' name='edit' value='Edit' /><input type='submit' name='delete' value='Delete' />\n</form>"; } else if(isset($_POST['events']) && $_POST['events'][0] != '*'){ //for singular personal registrations $event = explode(", ", $_POST['events'][0]); $user_id = $event[0]; $ev_id = $event[1]; $login_timestamp = $event[2]; $personalQuery = "SELECT * FROM ". DB_PREFIX ."aflac WHERE user_id = '$user_id' AND ev_id = '$ev_id' AND login_timestamp = '$login_timestamp' ORDER BY login_timestamp DESC"; $personalResult = dbquery($personalQuery); echo "<span style='font-weight: bold; font-size: 1.35em;'>Your Registrations:</span><br /><br /><br />\n\n"; echo "<form method='post' id='registrationForm' action='{$_SERVER['PHP_SELF']}'>\n"; echo "<table cellspacing='0' cellpadding='5' class='tbl'>\n\t<tr class='regtbl2'>\n\t\t<th></th><th>Registering Agent</th><th>Event</th><th>Agent Writing Number</th><th>Phone Number</th><th>E-mail Address</th><th>Regional Sales Coordinator</th><th>District Sales Coordinator</th>\n\t</tr>"; while($row = mysql_fetch_assoc($personalResult)){ echo "\n\t<tr class='regtbl1'>\n\t\t<td><input type='checkbox' name='events[]' value='{$row['user_id']}, {$row['ev_id']}, {$row['login_timestamp']}' /></td><td>{$row['registering_agent']}</td><td>{$row['ev_title']}</td><td>{$row['agent_writing_number']}</td><td>{$row['phone']}</td><td>{$row['email']}</td><td>{$row['regional_sales_coordinator']}</td><td>{$row['district_sales_coordinator']}</td>\n\t</tr>"; } echo "</table>\n<input type='submit' name='edit' value='Edit' /><input type='submit' name='delete' value='Delete' />\n</form>"; } } if(isset($_POST['adminSubmit'])){ //ADMIN-only: ALL possible event registrations if(isset($_POST['adminEvents']) && $_POST['adminEvents'][0] == '*'){ //if ALL registrations are selected $adminQuery = "SELECT * FROM ". DB_PREFIX ."aflac ORDER BY login_timestamp DESC"; $adminResult = dbquery($adminQuery); echo "<span style='font-weight: bold; font-size: 1.35em;'>All Member Registrations:</span><br /><br /><br />\n\n"; echo "<form method='post' id='registrationForm' action='{$_SERVER['PHP_SELF']}'>\n"; echo "<table cellspacing='0' cellpadding='5' class='tbl'>\n\t<tr class='regtbl2'>\n\t\t<th></th><th>Registering Agent</th><th>Event</th><th>Agent Writing Number</th><th>Phone Number</th><th>E-mail Address</th><th>Regional Sales Coordinator</th><th>District Sales Coordinator</th>\n\t</tr>"; $count = 0; while($row = mysql_fetch_assoc($adminResult)){ if($count % 2 == 0){ echo "\n\t<tr class='regtbl1'>\n\t\t<td><input type='checkbox' name='adminEvents[]' value='{$row['user_id']}, {$row['ev_id']}, {$row['login_timestamp']}' /></td><td>{$row['registering_agent']}</td><td>{$row['ev_title']}</td><td>{$row['agent_writing_number']}</td><td>{$row['phone']}</td><td>{$row['email']}</td><td>{$row['regional_sales_coordinator']}</td><td>{$row['district_sales_coordinator']}</td>\n\t</tr>"; } else{ echo "\n\t<tr class='regtbl2'>\n\t\t<td><input type='checkbox' name='adminEvents[]' value='{$row['user_id']}, {$row['ev_id']}, {$row['login_timestamp']}' /></td><td>{$row['registering_agent']}</td><td>{$row['ev_title']}</td><td>{$row['agent_writing_number']}</td><td>{$row['phone']}</td><td>{$row['email']}</td><td>{$row['regional_sales_coordinator']}</td><td>{$row['district_sales_coordinator']}</td>\n\t</tr>"; } $count++; } echo "</table>\n<input type='submit' name='delete' value='Delete' />\n</form>"; } else if(isset($_POST['adminEvents']) && $_POST['adminEvents'][0] != '*'){ //for singular registrations $event = explode(", ", $_POST['adminEvents'][0]); $user_id = $event[0]; $ev_id = $event[1]; $login_timestamp = $event[2]; $adminQuery = "SELECT * FROM ". DB_PREFIX ."aflac WHERE ev_id = '$ev_id' AND login_timestamp = '$login_timestamp' ORDER BY login_timestamp DESC"; $adminResult = dbquery($adminQuery); echo "<span style='font-weight: bold; font-size: 1.35em;'>One Member Registration:</span><br /><br /><br />\n\n"; echo "<form method='post' id='registrationForm' action='{$_SERVER['PHP_SELF']}'>\n"; echo "<table cellspacing='0' cellpadding='5' class='tbl'>\n\t<tr class='regtbl2'>\n\t\t<th></th><th>Registering Agent</th><th>Event</th><th>Agent Writing Number</th><th>Phone Number</th><th>E-mail Address</th><th>Regional Sales Coordinator</th><th>District Sales Coordinator</th>\n\t</tr>"; while($row = mysql_fetch_assoc($adminResult)){ echo "\n\t<tr class='regtbl1'>\n\t\t<td><input type='checkbox' name='adminEvents[]' value='{$row['user_id']}, {$row['ev_id']}, {$row['login_timestamp']}' /></td><td>{$row['registering_agent']}</td><td>{$row['ev_title']}</td><td>{$row['agent_writing_number']}</td><td>{$row['phone']}</td><td>{$row['email']}</td><td>{$row['regional_sales_coordinator']}</td><td>{$row['district_sales_coordinator']}</td>\n\t</tr>"; } echo "</table>\n<input type='submit' name='delete' value='Delete' />\n</form>"; } } require_once "side_right.php"; require_once "footer.php"; ?> As you can see, the code -- especially registration_controller's -- is pretty messy. It all works, and works correctly, but it is anything but readable and easy to maintain. It is my belief that it could use an OOP makeover. The following posts will be something of a brainstorming session. Since I'm learning as I go, I'll be throwing ideas out that, hopefully, the vets will be able to help me refine. My next post will start the process of rebuilding registration_viewer. Quote Link to comment Share on other sites More sharing options...
KevinM1 Posted July 17, 2007 Author Share Posted July 17, 2007 Transforming registration_viewer NOTE: all posts from now on will ignore the PHP-Fusion includes that display that software's chrome (so maincore.php, side_left.php, etc). In my study, I've learned that one of the tenets of OOP is that conditionals (especially repeated/parallel conditionals) are bad. So, naturally, the first thing I've done is look at the conditionals. Registration_viewer, in this case, isn't bad. There are three conditionals: <?php if(!iMEMBER){ fallback(); } ?> This conditional checks, using one of PHP-Fusion's built-in constants, if the user trying to access the script is a registered member of the site. If not, the user is redirected to the index of the site. <?php if(iADMIN){ //do stuff } ?> This conditional checks to see if the user is a site administrator. This is important because, like I said in the first post, administrators have edit/delete options that normal members do not. <?php if(iMEMBER && !iADMIN){ //do stuff } ?> This conditional checks to see that the user is just a normal member. Now, I'm thinking that I can make some sort of viewer class, something like: <?php class RegistrationViewer{ protected $status; public function __construct(){ switch($userdata['user_level']){ //built-in PHP-Fusion array case 101: return new MemberViewer(); break; case 102: case 103: return new AdminViewer(); break; default: echo "You're not a registered user!"; return false; } } } class AdminViewer extends RegistrationViewer{ public function __construct(){ $status = 'iADMIN'; } } class MemberViewer extends RegistrationViewer{ public function __construct(){ $status = 'iMEMBER'; } } ?> With this, polymorphism takes the place of the conditionals. Obviously, I must give the classes something to do, but right now I'm just focused on the preliminary setup. I'm thinking of doing something along the lines of: <?php class RegistrationViewer{ protected $status; public function __construct(){ switch($userdata['user_level']){ //built-in PHP-Fusion array case 101: return new MemberViewer(); break; case 102: case 103: return new AdminViewer(); break; default: echo "You're not a registered user!"; return false; } } abstract function makeMenu(); } class AdminViewer extends RegistrationViewer{ public function __construct(){ $status = 'iADMIN'; } public function makeMenu(){ //make the admin menus } } class MemberViewer extends RegistrationViewer{ public function __construct(){ $status = 'iMEMBER'; } public function makeMenu(){ //make the member menu } } ?> Do I have the syntax right? Actually, more to the point, am I on the right track so far? Quote Link to comment Share on other sites More sharing options...
KevinM1 Posted July 17, 2007 Author Share Posted July 17, 2007 So, now for the next step: writing all of my viewer classes. Before I do that, though, I need to figure out what to do with the forms' (that will be built via makeMenu) actions. I believe that keeping the scripts seperate will be the most efficient way to handle things. That way, I can use a Factory to create whatever objects I need on that page out of the info that's passed to it by POST. For the viewer classes themselves, there's an added wrinkle. There are TWO lists that must be made for site administrators. I could just copy what I have in my old script to the makeMenu() function, but I'm not sure if that's really OOP-ish. On the one hand, both lists use the same form. On the other, everything else about them is seperate, even their respective inputs. I'm leaning towards separating the two processes, but I'm not sure how to incorporate them into the makeMenu() function. Any vets have any ideas on this? In any event, MemberViewer is ready to be completed as it only has one list to make. <?php class RegistrationViewer{ protected $status; public function __construct(){ switch($userdata['user_level']){ //built-in PHP-Fusion array case 101: return new MemberViewer(); break; case 102: case 103: return new AdminViewer(); break; default: echo "You're not a registered user!"; return false; } } abstract function makeMenu(); } class AdminViewer extends RegistrationViewer{ public function __construct(){ $this -> status = 'iADMIN'; } public function makeMenu(){ //do stuff } } class MemberViewer extends RegistrationViewer{ public function __construct(){ $this -> status = 'iMEMBER'; } public function makeMenu(){ $formText = ""; $query = "SELECT * FROM ". DB_PREFIX ."aflac WHERE user_id = '". $userdata['user_id'] ."'"; $result = dbquery($query); $formText .= "<form method='POST' action='registration_controller.php'>\n<br />\n"; $formText .= "Your registrations:<br /><br />\n"; $formText .= "<select name='events[]'>\n<br />\n"; $formText .= "<option value='*'>All</option>\n<br />\n"; while($row = mysql_fetch_assoc($result)){ $formText .= "<option value='{$row['user_id']}, {$row['ev_id']}, {$row['login_timestamp']}'>{$row['ev_title']} -- ". date('M j, Y', $row['login_timestamp']) ."</option>\n<br />\n"; } $formText .= "</select>\n"; $formText .= "<input type='submit' name='submit' value='Go' />\n<br />\n</form>\n<br />\n"; return $formText; } } ?> As you can see, the process remains the same as it was in the old script, with the exception that all of the echoed text is now returned as a large string. There isn't any error checking with the database as any empty queries create empty lists in the form, letting the user see that they haven't registered for anything yet. And yes, I know that my constructor code changed slightly...I forgot to add $this to the first versions. Oops! Quote Link to comment Share on other sites More sharing options...
KevinM1 Posted July 17, 2007 Author Share Posted July 17, 2007 Now that I've got my classes somewhat constructed (the obvious exception being AdminViewer), it's time to test it out. So, here's my test script (regviewertest.php5): <?php require_once "maincore.php"; require_once "subheader.php"; require_once "side_left.php"; require_once "regclasses.php5"; $viewer = new RegistrationViewer(); $menu = $viewer->makeMenu(); echo "$menu"; require_once "side_right.php"; require_once "footer.php"; ?> Sexy, huh? The required regclasses.php5 file is, obviously, the file containing my classes. So, I fire up the script and get the following message: Fatal error: Class RegistrationViewer contains 1 abstract method and must therefore be declared abstract or implement the remaining methods (RegistrationViewer::makeMenu) in /home/nights/www/www/regclasses.php5 on line 22 I didn't realize that abstract methods weren't allowed in normal classes. It's a nice little 'gotcha' to remember. So, I modify my classes to be the following: <?php class RegistrationViewer{ protected $status; public static function getInstance(){ switch($userdata['user_level']){ //built-in PHP-Fusion array case 101: return new MemberViewer(); break; case 102: case 103: return new AdminViewer(); break; default: echo "You're not a registered user!"; return false; } } } /* class AdminViewer extends RegistrationViewer{ public function __construct(){ $this -> status = 'iADMIN'; } public function makeMenu(){ //do stuff } } */ class MemberViewer extends RegistrationViewer{ public function __construct(){ $this -> status = 'iMEMBER'; } public function makeMenu(){ $formText = ""; $query = "SELECT * FROM ". DB_PREFIX ."aflac WHERE user_id = '". $userdata['user_id'] ."'"; $result = dbquery($query); $formText .= "<form method='POST' action='registration_controller.php'>\n<br />\n"; $formText .= "Your registrations:<br /><br />\n"; $formText .= "<select name='events[]'>\n<br />\n"; $formText .= "<option value='*'>All</option>\n<br />\n"; while($row = mysql_fetch_assoc($result)){ $formText .= "<option value='{$row['user_id']}, {$row['ev_id']}, {$row['login_timestamp']}'>{$row['ev_title']} -- ". date('M j, Y', $row['login_timestamp']) ."</option>\n<br />\n"; } $formText .= "</select>\n"; $formText .= "<input type='submit' name='submit' value='Go' />\n<br />\n</form>\n<br />\n"; return $formText; } } And my script has changed slightly in order to use the static function: <?php require_once "maincore.php"; require_once "subheader.php"; require_once "side_left.php"; require_once "regclasses.php5"; $viewer = RegistrationViewer::getInstance(); $menu = $viewer->makeMenu(); echo "$menu"; require_once "side_right.php"; require_once "footer.php"; ?> Unfortunately, we lose the makeMenu() function from the base class. But since I want to rely on polymorphism to return the correct object, I believe that's the only thing I could do. Upon the next test, I get the following output: You're not a registered user! Fatal error: Call to a member function makeMenu() on a non-object in /home/nights/www/www/regviewertest.php5 on line 12 It looks like my parent class isn't recognizing that my current user level is indeed 101 (which I double-checked in the script by echoing $userdata['user_level']). Because of this, $viewer = false. That, in turn, means that it can't call makeMenu() because it's not an object. The worst part is, however, is that I'm not sure why the logic error is occurring as my syntax looks to be correct and, as I said above, my user level is 101. I should be getting a MemberViewer object back. So, any vets mind helping me out with this error? I'm at a bit of a loss. Quote Link to comment Share on other sites More sharing options...
keeB Posted July 18, 2007 Share Posted July 18, 2007 $viewer is not an object. That's why you cant call makeMenu(). Quote Link to comment Share on other sites More sharing options...
KevinM1 Posted July 18, 2007 Author Share Posted July 18, 2007 $viewer is not an object. That's why you cant call makeMenu(). I know that. $viewer SHOULD be an object, though, as getInstance is supposed to return an object, its type determined by the user's user level. In my test script, it's supposed to be a MemberViewer object. Quote Link to comment Share on other sites More sharing options...
keeB Posted July 18, 2007 Share Posted July 18, 2007 So, that means $userdata['user_level'] is not set properly in your script. That's what I think Quote Link to comment Share on other sites More sharing options...
KevinM1 Posted July 18, 2007 Author Share Posted July 18, 2007 With a little help of someone on another forum, I've gotten my test to work. The problem I had: For some reason, the global array $userdata didn't work right within my classes. The solution: Removing direct calls to it solved that issue, and, as a positive side effect, made my class code less reliant on its environment. I've refined my classes a bit more: There's a new property, $userId, which is used in database calls. I've made both $status and $userId static as they should remain the same throughout the class' lifetimes. I didn't make $status const mainly because I hate dealing with PHP consts. I've added a debugging method. Class code: <?php class RegistrationViewer{ protected static $status; protected static $userId; public static function getInstance($userLevel, $userId){ switch($userLevel){ case 101: return new MemberViewer('iMEMBER', $userId); break; case 102: case 103: return new AdminViewer('iADMIN', $userId); break; default: echo "You're not a registered user!"; return false; } } public function printStatus(){ //for debugging echo 'User level: '. $this->status .'<br />User ID: '. $this->userId .'<br /><br />'; } } /* class AdminViewer extends RegistrationViewer{ public function __construct($status, $userId){ $this->status = $status; $this->userId = $userId; } public function makeMenu(){ do stuff } } */ class MemberViewer extends RegistrationViewer{ public function __construct($status, $userId){ $this->status = $status; $this->userId = $userId; } public function makeMenu(){ $formText = ""; $query = "SELECT * FROM ". DB_PREFIX ."aflac WHERE user_id = '". $this->userId ."'"; $result = dbquery($query); $formText .= "<form method='POST' action='registration_controller.php'>\n<br />\n"; $formText .= "Your registrations:<br /><br />\n"; $formText .= "<select name='events[]'>\n<br />\n"; $formText .= "<option value='*'>All</option>\n<br />\n"; while($row = mysql_fetch_assoc($result)){ $formText .= "<option value='{$row['user_id']}, {$row['ev_id']}, {$row['login_timestamp']}'>{$row['ev_title']} -- ". date('M j, Y', $row['login_timestamp']) ."</option>\n<br />\n"; } $formText .= "</select>\n"; $formText .= "<input type='submit' name='submit' value='Go' />\n<br />\n</form>\n<br />\n"; echo $formText; } } ?> Test script: <?php require_once "maincore.php"; require_once "subheader.php"; require_once "side_left.php"; require_once "regclasses.php5"; $viewer = RegistrationViewer::getInstance($userdata['user_level'], $userdata['user_id']); $viewer->printStatus(); $menu = $viewer->makeMenu(); require_once "side_right.php"; require_once "footer.php"; ?> Quote Link to comment Share on other sites More sharing options...
keeB Posted July 18, 2007 Share Posted July 18, 2007 You may want to create a generic user object. <?php class User { public $userId; public $userLevel; function User($userId) { $this->userId = $userId; } . . . . } ?> That way, you can turn your code to look something like this: Class code: <?php class RegistrationViewer{ protected static $status; protected static $userId; public static function getInstance(User $user){ switch($user->userLevel){ case 101: return new MemberViewer('iMEMBER', $user->userId); break; case 102: case 103: return new AdminViewer('iADMIN', $user->userId); break; default: echo "You're not a registered user!"; return false; } } public function printStatus(){ //for debugging echo 'User level: '. $this->status .'<br />User ID: '. $this->userId .'<br /><br />'; } } /* class AdminViewer extends RegistrationViewer{ public function __construct($status, $userId){ $this->status = $status; $this->userId = $userId; } public function makeMenu(){ do stuff } } */ class MemberViewer extends RegistrationViewer{ public function __construct($status, $userId){ $this->status = $status; $this->userId = $userId; } public function makeMenu(){ $formText = ""; $query = "SELECT * FROM ". DB_PREFIX ."aflac WHERE user_id = '". $this->userId ."'"; $result = dbquery($query); $formText .= "<form method='POST' action='registration_controller.php'>\n<br />\n"; $formText .= "Your registrations:<br /><br />\n"; $formText .= "<select name='events[]'>\n<br />\n"; $formText .= "<option value='*'>All</option>\n<br />\n"; while($row = mysql_fetch_assoc($result)){ $formText .= "<option value='{$row['user_id']}, {$row['ev_id']}, {$row['login_timestamp']}'>{$row['ev_title']} -- ". date('M j, Y', $row['login_timestamp']) ."</option>\n<br />\n"; } $formText .= "</select>\n"; $formText .= "<input type='submit' name='submit' value='Go' />\n<br />\n</form>\n<br />\n"; echo $formText; } } ?> Just a suggestion Quote Link to comment Share on other sites More sharing options...
KevinM1 Posted July 18, 2007 Author Share Posted July 18, 2007 Good idea. I just implemented that now: <?php class User{ private $userLevel; private $userId; public function __construct($userLevel, $userId){ $this->userLevel = $userLevel; $this->userId = $userId; } public function getUserLevel(){ return $this->userLevel; } public function getUserId(){ return $this->userId; } } class RegistrationViewer{ protected static $status; protected static $userId; public static function getInstance(User $user){ switch($user->getUserLevel()){ case 101: return new MemberViewer('iMEMBER', $user->getUserId()); break; case 102: case 103: return new AdminViewer('iADMIN', $user->getUserId()); break; default: echo "You're not a registered user!"; return false; } } public function printStatus(){ echo 'User level: '. $this->status .'<br />User ID: '. $this->userId .'<br /><br />'; } } /* class AdminViewer extends RegistrationViewer{ public function __construct($status, $userId){ $this->status = $status; $this->userId = $userId; } public function makeMenu(){ do stuff } } */ class MemberViewer extends RegistrationViewer{ public function __construct($status, $userId){ $this->status = $status; $this->userId = $userId; } public function makeMenu(){ $formText = ""; $query = "SELECT * FROM ". DB_PREFIX ."aflac WHERE user_id = '". $this->userId ."'"; $result = dbquery($query); $formText .= "<form method='POST' action='registration_controller.php'>\n<br />\n"; $formText .= "Your registrations:<br /><br />\n"; $formText .= "<select name='events[]'>\n<br />\n"; $formText .= "<option value='*'>All</option>\n<br />\n"; while($row = mysql_fetch_assoc($result)){ $formText .= "<option value='{$row['user_id']}, {$row['ev_id']}, {$row['login_timestamp']}'>{$row['ev_title']} -- ". date('M j, Y', $row['login_timestamp']) ."</option>\n<br />\n"; } $formText .= "</select>\n"; $formText .= "<input type='submit' name='submit' value='Go' />\n<br />\n</form>\n<br />\n"; echo $formText; } } ?> And the test script is: <?php require_once "maincore.php"; require_once "subheader.php"; require_once "side_left.php"; require_once "regclasses.php5"; $currentUser = new User($userdata['user_level'], $userdata['user_id']); $viewer = RegistrationViewer::getInstance($currentUser); $viewer->makeMenu(); require_once "side_right.php"; require_once "footer.php"; ?> I feel I should pause and explain the benefits of this method of coding to any newbies reading in case it's not obvious. The functionality is more or less the same as it was in the procedural script. The difference, however, is that it's sequestered away into classes and objects. The only real OOP-ish component, at this point, is how getInstance() works. It automatically returns the correct type of RegistrationViewer object at runtime as it's derived from what kind of User is currently trying to access the page. The benefits are most appearent in the actual test script. Rather than having to put all of the form-creation process in the script itself, and repeat it where ever I want the form, I can just create a new object and call makeMenu(). The form is, at least in the realm of PHP-Fusion, modular. Up next: AdminViewer's makeMenu()! Quote Link to comment Share on other sites More sharing options...
KevinM1 Posted July 18, 2007 Author Share Posted July 18, 2007 I made the decision to break AdminViewer's makeMenu() method into smaller chunks -- one to deal with an administrator's personal event registrations, the other to deal with ALL event registrations. This allows me to keep the generic makeMenu() method call, but with specific things occurring in the background: <?php class User{ private $userLevel; private $userId; public function __construct($userLevel, $userId){ $this->userLevel = $userLevel; $this->userId = $userId; } public function getUserLevel(){ return $this->userLevel; } public function getUserId(){ return $this->userId; } } class RegistrationViewer{ protected static $status; protected static $userId; public static function getInstance(User $user){ switch($user->getUserLevel()){ case 101: return new MemberViewer('iMEMBER', $user->getUserId()); break; case 102: case 103: return new AdminViewer('iADMIN', $user->getUserId()); break; default: echo "You're not a registered user!"; return false; } } public function printStatus(){ echo 'User level: '. $this->status .'<br />User ID: '. $this->userId .'<br /><br />'; } } class AdminViewer extends RegistrationViewer{ public function __construct($status, $userId){ $this->status = $status; $this->userId = $userId; } public function makeMenu(){ echo $this->makePersonalMenu() . $this->makeAdminMenu(); } public function makePersonalMenu(){ $formText = ""; $query = "SELECT * FROM ". DB_PREFIX ."aflac WHERE user_id = '". $this->userId ."'"; $result = dbquery($query); $formText .= "<form method='POST' action='registration_controller.php'>\n<br />\n"; $formText .= "Your registrations: <br /><br />\n"; $formText .= "<select name='personalEvents[]'>\n<br />\n"; $formText .= "<option value='*'>All</option>\n<br />\n"; while($row = mysql_fetch_assoc($result)){ $formText .= "<option value='{$row['user_id']}, {$row['ev_id']}, {$row['login_timestamp']}'>{$row['ev_title']} -- ". date('M j, Y', $row['login_timestamp']) ."</option>\n<br />\n"; } $formText .= "</select>\n"; $formText .= "<input type='submit' name='personalSubmit' value='Go' />\n<br />\n<br /><br /><br /><br />\n"; return $formText; } public function makeAdminMenu(){ $formText = ""; $query = "SELECT * FROM ". DB_PREFIX ."aflac"; $result = dbquery($query); $formText .= "All registrations: <br /><br />\n"; $formText .= "<select name='adminEvents[]'>\n<br />\n"; $formText .= "<option value='*'>All</option>\n<br />\n"; while($row = mysql_fetch_assoc($result)){ $formText .= "<option value='{$row['user_id']}, {$row['ev_id']}, {$row['login_timestamp']}'>{$row['registering_agent']}: {$row['ev_title']} -- ". date('M j, Y', $row['login_timestamp']) ."</option>\n<br />\n"; } $formText .= "</select>\n"; $formText .= "<input type='submit' name='adminSubmit' value='Go' />\n<br />\n<br />\n</form>\n"; return $formText; } } class MemberViewer extends RegistrationViewer{ public function __construct($status, $userId){ $this->status = $status; $this->userId = $userId; } public function makeMenu(){ $formText = ""; $query = "SELECT * FROM ". DB_PREFIX ."aflac WHERE user_id = '". $this->userId ."'"; $result = dbquery($query); $formText .= "<form method='POST' action='registration_controller.php'>\n<br />\n"; $formText .= "Your registrations:<br /><br />\n"; $formText .= "<select name='events[]'>\n<br />\n"; $formText .= "<option value='*'>All</option>\n<br />\n"; while($row = mysql_fetch_assoc($result)){ $formText .= "<option value='{$row['user_id']}, {$row['ev_id']}, {$row['login_timestamp']}'>{$row['ev_title']} -- ". date('M j, Y', $row['login_timestamp']) ."</option>\n<br />\n"; } $formText .= "</select>\n"; $formText .= "<input type='submit' name='submit' value='Go' />\n<br />\n</form>\n<br />\n"; echo $formText; } } ?> Now that this all working, the hard part begins -- transforming registration_controller. Before we dive right in, we must look at how the Viewer classes create their respective forms. In each case, the forms' select elements each have a different name. Each submit button also has a different name corresponding to those select element names. How can I create a Controller object that can accept any of the Viewers' info and return the correct data from the table, as well as edit and delete the correct items? Is this even possible? The problem hinges on AdminViewer. It creates one form, but it has TWO submit buttons, and TWO different lists of information. I think that creating a specific Member/AdminController behind a generic RegistrationController facade (much like Member/AdminViewer was created by the generic RegistrationViewer) is the way to go. The structure will be similar to what I've already built, and it will give the Controllers some modularity (at least, in the context of PHP-Fusion). EDIT: just thought of something. The original script is a sticky form. Is there any way for me to emulate that functionality within a class? Quote Link to comment Share on other sites More sharing options...
KevinM1 Posted July 20, 2007 Author Share Posted July 20, 2007 Shameless bump.... I still haven't figured out how to reproduce sticky form functionality using OOP. Are there any patterns/combinations of patterns I should look for? Thanks. Quote Link to comment Share on other sites More sharing options...
keeB Posted July 21, 2007 Share Posted July 21, 2007 Can you explain what you mean by a "sticky form?" Quote Link to comment Share on other sites More sharing options...
KevinM1 Posted July 21, 2007 Author Share Posted July 21, 2007 Can you explain what you mean by a "sticky form?" A sticky form is a form that will display the info the user input (in the correct form fields) upon an unsuccessful form submission. This is a convenience for the user as it makes it so they don't need to re-enter all of their info if the submission fails. So something like: <input type="text" name="username" value="<?php if(isset($_POST['username'])){echo $_POST['username'];} ?>" /> Now that I think about it more, though, I don't need a sticky form as the only input is only a series of checkboxes. What I do need, however, is this: My current controller forms use their own scripts as the forms' action. <form action="<?php echo $_SERVER['PHP_SELF']; ?>" method="POST"> . . . </form> I'm not sure how to do the same thing in an OOP manner. Is there an OOP way to do this? Or are forms like this typically handled in a procedural manner? Quote Link to comment Share on other sites More sharing options...
keeB Posted July 21, 2007 Share Posted July 21, 2007 You could do something like this <?php abstract class Form { abstract function addItem(Item $item, $value) abstract function draw() } abstract class Item { abstract function toHTML(); // abstract this to items like button, input, textarea, etc } class StickyForm extends Form { private $itemList; function addItem(Item $item, $value=NULL) { $this->itemList[] += array($item, value); } function draw() { foreach ($this->itemList as $item) { $obj = $item[0]; $obj->toHTML($item[1]); } } } ?> Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.