php Source Building Blog 4--Implementing MVC Architecture Mini-Framework

Posted by jeremy_brooks on Sat, 18 May 2019 05:54:25 +0200

Mainly:

  1. Constant optimization path
  2. Automatic loading class
  3. Optimizing entry files
  4. Secure Access Project Directory
File structure: -----------------------------------------------------------------------------------------------------------------------------------------------------
blog
├─App
_-Model Model
UserModel.class.php User Model Class
-View View
-Back Backstage
│  │  │  └─Index
Background Home Page of index.html
Home Front Desk
User View Directory
Login form page
-Controller Controller
-Back Backstage
IndexController.class.php Background Home Controller
Home Front Desk
User Controller. class. PHP User Controller
-Public Static Public Files (js,css,images)
-Plugins plug-in
-layui front-end framework plug-in
-Back Backstage
-js/js file
-css/css style file
image img pictures
Home Front Desk
-js/js file
-css/css style file
image img pictures
-Frame public-use classes
-BaseModel.class.php database connection class
- BaseController.class.php Controller Common Operations (Setting Code, Information Jump)
_-FactoryModel.class.php Model Factory Class
-Init.class.php Initializes application classes
- MySQLDB.class.php database operation tool class
-index.php entry file -----------------------------------------------------------------

In the previous article, four problems are put forward to be solved. This article focuses on solving these four problems, and finally forms a complete framework of micro MVC. Follow-up blog projects, or other projects, can directly use the framework for development and learning.

Download and view the source code of the project: https://gitee.com/NewbiesYang/young_blog

Constant optimization path

Prepare: Create Branches

1 $ git checkout master
2 $ git checkout -b "MVC"

Thinking

1) Define common directory paths as constants. For example, model directory, controller directory, etc.
2) Introducing classes to use defined constants instead of partial paths. For example, include FRAME.BaseModel.class.php
3) Load views use constants instead of partial paths such as include VIEW.'login.html'in simple form

Code implementation

1) Operational steps

step 1: Define the required constants in the entry file

step 2: When introducing views into the controller, use constants to optimize 
Operational Steps and Thoughts

2) Define common path constants in the entry file [index.php]

 1 <?php
 2 /**
 3  * Entry file
 4  */
 5 $p = !empty($_GET['p']) ? $_GET['p'] : 'Home';  //platform
 6 $c = !empty($_GET['c']) ? $_GET['c'] : 'User';  //Controller
 7 $a = !empty($_GET['a']) ? $_GET['a'] : 'login'; //action
 8 
 9 define('PLAT', $p);  //Platform constants
10 define('CTR', $c);  //Controller
11 define('ACTION', $a); //action
12 
13 
14 define('DS', DIRECTORY_SEPARATOR); //Catalog splitter
15 define('ROOT', getcwd().DS);  //Current directory project directory
16 define('FRAME', ROOT.'Frame'.DS);
17 define('APP', ROOT.'App'.DS);
18 define('PUB', ROOT.'Public'.DS);
19 define('ADMIN', PUB.'Admin'.DS);
20 define('HOME', PUB.'Home'.DS);
21 
22 //MVC Catalog
23 define('MODEL', APP.'Model'.DS);
24 define('VIEW', APP.'View'.DS.PLAT.DS.CTR.DS);
25 define('CTRONLLER', APP.'Controller'.DS.PLAT.DS);
26 
27 $ctr = $c."Controller";
28 
29 require_once FRAME.'Db.class.php';  //Database Operations Class
30 require_once FRAME.'BaseModel.class.php';  //Basic Model Class
31 require_once MODEL.'UserModel.class.php';  //User Model Class
32 require_once FRAME.'FactoryModel.class.php';//Model factory class
33 require_once FRAME.'BaseController.class.php'; //Basic controller class
34 require_once CTRONLLER.$ctr.'.class.php';
35 
36 
37 //Instance Controller
38 $userCtr = new $ctr();
39 
40 $userCtr -> $a();

2) The use of constants:

Background Home Controller [App/Controller/Admin/IndexController.class.php]

 1 <?php
 2 /**
 3  * IndexController Controller class
 4  * Background related operations
 5  * User: young
 6  */
 7 
 8 class IndexController extends BaseController
 9 {
10     //Show Backstage Home Page
11     public function index()
12     {
13         include VIEW.'index.html';
14     }
15 }
Background Home Page Controller Introduces View Path Modification

User Controller Logon View Introducing Path [App/Controller/Home/UserController.class.php]

 1 <?php
 2 /**
 3  * UserController.class.php User Controller
 4  */
 5 
 6 class UserController  extends  BaseController{
 7     /**
 8      * Show the login interface
 9      * @access public
10      */
11     public function login()
12     {
13         include VIEW."login.html";
14     }
15 . . . 
16 . . . 
17 . . . 
User Controller Logon View Introducing Path

3) Submit code

$  git add -A
$  git commit -m "Constant usage"

Automatic loading class

Thoughts

Question: Requ_once has introduced six classes into the entry file, adding one that needs to be introduced. It is easy to omit, repeat and make mistakes.

Solution: Automatic loading of class files

Mode 1: Autoloading can be achieved by using the autoloading class function _autoload().
Mode 2: In the actual project, many people develop, according to practicability, more use sql_autoload_register() registration function to load automatically.

Automatic loading according to the characteristics of directory
Model class file features, class name substr($className,-5) ending with Model
Controller file features: class name ending with Controller, substr($class,-10)

Common Class: There is no uniform form for class names. You can put common classes under Fame into arrays, and then determine whether classes are in arrays, thus automatically loading class files under that directory.

Code implementation

1) Automatic loading of entry file implementation classes

 1 <?php
 2 /**
 3  * Entry file
 4  */
 5 $p = !empty($_GET['p']) ? $_GET['p'] : 'Home';  //platform
 6 $c = !empty($_GET['c']) ? $_GET['c'] : 'User';  //Controller
 7 $a = !empty($_GET['a']) ? $_GET['a'] : 'login'; //action
 8 
 9 define('PLAT', $p);  //Platform constants
10 define('CTR', $c);  //Controller
11 define('ACTION', $a); //action
12 
13 
14 define('DS', DIRECTORY_SEPARATOR); //Catalog splitter
15 define('ROOT', getcwd().DS);  //Current directory project directory
16 define('FRAME', ROOT.'Frame'.DS);
17 define('APP', ROOT.'App'.DS);
18 define('PUB', ROOT.'Public'.DS);
19 define('ADMIN', PUB.'Admin'.DS);
20 define('HOME', PUB.'Home'.DS);
21 
22 //MVC Catalog
23 define('MODEL', APP.'Model'.DS);
24 define('VIEW', APP.'View'.DS.PLAT.DS.CTR.DS);
25 define('CTRONLLER', APP.'Controller'.DS.PLAT.DS);
26 
27 $ctr = $c."Controller";
28 
29 spl_autoload_register('autoload'); //Register autoload function
30 //Automatic loading class
31 /**
32  * Real Auto Loading Class Files
33  * @param  string $className Class name
34  */
35 function autoload($className)
36 {
37     $upperClassName = strtoupper($className);
38     $frame = array('BaseController','BaseModel','Db','FactoryModel');
39     if(in_array($className, $frame)) {  //Loading public Frame Class files in directories
40         require_once FRAME."$className.class.php";
41     } elseif(substr($upperClassName, -5) == 'MODEL'){  //Loading model Model Class files in directories
42         require_once MODEL."$className.class.php";
43     } elseif(substr($upperClassName, -10) == 'CONTROLLER'){  //Load Class Files in Controller Directory
44         require_once CTRONLLER."$className.class.php";
45     }
46 }
47 
48 //Instance Controller
49 $userCtr = new $ctr();
50 $userCtr -> $a();

2) Submit code

1 $  git add -A
2 $  git commit -m "Automatic loading class completion"

Optimizing entry files

Thinking

Question: At this time, the entry file code fragmentation increases, with the increase of subsequent code, the entry file will become more bulky and complex, difficult to manage.

Solution: Encapsulating an operation in an entry file is called a class, so you only need to call the method of the class in the entry file.

Create Init.class.php class file and put it into Frame
Encapsulate all operations of the entry file into class methods
Load Class () Sets the autoload function
autoload() Autoload class
setConst() defines constants
dispatch() front-end distributor

Code implementation

Create Init.class.php file in the Frame directory and modify the code copy in the import file index to a class

  [Frame/Init.class.php]

 1 <?php
 2 /**
 3  * Application Initialization Operations Class
 4  * User: young
 5  */
 6 
 7 class Init
 8 {
 9     protected static $frame = array('BaseController','BaseModel','Db','FactoryModel'); //Frame Catalog Common Operations Class
10     public static function run()
11     {
12         //platform
13         self::dispatch();
14 
15         //Const
16         self::setConst();
17 
18         //Automatic loading class
19         self::loadClass();
20 
21         $ctr = CTR."Controller";  //Stitching Controller Name
22 
23         //Instance Controller
24         $ctrObj = new $ctr();
25         $a = ACTION;
26         $ctrObj -> $a();
27     }
28     /**
29      * Setting up automatic loading class method
30      */
31     private static function loadClass()
32     {
33         spl_autoload_register('self::autoload');
34     }
35 
36     /**
37      * Automatic Loading
38      * @param  string $className Class name
39      */
40     private static function autoload($className)
41     {
42         $upperClassName = strtoupper($className);
43         if(in_array($className, static::$frame)) {
44             require_once FRAME."$className.class.php";
45         } elseif(substr($upperClassName, -5) == 'MODEL'){
46             require_once MODEL."$className.class.php";
47         } elseif(substr($upperClassName, -10) == 'CONTROLLER'){
48             require_once CTRONLLER."$className.class.php";
49         }
50     }
51 
52     /**
53      * Const
54      */
55     private static function setConst()
56     {
57         define('DS', DIRECTORY_SEPARATOR); //Catalog splitter
58         define('ROOT', getcwd().DS);
59         define('FRAME', ROOT.'Frame'.DS);
60         define('APP', ROOT.'App'.DS);
61         define('PUB', ROOT.'Public'.DS);
62         define('ADMIN', PUB.'Admin'.DS);
63         define('HOME', PUB.'Home'.DS);
64 
65 
66         define('MODEL', APP.'Model'.DS);
67         define('VIEW', APP.'View'.DS.PLAT.DS.CTR.DS);
68         define('CTRONLLER', APP.'Controller'.DS.PLAT.DS);
69     }
70 
71     /**
72      * Get the GET value of p c a and set it to a constant
73      * @return void
74      */
75     private static function dispatch()
76     {
77         $p = !empty($_GET['p']) ? $_GET['p'] : 'Home';  //platform
78         $c = !empty($_GET['c']) ? $_GET['c'] : 'User';  //Controller
79         $a = !empty($_GET['a']) ? $_GET['a'] : 'login'; //action
80 
81         define('PLAT', $p);
82         define('CTR', $c);
83         define('ACTION', $a);
84     }
85 }

2) The entry file introduces the initialization class and calls its method [index.php]

1 <?php
2 /**
3  * Entry file
4  */
5 
6 require_once './Frame/Init.class.php';
7 Init::run();

3) Submit code

1 $  git add -A
2 $  git commit -m "Optimize entry files and encapsulate initialization classes"

Secure Access Project Directory

Thoughts

Question: At this point, all directories in the project can be accessed through browsers, such as direct access to Frame/Db.class.php files and direct access to view database login information, which is obviously unsafe.

Solutions:

Mode 1: Define constants at the beginning of accessible files. Access is to determine whether constants are defined(..) or exit('Access Deny') if no constants are defined.

Mode 2: Open the distributed permission configuration and write. htaccess file. If access is prohibited, place the file in the directory where access is prohibited.

Realization

1) In the form of mode 2 above, an item (already added when setting up the environment) has been added to the site configuration: See in detail: PHP Source Building Blog 1 - Environment Building

Site configuration in apache configuration file httpd-vhosts.conf

1  #Allow Distributed Permission Configuration (Allow Rewriting) (. htacess)
2   AllowOverride All

2) After restarting apache, write the. htaccess file, which contains:

deny from all

3) Place the. htaccess file in a directory that is not accessible. For example, App / Frame / directory. Just put it on the first layer, and the inner directory is automatically not allowed to access directly.

                               

4) Access testing

                   

Summary:

It mainly implements the introduction of path optimization, automatic loading of classes, encapsulation of optimized entry files, directory access restrictions.

The MVC micro-frame is basically completed. In fact, there are still many things that can be extended, such as

1. Class file naming uses the end of. class.php, which is essentially optimized for direct use of. PHP endings.

2. Introducing namespaces to load classes more easily

3. Errors occur in the project, which are displayed directly on the browser. You can write a log class and write errors to files or databases.

4. The database connection information is written directly in DB class and BaseModel, which is insecure. You can create a configuration directory, write this information to the configuration file, and then write a class that loads the configuration file.

5. This architecture directory is a platform in C and V, such as Controller/Home, Controller/Admin; it can also be written as MVC structure in platform, such as Admin/Controller, Admin/Model, Home/Controller,Home/View.

In fact, on-line projects, it is still recommended to use frameworks safely and quickly; self-simulated frameworks are suitable for learning, research and use, easy to omit, resulting in security risks, inconvenience in operation and other issues.

Next step: According to the front-end template of the blog, analyze and create data tables, start to build the background program of the blog, and then prepare to implement the "classification module" first. Classified display, modification, addition and deletion functions

Topics: PHP git Database Apache