cgm225 Posted April 29, 2008 Share Posted April 29, 2008 I have a simple MVC (included below) which works fine, and recently I also coded a user authentication class (also included below) which works fine as well. However, I need the user authentication object to be available to all modules pulled in by the MCV, but I am not sure the best way to integrate this "global-like" object within my MVC without mixing their logics (which I want to avoid). Basically, I want to do something like instantiate the authentication class before/outside the MVC class, as such... $mysqli = new mysqli(MYSQL_SERVER, MYSQL_SERVER_USERNAME, MYSQL_SERVER_PASSWORD, 'example_authentication'); $authentication = new MysqliAuthentication($username, $password, $mysqli); ..and then somehow have the doLogin() and checkPermission() methods available to all modules brought in by the MCV (because other applications are going to need to check if someone is logged in or has proper permissions). Any ideas? Thank you all in advance! My MVC: <?php class FrontController extends ActionController { //Declaring variable(s) private static $instance; protected $controller; private function __construct(){} //Starting new instance of this class with a singleton pattern public static function getInstance() { if(!self::$instance) { self::$instance = new self(); } return self::$instance; } public function dispatch($throwExceptions = false) { /* Checking for the GET variables $module and $action, and, if present, will strip them down with a regular expression function with a white list of allowed characters, removing anything that is not a letter, number, underscore or hyphen. */ $regex = '/[^-_A-z0-9]++/'; $module = isset($_GET['module']) ? preg_replace($regex, '', $_GET['module']) : 'home'; $action = isset($_GET['action']) ? preg_replace($regex, '', $_GET['action']) : 'frontpage'; /* Generating Actions class filename (example: HomeActions) and path to that class (example: home/HomeActions.php5), checking if $file is a valid file, and then, if so, requiring that file. */ $class = ucfirst($module) . 'Actions'; $file = $this->pageDir . '/' . $module . '/' . $class . '.php5'; if (!is_file($file)) { throw new FrontControllerException('Page not found!'); } require_once $file; /* Creating a new instance of the Actions class (example: $controller = new HomeActions(), and passing page directory variable to the ActionController class. */ $controller = new $class(); $controller->setPageDir($this->pageDir); try { //Using the setModule method in the ActionController class $controller->setModule($module); /* The ActionController dispatchAction method Checks if the method exists, then runs the displayView function in the ActionController class. */ $controller->dispatchAction($action); } catch(Exception $error) { /* An exception has occurred, and will be displayed if $throwExceptions is set to true. */ if($throwExceptions) { echo $error->errorMessage($error); //Full exception echoed } else { echo $error->errorMessage(null); //Simple error messaged echoed } } } } abstract class ActionController { //Declaring variable(s) protected $pageDir; protected $module; protected $viewData = array(); public function setPageDir($pageDir){ $this->pageDir = $pageDir; } public function setModule($module) { $this->module = $module; } public function getModule() { return $this->module; } //Placing a value in the $viewData array at the key position public function setVar($key, $value) { $this->viewData[$key] = $value; } //Returns a value from the $viewData array located at the key position public function getVar($key) { if (array_key_exists($key, $this->viewData)) { return $this->viewData[$key]; } } public function getViewData($viewData) { $this->viewData = $viewData; } /* Checking for actionMethod in the Actions class (example: doFrontpage() within home/HomeActions.php5) with the method_exists function and, if present, the actionMethod and displayView functions are executed. */ public function dispatchAction($action) { $actionMethod = 'do' . ucfirst($action); if (!method_exists($this, $actionMethod)) { throw new FrontControllerException('Page not found!'); } $this->$actionMethod(); $this->displayView($action); } public function displayView($action) { if (!is_file($this->pageDir . '/' . $this->getModule() . '/' . $action . 'View.php5')) { throw new FrontControllerException('Page not found!'); } //Setting $this->actionView to the path of the action View file $this->actionView = $this->pageDir . '/' . $this->getModule() . '/' . $action . 'View.php5'; /* Creating a new instance of the View class and passing the $pageDir, $viewData, and actionView variables */ $view = new View(); $view->setPageDir($this->pageDir); $view->getViewData($this->viewData); $view->setVar('actionView',$this->actionView); $view->render(); } } class View extends ActionController { public function render() { //Including default template settings require_once $this->pageDir . '/defaultTplSettings.php5'; /* Merging the default template variables with variables provided in the $this->viewData array, taken from the Actions class, giving priority to those provided by the action class, then extracting the array with the extract() function, which creates a variable for every array value, and the name of the value (the variable name) is the key's value. */ $templateSettings = array_merge($defaultTemplateSettings, $this->viewData); extract($templateSettings, EXTR_OVERWRITE); //Including template file within which the action View file is included require_once $this->pageDir . '/default.tpl'; } } class FrontControllerException extends Exception { public function errorMessage($error) { /* If and throwExceptions is true, then the full exception will be returned. */ $errorMessage = isset($error) ? $error : $this->getMessage(); return $errorMessage; } } ?> My user authentication class: interface Authentication { public function doLogin(); public function checkPermission($permission); } class MysqliAuthentication implements Authentication { /* Variable declaration */ private $username; private $password; private $connection; /* Sets username and raw password for authentication, as well as the * mysqli connection object WITH database selected */ public function __construct($username, $password, mysqli $connection) { $this->username = $username; $this->password = md5($password); $this->connection = $connection; } /* Checks provided username and password against a MySQL database table and * returns true if login is successful, followed with setting of username * and password session variables. */ public function doLogin() { $query = "SELECT COUNT(*) FROM users WHERE username = ? AND password = ?"; $statement = $this->connection->prepare($query); $statement->bind_param('ss', $this->username, $this->password); $statement->execute(); $statement->bind_result($count); $statement->fetch(); if ($count == 1) { return $this->setSession($this->username); } else { return false; } } /* Checks if a username has a given permission found within a MySQL database * table, returning true if the username has the given permission. */ public function checkPermission($permission) { $query = "SELECT COUNT(*) FROM permissions WHERE username = ? AND permission_for = ?"; $statement = $this->connection->prepare($query); $statement->bind_param('ss', $this->username, $permission); $statement->execute(); $statement->bind_result($count); $statement->fetch(); return $count == 1; } /* Sets the provided username and password to session variables */ private function setSession($username) { $_SESSION['username'] = $username; return true; } } Quote Link to comment Share on other sites More sharing options...
rhodesa Posted April 29, 2008 Share Posted April 29, 2008 Check out singletons: http://us2.php.net/manual/en/language.oop5.patterns.php#language.oop5.patterns.singleton Basically, you do the following: 1) Create a private static variable 2) Store $this into that variable in the constructor 3) Create a public static method called getInstance() that returns the value of the static variable 4) In your other classes, you would get the object like: $auth = MysqliAuthentication::getInstance(); Quote Link to comment Share on other sites More sharing options...
cgm225 Posted April 29, 2008 Author Share Posted April 29, 2008 Thank you for your reply! Could you help me a little more, showing me what my constructor and instantiation would look like? I am getting some syntax errors. Thanks again! Quote Link to comment Share on other sites More sharing options...
rhodesa Posted April 29, 2008 Share Posted April 29, 2008 You actually already use the concept in your FrontController With this, you will only be allowed to have one user, but I would assume that is what you want...right? class MysqliAuthentication implements Authentication { /* Variable declaration */ private $username; private $password; private $connection; private static $instance; /* Sets username and raw password for authentication, as well as the * mysqli connection object WITH database selected */ public function __construct($username, $password, mysqli $connection) { $this->username = $username; $this->password = md5($password); $this->connection = $connection; self::$instance = $this; } public static function getInstance(){ return self::$instance; } .... So now, you do this once: $mysqli = new mysqli(MYSQL_SERVER, MYSQL_SERVER_USERNAME, MYSQL_SERVER_PASSWORD, 'example_authentication'); $authentication = new MysqliAuthentication($username, $password, $mysqli); And from anywhere, can you retrieve it with: $auth = MysqliAuthentication::getInstance(); $auth->doLogin(); Quote Link to comment Share on other sites More sharing options...
cgm225 Posted April 29, 2008 Author Share Posted April 29, 2008 Thanks again for the help and examples. I tried your code (with the new variable declaration and constructor), and it works as it should when I test the following Outside my MVC, like in my index.php5 file (after I include the authentication class) for example... [ Line 1 ] $mysqli = new mysqli(MYSQL_SERVER, MYSQL_SERVER_USERNAME, MYSQL_SERVER_PASSWORD, [ Line 2 ] 'example_authentication'); [ Line 3 ] $authentication = new MysqliAuthentication($username, $password, $mysqli); [ Line 4 ] $auth = MysqliAuthentication::getInstance(); [ Line 5 ] $auth->doLogin(); However, if I first include lines 1 - 3, or even the 4th as well, before I instantiate my MVC class (like earlier in my index.php5 file), and then try to call the $auth->doLogin method in my Action Class (which is called by my MCV (see earlier code; an example would be HomeActions), I get the following errors Notice: Undefined variable: auth ... Fatal error: Call to a member function doLogin() on a non-object ... Any ideas on what I am doing wrong? Thanks again for all your help!! Quote Link to comment Share on other sites More sharing options...
rhodesa Posted April 29, 2008 Share Posted April 29, 2008 Almost there. Inside your MVC class, you don't have access to $auth, as it's outside of your scope. So, we simply retrieve it again with getInstance() class FrontController extends ActionController { //blah blah function someFunction ( ) { $auth = MysqliAuthentication::getInstance(); $auth->doLogin(); } //blah blah } Then in index.php <?php $mysqli = new mysqli(MYSQL_SERVER, MYSQL_SERVER_USERNAME, MYSQL_SERVER_PASSWORD,'example_authentication'); new MysqliAuthentication($username, $password, $mysqli); //We don't even need to store the object in a variable since it's stored within itself $mvc = new FrontController(); $mvc->someFunction(); ?> Quote Link to comment Share on other sites More sharing options...
cgm225 Posted April 29, 2008 Author Share Posted April 29, 2008 perfect.. thank you for helping me power through that! Quote Link to comment Share on other sites More sharing options...
cgm225 Posted April 29, 2008 Author Share Posted April 29, 2008 So follow up question: given the structure of my MVC, where would you place the... $auth = MysqliAuthentication::getInstance(); ...so that the doLogin() method is available to all the extended classes? I was thinking somewhere in the ActionController class? I just don't want to have to redundantly include that line of code every time I want to use the doLogin(). Thanks again. Quote Link to comment Share on other sites More sharing options...
rhodesa Posted April 29, 2008 Share Posted April 29, 2008 You can use the MVC constructor to call: $this->auth = MysqliAuthentication::getInstance(); Then any class that extends the MVC can use: $this->auth->doLogin(); Quote Link to comment Share on other sites More sharing options...
cgm225 Posted April 29, 2008 Author Share Posted April 29, 2008 That is exactly what I needed. And here is another question, in my case, with my MVC, how would you get that $this->auth object value to the abstract ActionController class (which most of my classes extend)? Would you create a setNewAuth function in the ActionController and pass it that way? Like this I mean (similar to how I pass the page dir): public function setNewAuth($newAuth){ $this->auth = $newAuth; } Or would you do it another way? My ActionController is abstract so I don't have a constructor in there. Edit: Also, again, I want to be careful here that I am not mixing up my different logics? Thanks again! Quote Link to comment Share on other sites More sharing options...
cgm225 Posted April 29, 2008 Author Share Posted April 29, 2008 Got it.. didn't realize abstract classes could have constructs 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.