I recently released version 2.0 of my PHP MVC Framework. This is a quick example of how to use it.
Inside the configuration file (application/config/config.php) you will see a LOT of new ways to configure it. By default it tries to implement a lowerCamelCase naming convention. If the names aren’t obvious, let me know and I’ll try and update this section.
You will notice that you have a function below, if you wish, you can simply make the variable “$config['application']['hook']” a anonymous function if you wish. This is there so you can add events to the core, but since the eventQue has not been initialized yet, you will be unable to do so until later. I have a default one that triggers on the 404 page.
Next you will notice a database config file in the same directory. The name “default” is not necessary, you can name this whatever you want, the default database connection is always the first one in the array, regardless of the name of it. When calling a model you can pick which one of these profiles you want to use, or it will pick the default one. The drivers currently available are “mysql”, “mysqli”, and “mssql”.
Naming conventions is what I like the most about this framework. You might want to make a controller with the same name as a model, such as “user”. If both classes are named “user” it will throw an error. This allows me to add a suffix to a model “Model” by default and controller “Controller” but still call them by the same name. This is the case for the sample below, both the controller and model are called “pasteMaster”.
Another good thing about this framework, is that you can duplicate the “config.php” file. So the root application can have it’s own, then the admin panel can have another, this works great if you wanted the admin panel or something similar to have it’s own folder or URL.
I made a simple application that allows you to paste and view PHP code. This is not a secure application, it is just for demonstration purposes only. To do this I require a database connection, a single table, one controller, one model, and a few view files.
Here is the database structure I decided on:
CREATE TABLE `pasteMaster` ( `pasteId` INT NOT NULL AUTO_INCREMENT , `pasteURL` VARCHAR(45) NOT NULL , `pasteData` TEXT NOT NULL , `pasteType` VARCHAR(3) NOT NULL , `pasteDate` DATETIME NOT NULL , `pasteParent` INT NOT NULL DEFAULT 0 , PRIMARY KEY (`pasteId`) );
The model only has two new functions to interact with the database insertPaste($pasteURL, $pasteData, $pasteParent) and getPaste($url).
class pasteMasterModel extends Model { public function insertPaste($pasteURL, $pasteData, $pasteParent) { $this->query(" INSERT INTO `pasteMaster` (`pasteURL`, `pasteData`, `pasteDate`, `pasteParent`) VALUES ('{$pasteURL}', '{$pasteData}', NOW(), {$pasteParent}) "); return $this->insertId(); } public function getPaste($url) { return $this->query("SELECT * FROM `pasteMaster` WHERE `pasteURL` = '{$url}' LIMIT 1"); } }
I also created a small helper which can generate a hash and verify that a hash is valid or not. These are part of the helper “hashHelper”.
function generateHash() { $retLen = 10; $possible = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; $posLen = strlen($possible)-1; $return = ''; for($i = 0;$i<$retLen;$i++) { $return .= $possible[mt_rand(0,$posLen)]; } return $return; } function checkHash($a) { $pattern = '/^\w{10}$/'; return (preg_match($pattern, $a, $matches)===1)?true:false; }
The controller is where most of the magic happens. The index function allows for a “parent” parameter. This is because I allow each “paste” to have a parent, so there can be a type of hierachy in the posts and replies if I wanted. This method loads a view and gives it to variables “title” and “parent”. The title is required for my view files since all view files use the $title variable and will throw a warning if it’s not included.
public function index($parent = 0) { if(!is_numeric($parent)) { $parent = 0; } $this->view->load('default', array( 'title' => 'PHP Paster - Paste', 'parent' => $parent )); return; }
The view function requires a $url parameter which is the unique string created for each “paste” we can look it up based on this. It’s a little prettier and safer than giving users the primary key. This method calls a helper “hashHelper” which I posted earlier. If we received a valid hash we retrieve it from the pasteMaster model. The “viewRaw” is a duplicate of “view” but sends the data to a different view that has a header of text/plain so no formatting will be done.
public function view($url) { $this->helper->load('hashHelper'); $pasteId = 0; $pasteURL = $pasteDate = $pasteData = $pasteParent = ''; if(checkHash($url)) { $this->model->load('pasteMaster'); $result = $this->model->pasteMaster->getPaste($url); if($this->model->pasteMaster->rowCount($result) == 1) { $row = $this->model->pasteMaster->fetchObject($result); $pasteId = $row->pasteId; $pasteURL = $row->pasteURL; $pasteDate = $row->pasteDate; $pasteData = $row->pasteData; $pasteParent = $row->pasteParent; } } $this->view->load('view', array( 'title' => 'PHP Paster - View', 'pasteId' => $pasteId, 'pasteURL' => $pasteURL, 'pasteDate' => $pasteDate, 'pasteData' => $pasteData, 'pasteParent' => $pasteParent )); return; }
The insert automatically loads a model and a helper since we know it will always use the model. We check a little of the input, then make sure to generate a unique hash, then insert into the database using the model.
public function insert() { $this->model->load('pasteMaster'); $this->helper->load('hashHelper'); // Variables $count = 1; $pasteData = htmlentities($_POST['post'], ENT_QUOTES); if(isset($_POST['parent'])) { $pasteParent = $_POST['parent']; } else { $pasteParent = 0; } // Variable Checks if(!is_numeric($pasteParent)) { $pasteParent = 0; } // Data too small? if(strlen($pasteData) == 0) { $newURL = $this->config['application']['baseURL'] . '/index/'; header("Location: {$newURL}"); return; } // Data too large? // Find unqiue hash while($count !== 0) { $pasteURL = generateHash(); $result = $this->model->pasteMaster->getPaste($pasteURL); $count = $this->model->pasteMaster->rowCount($result); } // Insert and redirect $this->model->pasteMaster->insertPaste($pasteURL, $pasteData, $pasteParent); $newURL = $this->config['application']['baseURL'] . '/view/' . $pasteURL . '/'; header("Location: {$newURL}"); return; }
Thank you for taking the time to read this example. I hope you enjoy version 2.0 of this framework!