1 What is MVC
The MVC pattern (model-view-controller) is a software architecture model in software engineering, which divides the software system into three basic parts: model, view and controller.
The purpose of the MVC pattern is to implement a dynamic program design that simplifies the subsequent modification and expansion of the program, and makes it possible to reuse a part of the program. In addition, this mode makes the program structure more intuitive by simplifying the complexity. By separating the basic parts of the software system, it also gives the functions of each basic part.
Nutshell
The model model– manages all database-related logic. The model provides an abstraction layer for connecting and manipulating databases.
Controller controllers-Responsible for all business logic, such as if/else logic.
The view view– is responsible for the interface display, such as Hmtl/xml/json display.
PHP MVC Tutorial
2 Why you should develop your own MVC framework
There are a number of excellent MVC frameworks available on the Web, and this tutorial is not intended to develop a comprehensive, ultimate MVC framework solution, but to consider it a good opportunity to learn PHP from the inside, and in the process you will learn about object-oriented programming and MVC design patterns, and learn some of the considerations in development.
More importantly, you can take full control of your framework and incorporate your ideas into your development framework. Although not necessarily a good one, you can develop features and modules in your own way.
3 start to develop your own MVC framework
3.1 Directory Preparation
Before starting the development, let's set up the project first, assuming that the project we built for the TODO,MVC framework can be named Fastphp, then the first step is to set the directory structure first.
PHP MVC Simple Directory
Although all of the above directories are not used in this tutorial, it is necessary to set up the program directory at the outset in order to extend the program's extensibility. Here's what each directory is about:
application– Application code
config– program configuration or database configuration
fastphp-Framework Core Catalog
public– Static files
Runtime-Temp Data Directory
scripts– command-line tools
3.2 Code Specification
After the catalog has been set up, we're going to specify the code specification:
MySQL's table name should be lowercase, such as: Item,car
The module name (Models) needs to be capitalized, and a "Model" is added after the name, such as: Itemmodel,carmodel
The controller (Controllers) needs to be capitalized, and adds "controller" to the name, such as: Itemscontroller,carscontroller
View (views) The deployment structure is "controller name/behavior name", such as: item/view.php,car/buy.php
Some of the rules above are designed to make better calls to each other in the program. The next step is to start real PHP MVC programming.
3.3 Redirects
Redirect all data requests to the index.php file and create a new. htaccess file in the Todo directory with the following file contents:
Rewriteengine on # Make sure the request path is not a file name or directory Rewritecond%{request_filename}!-f rewritecond%{request_filename}!-d # REDIRECT all requests to IND Ex.php?url=pathname rewriterule ^ (. *) $ index.php?url=$1 [pt,l]
The main reasons for this are:
The program has a single entrance;
In addition to the static program, all other programs are redirected to index.php;
can be used to generate SEO-conducive URLs, want to better configure the URL, late may need URL routing, here do not introduce.
3.4 Entry File
Finish the above operation, you should know what we need to do, yes! In the public directory, add the index.php file with the following file contents:
The application directory is the current directory define (' App_path ', __dir__. ' /‘); Turn on Debug mode define (' App_debug ', true); Load frame require './fastphp/fastphp.php ';
Note that the PHP code above does not add the PHP end symbol "?>", so the main reason for this is that for files with only PHP code, the end flag ("?>") best not exist, PHP itself does not need to end the symbol, Not adding a closing symbol can largely prevent the end from being added with additional injected content, making the program more secure.
3.5 Configuration files and master requests
In index.php, we made a request to fastphp.php under the fastphp folder, so what exactly does fastphp.php this boot file contain?
Initialize the constant defined (' root ') or define (' root ', __dir__. /‘);
Defined (' App_path ') or define (' App_path ', dirname ($_server[' script_filename ']). ' /‘);
Defined (' App_debug ') or define (' App_debug ', false);
Defined (' Config_path ') or define (' Config_path ', App_path. ') config/');
Defined (' Runtime_path ') or define (' Runtime_path ', App_path. ') runtime/'); class file extension Const EXT = '. class.php '; Contains the configuration file require App_path. ' config/config.php '; Contains the core framework class require ROOT. ' core.php '; Instantiate the core class $fast = new Fast;
$fast->run ();
The above files can actually be directly included in the index.php file, constants can also be directly defined in the index.php, we do so for the later management and expansion of the more convenient, so the need to load the run at the beginning of the program is unified into a separate file reference.
First look at the config file under config. php file, the main role of the file is to set some program configuration items and database connection, the main content is:
/** variable configuration **/define (' db_name ', ' todo ');
Define (' Db_user ', ' root ');
Define (' Db_password ', ' root ');
Define (' db_host ', ' localhost ');
It should be said that config.php involved in a few things, but some basic database settings, and then see fastphp under the Common framework portal file core.php should be how to write.
/**
* fastphp Core Framework
*/class Fast {//Run program function run () {
Spl_autoload_register (Array ($this, ' loadclass ')); $this->setreporting (); $this->removemagicquotes (); $this->unregisterglobals (); $this->callhook ();
}//Master request method, the main purpose is to split the URL request function Callhook () {if (!empty ($_get[' url ')) {
$url = $_get[' url '];
$urlArray = Explode ("/", $url); Get controller name $controllerName = Ucfirst (Empty ($urlArray [0])? ' Index ': $urlArray [0]);
$controller = $controllerName. ' Controller '; Gets the action name Array_shift ($urlArray);
$action = Empty ($urlArray [0])? ' Index ': $urlArray [0]; Gets the URL parameter array_shift ($urlArray);
$queryString = Empty ($urlArray)? Array (): $urlArray;
}//data is empty processing $action = Empty ($action)? ' Index ': $action;
$queryString = Empty ($queryString)? Array (): $queryString; Instantiate controller $int = new $controller ($controllerName, $action); If the controller exists and the action is present, this invokes and passes in the URL parameter if ((int) method_exists ($controller, $action)) {
Call_user_func_array (Array ($int, $action), $queryString);
} else {exit ($controller. "Controller does not exist");
}
}//Detect development environment function setreporting () {if (App_debug = = True) {
Error_reporting (E_all);
Ini_set (' display_errors ', ' on ');
} else {
Error_reporting (E_all);
Ini_set (' display_errors ', ' Off ');
Ini_set (' log_errors ', ' on ');
Ini_set (' Error_log ', Runtime_path. ' Logs/error.log ');
}
}//Delete sensitive character function stripslashesdeep ($value) {
$value = Is_array ($value)? Array_map (' Stripslashesdeep ', $value): Stripslashes ($value); return $value;
}//detects sensitive characters and removes function removemagicquotes () {if (GET_MAGIC_QUOTES_GPC ()) {
$_get = Stripslashesdeep ($_get);
$_post = Stripslashesdeep ($_post);
$_cookie = Stripslashesdeep ($_cookie);
$_session = Stripslashesdeep ($_session);
}
}//detects the custom global variable (register globals) and removes function unregisterglobals () {if (Ini_get (' register_globals ')) {
$array = Array (' _session ', ' _post ', ' _get ', ' _cookie ', ' _request ', ' _server ', ' _env ', ' _files '); foreach ($array as $value) {foreach ($GLOBALS [$value] as $key = + $var) {if ($var = = = $GLOBALS [$key]) {unset ($GLOBALS [$key]);
}
}
}
}
}//Auto load Controller and model class static function LoadClass ($class) {
$frameworks = ROOT. $class. EXT;
$controllers = App_path. ' application/controllers/'. $class. EXT;
$models = App_path. ' application/models/'. $class. EXT; if (file_exists ($frameworks)) {//Load frame core class include $frameworks;
} elseif (File_exists ($controllers)) {//Load the application controller class include $controllers;
} elseif (File_exists ($models)) {//Load Application model class include $models;
} else {/* error code */}
}
}
The following focuses on the main request method Callhook (), first we want to see our URL will be like this:
Yoursite.com/controllername/actionname/querystring
The function of Callhook () is to get the URL from the global variable $_get[' URL ' variable and split it into three parts: $controller, $action, and $queryString.
For example, the URL link is: Todo.com/item/view/1/first-item, then
$controller is: Items
$action is: view
Query string: Array (1, First-item)
When the partition is complete, a new controller is instantiated: $controller. ' Controller ' (where ".") is a hyphen) and calls its method $action.
3.6 Controller/controller base class
The next step is to build the base classes required for the program in fastphp, including the base classes for controllers, models, and views.
The new Controller base class is Controller.class.php, the main function of the controller is the total scheduling, the specific content is as follows:
/**
* Controller base class
*/class Controller {protected $_controller; protected $_action; protected $_view;//constructors, initialize properties, and instantiate corresponding model function __cons Truct ($controller, $action) {$this->_controller = $controller; $this->_action = $action; $this->_view = new View ($controller, $action);
} function set ($name, $value) {$this->_view->set ($name, $value);
} function __destruct () {$this->_view->render ();
}
}
The Controller class implements communication for all controllers, models, and Views (view classes). When the destructor is executed, we can call render () to display the view file.
3.7 Model base class
The new model base class is Model.class.php, and the model base class Model.class.php code is as follows:
Class Model extends Sql {protected $_model; protected $_table; function __construct () {//Connect to Database $this->connect (db_hos T,db_user,db_password,db_name); Convert model +model to model name//Gets the name of the class to which the object belongs $this->_model = Get_class ($this); $this->_model = RTrim ($this->_model, ' model '); The database table name is consistent with the class name $this->_table = strtolower ($this->_model);
} function __destruct () {
}
}
Considering that the model needs to process the database, a separate database base class Sql.class.php is created, and the model base class inherits Sql.class.php, the code is as follows:
Class Sql {protected $_dbhandle; protected $_result;/** Connect database **/function connect ($address, $account, $pwd, $name) {$t His->_dbhandle = @mysql_connect ($address, $account, $pwd); if ($this->_dbhandle! = 0) {if (mysql_select_db ($name, $this->_dbhandle)) {return 1;
} else {return 0;
}
} else {return 0;
}
}/** disconnects from the database **/function disconnect () {if (@mysql_close ($this->_dbhandle)! = 0) {return 1;
} else {return 0;
}
}/** queries all **/function SelectAll () {
$query = ' select * from '. $this->_table. ' ' return $this->query ($query);
/** Query **/function Select ($id) based on condition (ID) {
$query = ' select * from '. $this->_table. ' ' WHERE ' id ' = \ '. mysql_real_escape_string ($id). ' \‘‘; return $this->query ($query, 1);
}/** Delete the **/function Delete ($id) based on the condition (ID) {
$query = ' Delete from '. $this->_table. ' ' WHERE ' id ' = \ '. mysql_real_escape_string ($id). ' \‘‘; return $this->query ($query);
}/** custom SQL query **/function query ($query, $singleResult = 0) {$this->_result = mysql_query ($query, $this->_dbhandle ); if (Preg_match ("/select/i", $query)) {
$result = Array ();
$table = Array ();
$field = Array ();
$tempResults = Array ();
$numOfFields = Mysql_num_fields ($this->_result); for ($i = 0; $i < $numOfFields; + + $i) {Array_push ($table, mysql_field_table ($this->_result, $i));
Array_push ($field, Mysql_field_name ($this->_result, $i));
{$row = mysql_fetch_row ($this->_result)) {for ($i = 0; $i < $numOfFields; + + $i) {$table [$i] = Ucfirst ($tabl e[$i]); $tempResults [$table [$i]][$field [$i]] = $row [$i]; } if ($singleResult = = 1) {mysql_free_result ($this->_result); return $tempResults;
}
Array_push ($result, $tempResults);
}
Mysql_free_result ($this->_result); return ($result);
}
}/** gets the number of records **/function Getnumrows () {return mysql_num_rows ($this->_result);
/** Free Query Resource **/function Freeresult () {
Mysql_free_result ($this->_result);
}/** get error message **/function GetError () {return mysql_error ($this->_dbhandle);
}
}
It should be said that Sql.class.php is a core part of the framework. Why? Because of this, we created a SQL abstraction layer, which greatly reduces the programming of the database. The Connect () and disconnect () methods are relatively simple and do not explain more, focusing on query queries. Suppose we have the following SQL query statement:
SELECT table1.field1, Table1.field2, Table2.field3, table2.field4 from Table1,table2 WHERE ...
If you use the SQL base class above, the first thing to do is to select the fields to output and the corresponding data tables, and then put them in the array, where $field and $table use the same index values. In the example above, they are:
$field = Array (FIELD1,FIELD2,FIELD3,FIELD4);
$table = Array (table1,table1,table2,table2);
The script expands all the rows of data and transforms the data table into a model name (such as removing complex numbers and first letter capitalization). The result of the query is finally saved in a multidimensional array and then returned in a format similar to: $var [' modelname '] [' fieldName ']. This way, the output can be very easy to use in the view.
3.8 Views View class
The View.class.php contents of the view class are as follows:
/**
* Depending on the EOG class
*/class View {protected $variables = array (); protected $_controller; protected $_action; function __construct ($controll Er, $action) {$this->_controller = $controller; $this->_action = $action;
}/** Set Variable method **/function set ($name, $value) {$this->variables[$name] = $value;
}/** displays **/function render () {
Extract ($this->variables);
$defaultHeader = App_path. ' application/views/header.php ';
$defaultFooter = App_path. ' application/views/footer.php ';
$controllerHeader = App_path. ' application/views/'. $this->_controller. '/header.php ';
$controllerFooter = App_path. ' application/views/'. $this->_controller. '/footer.php '; Page header file if (file_exists ($controllerHeader)) {include ($controllerHeader);
} else {include ($defaultHeader);
}//page content file include (App_path. ' application/views/'. $this->_controller. ‘/‘ . $this->_action. '. php '); Footer file if (file_exists ($controllerFooter)) {include ($controllerFooter);
} else {include ($defaultFooter);
}
}
}
So our core PHP MVC framework is written, and here we start writing apps to test the framework functionality.
4 applications
4.1 Database Deployment
Create a new TODO database in SQL and use the following statement to increase the item data table and insert 2 records:
CREATE TABLE ' Items ' (
' id ' int (one) not NULL auto_increment,
' Item_name ' varchar (255) is not NULL,
PRIMARY KEY (' id ')
); INSERT into ' Items ' VALUES (1, ' Hello World '); INSERT into ' Items ' VALUES (2, ' Lets go! ');
4.2 Deployment of models
Then we also need to create a itemmodel.php model in the models directory, with the following content:
Class Itemmodel extends Model {/** new data **/function Add ($value) {
$query = ' insert INTO '. $this->_table. ' ' (item_name) VALUES (\ ". mysql_real_escape_string ($value). ' \‘)‘; return $this->query ($query);
}/** new data **/function Update ($id, $value) {
$query = ' Update '. $this->_table. ' ' Set item_name = \ '. mysql_real_escape_string ($value). ' \ ' where ' id ' = \ '. mysql_real_escape_string ($id). ' \‘‘; return $this->query ($query);
}
}
The model content is empty. Because the Item model inherits models, it has all the features of model.
4.3 Deployment of the Controller
Create a itemscontroller.php controller in the Controllers directory with the following contents:
Class Itemcontroller extends Controller {//Home method, test framework custom DB Query function index () {
$item = new Itemmodel; $this->set (' title ', ' all entries '); $this->set (' Todo ', $item->query (' SELECT * from item '));
}//Add record, test framework DB record creation (create) function add () {
$value = $_post[' value '];
$item = new Itemmodel; $this->set (' title ', ' Add success '); $this->set (' Todo ', $item->add ($value));
}//view record, test framework DB record read (read) function view ($id = null, $name = null) {
$item = new Itemmodel; $this->set (' title ', ' viewing '. $name); $this->set (' Todo ', $item->select ($id));
}//update record, test framework DB Record update (updated) function update () {
$id = $_post[' id '];
$value = $_post[' value '];
$item = new Itemmodel; $this->set (' title ', ' modified success '); $this->set (' Todo ', $item->update ($id, $value));
}//delete record, test framework DB record Delete (delete) function Delete ($id = null) {
$item = new Itemmodel; $this->set (' title ', ' delete succeeded '); $this->set (' Todo ', $item->delete ($id));
}
}
4.4 View of the deployment
Create a new header.php and footer.php two header footer templates in the Views directory, as follows.
header.php, Content:
Hand-writing your own PHPMVC Framework Example tutorial