Tuesday, August 6, 2013

Not So Simple-Student Registration PHP Program

The Requirements
REQUIREMENTS

Create a student class registration form that contains the following:

1. The system will provide a link to allow the user to create a 
userid and password (and enter name and major) if they do not
have one. When the user is correctly signed in, an entry will
be made in the log file. 
1A. The program will interface with four text files. 

1A1. One text file contains userid and password information. 
1A2. One text file contains classes available to take, including 
class number, class name, class size and current number
of students in the class.
1A3. One text file contains a log file which logs who accessed 
the system and when they accessed the system. 
1A4. One text file will include the userid, student name, major, 
and classes selected (see below).
2. When the user brings up the system it will ask for their userid and password. 
It will verify this information from the user text file.
3. The system will scan the student information text file for the userid entered 
and pull the students information from the flle to create a student object which 
will contain the userid, name, major of the student and three (empty) properties 
to hold classes the student wishes to take.
4. The system will use the classes text file to display available classes and allow 
the user to pick classes to take. The system will update the classes text file 
to adjust the number of students taking the class. If a class if full, the class 
is not displayed to the user to select. Use check boxes, or something smilar to 
allow the student to pick up to three classes.
5. Once the classes have been selected by the student, the system will display the 
student name, major, and classes selected by the student, update the student object 
to include the three (or less) classes selected, and save this information 
(student name, major, classes) in a text file. 
5A. This file should append information so the program can be run again to add other student information.


---------------------------------------

CLASSES - all have limit 30 and reg 0
CIST2351-PHP Programming 
ENGL2130-American Literature 
HUMN1101-Introduction to Humanities
CIST1520-Scripting Technologies
CIST2381-MOBILE APP DEVELOPMENT
CIST1305-PROGRAM DESIGN AND DEVELOPMENT 
CIST1520-SCRIPTING TECHNOLOGIES
MATH1111-COLLEGE ALGEBRA


---------------------------------------

Notes

Using "require" in the controller rather than "include" because an error message should be thrown if 
a view fragment is missing.

The first file I will discuss will be the generic file, it is simply an HTML file with a link to the main HTML file
A little bit of style to make it pretty and some opening and closing head and body tags and this file is complete. Only an idiot could mess this one up! 

<style>
body {
background-color:pink;
font-family: Arial, Helvetica, sans-serif;
font-size: 12pt;
color: #030303;
}
</style>

</head>

<body>

<h1 style="text-align: center; margin-top: 20%;">
<a href="default.html">CLICK HERE</a>
</h1>
</body>
Let's get this thing started, I know that is what you are thinking, thats a file anyone could make, show me the meat of the meal.. Ok here is a more in depth file
its the default.html file.
<!DOCTYPE html> ---This just gets us started
<html lang="en">
<head>
Lets break it down a little bit so I can explain what each chunk of code's mission is. 

<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/modernizr/2.5.3/modernizr.min.js"></script>
This is the part that gets the JavaScript & jQuery involved, there are a few links that google has been kind enough to publish for developers to use such scripts on their pages without installing all the proper files on the developers server.. Googleapis has the files on their server you simply just supply the link and it goes into the google files and pulls out what you need to make your magic work. 


<script type="text/javascript"src="default.js"></script>
This line points to the java script file created for the program ( to be discussed in detail later.)

<link rel="stylesheet" 
type="text/css" 
href="default.css" />
This line points to the css style sheet that defines the design of the program ( to be discussed in detail later.)

  <div id= "navDiv" name="navDiv">
To get the menu on the left hand side of the program, 
"navDiv",
heads over to the css file and pulls out 
[default.css]
#navDiv {float: left;}
 to style the navigational menu, the link to the file above allows us to do this, the file must be in the same folder or a path must be directed to the css file. 
    <nav>

<p>

<a href="http://chattahoocheetech.edu/">Home</a>
  </p>
  <p>
<a href="http://ctcweb.chattahoocheetech.edu/sports/">
Sports</a>
  </p>
  </nav>



A few links for the navigational bar are supplied in the above code.    


  <input type="hidden" id="loggedInUserName" name="loggedInUserName" />
This code declares the variable for the user's name  as they log in to the registration system.

 <div id="contentDiv" name="contentDiv">

 
And again we call on the css to style the output the user will interface during the program. 

   

[default.css]

#contentDiv {
margin-left: 30px;
float: left;
margin-top: 10px;
Above is the block of css that does this.

}
<input type="hidden" name="action" id="action" value="login"/> />
   </div> 
The "hidden" attribute lets us keep up with information for the duration of the user's session.

<div style="clear: both;"></div>
The W3C suggests placing a "cleared" element last in the container box, which is then recognized by the container height, forcing the container to enclose the float above that cleared element too. 
“..let's say you give that following box the clear property,  {clear: both;} . What this does is extend the margin on the top of the cleared box, pushing it down until it "clears" the bottom of the float. In other words, the top margin on the cleared box (no matter what it may have been set to), is increased by the browser, to whatever length is necessary to keep the cleared box below the float.”
So in effect, such a cleared box cannot be at the same horizontal level as a preceding float. It must appear just below that level. The image shows how this might look, with a red border representing the container element:
The standard method of making an outer container appear to "enclose" a nested float is to place a complete "cleared" element last in the container, which has the effect of 'dragging' the lower edge of the containing box lower than the float. Thus the float appears to be enclosed within the container even tho it really isn't.




<footer>
  <p>
  &copy; Copyright 2013 DANDE WEB DESIGNS
  </p>
  </footer>
    </div> 
</body>
</html> 
THE <footer> again tells the code to go look for the css file, and find out what it says to do about the information between the <p>&</p> tags defined by the <footer></footer> tags.
[default.css] 
footer {font-size: small;

color:blue;

        text-align:center;
  clear:right;
        padding-bottom:20px;
The last of the code simply closes the body and the html. 
end of default.html details.

*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-

Controller.php
The controller is the first thing which takes a request, parses it, initializes and invoke the model and takes the model response and sends it to the presentation layer. It’s practically the liant between the Model and the View, a small framework where Model and View are plugged in. In our  php implementation the controller is implemented by only one class, named unexpectedly controller. 
                         <?php  

require_once 'Model.User.php';
require_once 'Model.Student.php';
require_once 'Model.Classes.php';
The require_once statement is used to include other files into the controller.The require_once statement is identical to require, except PHP will check to see if the file has already been included, and if so, not include(require) it to be included again. 
$accessLogger = new AccessLogModel($_SERVER["REMOTE_ADDR"]);
The ServerVariables collection is used to retrieve the server variable values.
$accessLogger sets a variable that Returns the IP address of the remote host making the request from the server ["REMOTE_ADDR"].

PHP Switch Statement

switch ($_POST["action"]) {
The switch statement is used to perform different actions based on different conditions.
Use the switch statement to select one of many blocks of code to be executed.
case "authenticate" :

        $theUser = new UserModel();
        $theUser -> Retrieve($_POST["userNameTextBox"]);

        if ($theUser -> validUser) {
            if ($theUser -> password == $_POST["passwordTextBox"]) {
                $accessLogger -> LogEntry($_POST["userNameTextBox"], $_POST["passwordTextBox"], "login", "success");
                require "View.Profile.html";
            } else {
                $accessLogger -> LogEntry($_POST["userNameTextBox"], $_POST["passwordTextBox"], "login", "fail");
                print "";
            }
        } else {
            if ($_REQUEST["conditionalCreateCheckBox"] == "1") {
                $theUser -> Create($_POST["userNameTextBox"], $_POST["passwordTextBox"]);
                if ($theUser -> validUser) {
                    $accessLogger -> LogEntry($_POST["userNameTextBox"], $_POST["passwordTextBox"], "accountcreate", "success");
                    require "View.Profile.html";
                } else {
                    $accessLogger -> LogEntry($_POST["userNameTextBox"], $_POST["passwordTextBox"], "accountcreate", "fail");
                }
            } else {
                print "";
            }
        }

This is how it works: First we have an expression  ($_POST["action"])), that is evaluated once. The value of the expression is then compared with the values for each case in the structure.
case "loadProfile" :
        $theStudent = new StudentModel();
        $theStudent -> Retrieve($_POST["user"]);
        if ($theStudent -> validStudent) {
            $result -> data -> type = "student";
            $result -> data -> username = strval($theStudent -> username);
            $result -> data -> name = strval($theStudent -> studentName);
            $result -> data -> major = strval($theStudent -> major);
        } else {
            $theStudent -> Create($_POST["user"]);
            if ($theStudent -> validStudent) {
                $result -> data -> type = "student";
                $result -> data -> username = strval($theStudent -> username);
                $result -> data -> name = "";
                $result -> data -> major = "";
            } else {
                $result -> data -> username = "Invalid Student Detected.";
            }
        }
        echo json_encode($result);

        break;

    case "profile" :
        $username = $_POST["userNameTextBox"];
        $theStudent = new StudentModel();
        $theStudent -> Retrieve($username);
        if ($theStudent -> validStudent) {
            $saveRequired = false;
            if ($theStudent -> username != $username) {
                $theStudent -> username = $username;
                $saveRequired = true;
            }
            if ($theStudent -> studentName != $_POST["nameTextBox"]) {
                $theStudent -> studentName = $_POST["nameTextBox"];
                $saveRequired = true;
            }
            if ($theStudent -> major != $_POST["majorTextBox"]) {
                $theStudent -> major = $_POST["majorTextBox"];
                $saveRequired = true;
            }
            if ($saveRequired) {
                $theStudent -> Save();
                if ($theStudent -> validStudent == true) {
                    require "View.ClassReg.html";
                } else {
                    print "";
                }
            } else {
                require "View.ClassReg.html";
            }
        } else {
            echo "";
        }
        break;

    case "loadClassReg" :
        $username = $_POST["user"];

        $theStudent = new StudentModel();
        $theStudent -> Retrieve($username);

        $theClasses = new ClassesModel();
        $theClassList = $theClasses -> GetClassList();

        foreach ($theClassList as $class) {
            $full = (intval($class["actual"]) >= intval($class["limit"]));
            $registered = ($class["number"] == $theStudent -> class1 || $class["number"] == $theStudent -> class2 || $class["number"] == $theStudent -> class3);

            print "<div class='summaryBlock'><input ";

            if ($full && ($registered == false))
                print "disabled='disabled' ";

            if ($registered)
                print "checked='checked' ";

            print "type='checkbox' id='classCheckBox' name='classCheckBox' value='" . $class["number"] . "'/>";
            print "&nbsp;" . $class["number"] . "&nbsp;";
            print $class["name"];

            if ($full)
                print " (FULL)";

            print "</div>";

        }

        break;

    case "classReg" :
        $Student = new StudentModel();
        $Student -> Retrieve($_POST["user"]);

        $registeredClasses = explode("|", $_POST["classes"]);

        if ($Student -> class1 == $registeredClasses[0] && $Student -> class2 == $registeredClasses[1] && $Student -> class3 == $registeredClasses[2]) {
            require "View.Summary.html";
            return;
        }

        $Student -> class1 = $registeredClasses[0];
        $Student -> class2 = $registeredClasses[1];
        $Student -> class3 = $registeredClasses[2];

        $Student -> Save();

        if ($Student -> validStudent == false) {
            // save has failed
            $accessLogger -> LogEntry($_POST["user"], "n/a", "register", "fail");
            print "";
            return;
        }

        $accessLogger -> LogEntry($_POST["user"], "n/a", "register", "success");

        $Classes = new ClassesModel();
        if ($Classes -> UpdateClassStudentCounts()) {
            require "View.Summary.html";
        } else {
            print "";
        }

        break;

    case "loadSummary" :
        $Student = new StudentModel();
        $classModel = new ClassesModel();

        $Student -> Retrieve($_POST["user"]);

        if ($Student -> validStudent) {
            $response -> message = "";
            $response -> Student = $Student;

            $response -> Class1Name = "";
            if ($Student -> class1 != "") {
                $classModel -> Retrieve($Student -> class1);
                $response -> Class1Name = strval($classModel -> className);
            }
            $response -> Class2Name = "";
            if ($Student -> class2 != "") {
                $classModel -> Retrieve($Student -> class2);
                $response -> Class2Name = strval($classModel -> className);
            }
            $response -> Class3Name = "";
            if ($Student -> class3 != "") {
                $classModel -> Retrieve($Student -> class3);
                $response -> Class3Name = strval($classModel -> className);
            }

        } else {
            $response -> message = "Invalid student record detected.";
        }

        print json_encode($response);
        break;

    case "logout" :
        $accessLogger -> LogEntry($_POST["user"], "n/a", "logout", "success");
        require "View.Login.html";
        break;

    case "login" :
    default :
        require "View.Login.html";
        break; 
If there is a match, the block of code associated with that case is executed. Use break to prevent the code from running into the next case automatically. The default statement is used if no match is found.
This is the end of the 
Controller.php code, however, I need to go back and explain the mission of each case in detail.

 case "authenticate" :
        $theUser = new UserModel();
        $theUser -> Retrieve($_POST["userNameTextBox"]);
This case will authenticate the new user. the $theUser variable will Retrieve the Text that the user puts into the text box of the registration form. 

        if ($theUser -> validUser) {
            if ($theUser -> password == $_POST["passwordTextBox"]) {
                $accessLogger -> 
as well as verify the password, if the user has already been put into the system, and will pull up the users profile that has already been created. All transactions are logged into the accessLogger
LogEntry($_POST["userNameTextBox"], $_POST["passwordTextBox"], "login", "success");
                require "View.Profile.html";
            } else {
                $accessLogger -> LogEntry($_POST["userNameTextBox"], $_POST["passwordTextBox"], "login", "fail");
                print "";
            }
        } else {
            if ($_REQUEST["conditionalCreateCheckBox"] == "1") {
                $theUser -> Create($_POST["userNameTextBox"], $_POST["passwordTextBox"]);
                if ($theUser -> validUser) {
                    $accessLogger -> LogEntry($_POST["userNameTextBox"], $_POST["passwordTextBox"], "accountcreate", "success");
                    require "View.Profile.html";
                } else {
                    $accessLogger -> LogEntry($_POST["userNameTextBox"], $_POST["passwordTextBox"], "accountcreate", "fail");
                }
            } else {
                print "";
            }
        }

        break;












}