自己手写一个简易的MVC框架

130 阅读1分钟

#自己手写一个简易的MVC框架 mvc结构分为: m(model) - v(view) - c(controller). 其中m和v可用第三方包实现,而c这需要自己实现(原因: c是业务逻辑实现区,充满了不确定性).

m用到的第三方库为: catfan/medoo
v用到的第三方库为: league/plates

具体实现步骤步骤

  1. 创建一个项目目录testFrame在此目录下分别创建applicationcore目录

  2. 安装第三方包

    1. 安装catfan/medoo: composer require catfan/medoo 安装catfan-medoo
    2. 安装league/plates: composer require league/plates 安装league-plates
    3. 最终目录结构 最终目录结构
  3. 在core目录中新建Model和View脚本并在其中导入第三方包

    1. Model.php的代码:
    <?php
    namespace core;
    use Medoo\Medoo;
    class Model extends Medoo
    {
         public function __construct(array $options) 
         { 
             parent::__construct($options); 
         }
    }
    
    1. View.php的代码:
    <?php
    namespace core;
    use League\Plates\Engine;
    class View extends Engine
    {
        public function __construct($directory = null, $fileExtension = 'php') { parent::__construct($directory, $fileExtension); }
    }
    

    3.最终目录 引入第三方包

  4. application目录下创建三个目录,分别是models, views, controllers

    1. models目录下新建StaffsModel.php,获取员工表的数据.
    2. views目录下新建staffs目录,创建显示员工数据的视图list.php(html).
    3. controllers目录下创建StaffsController.php,把员工数据(StaffsModel)插入到视图(StaffsView)中.

    具体代码:

    StaffsController.php

        <?php
    
          namespace controllers;
          
          use Closure;
          
          // 服务容器
          class Container
          {
          protected $instanles;
          
              // 插入外部依赖
              public function bind($alias, Closure $process)
              {
                  $this->instanles[$alias] = $process;
              }
          
              // 取出外部依赖
              public function make($alias, $params = []):object
              {
                  return call_user_func_array($this->instanles[$alias], $params);
              }
          }
          
          // 门面
          class Facade
          {
          protected static $container = null;
          
              // 构造函数,初始化$container
              public static function initialize(Container $container)
              {
                  static::$container = $container;
              }
          }
          
          // 静态化模型类
          class StaticStaffModel extends Facade
          {
          public static function select($tablename, $field, $condition)
          {
          return static::$container->make('model')->select($tablename, $field, $condition);
          }
          }
          
          // 静态化视图类
          class StaticStaffView extends Facade
          {
          public static function fetch($path, $data)
          {
          return static::$container->make('view')->render($path, ['staffs' => $data]);
          }
          }
          
          // 控制器
          class StaffController
          {
          public function __construct(Container $container)
          {
          Facade::initialize($container);
          }
          
              public function index($tablename, $field, $condition, $path)
              {
                  $data = StaticStaffModel::select($tablename, $field, $condition);
                  return StaticStaffView::fetch($path, $data);
              }
          }
    

    StaffsModel.php

    <?php
         namespace models;
         
         use testFrame\core\Model;
         
         class StaffModel extends Model
         {
         public function __construct(array $options)
         {
         parent::__construct($options);
         }
    }
    

    staffs/list.php

       <!DOCTYPE html>
       <html lang="en">
       	<head>
       		<meta charset="UTF-8">
       		<meta name="viewport" content="width=device-width, initial-scale=1.0">
       		<title>员工信息</title>
       		<style>
       			body {
       				display: flex;
       				flex-direction: column;
       				align-items: center;
       			}
       			table {
       				border-collapse: collapse;
       				border: 1px solid;
       				width: 50%;
       				text-align: center;
       			}
       			th,
       			td {
       				border: 1px solid;
       				padding: 5px;
       			}
       			tr:first-child {
       				background-color: #eee;
       			}
       		</style>
       	</head>
       	<body>
       		<h3>用户管理系统</h3>
       		<table>
       			<tr>
       				<th>id</th>
       				<th>姓名</th>
       				<th>性别</th>
       				<th>工资</th>
       				<th>邮箱</th>
       				<th>操作</th>
       			</tr>
       			<?php foreach ($staffs as $staff): ?>
       				<tr>
       					<td><?= $this->e($staff['sid']) ?></td>
       					<td><?= $this->e($staff['name']) ?></td>
       					<td><?= $this->e($staff['gender']) == 'male' ? '男' : '女' ?></td>
       					<td><?= $this->e($staff['salary']) ?></td>
       					<td><?= $this->e($staff['email']) ?></td>
       					<td>
       						<button>编辑</button>
       						<button>删除</button>
       					</td>
       				</tr>
       			<?php endforeach ?>
       		</table>
       		<p>
       			<a href="">1</a>
       			<a href="">2</a>
       			<a href="">3</a>
       			<a href="">4</a>
       			<a href="">5</a>
       			<a href="">6</a>
       		</p>
       	</body>
       </html>
    
5. 在`composer.json`中添加*autoload*,然后在控制台执行`composer dump`.注意,控制台路径要在当前目录下.
```json5
{
    "name": "zhang/null",
    "description": "this is a test",
    "require": {
        "catfan/medoo": "^1.7",
        "league/plates": "^3.4"
    },
    "autoload": {
        "classmap": [
            "application/controllers",
            "application/models",
            "application/views",
            "core"
        ]
    }
}

  1. 测试,在根目录下创建一个index.php进行测试,具体代码如下:
<?php

use testFrame\core\View;

use models\StaffModel;

use controllers\Container;
use controllers\StaffController;

require_once './vendor/autoload.php';


$container = new Container();
$container->bind('view', function () { return new View('application/views'); });
$container->bind(
    'model', function () {
    $config = [
        'database_type' => 'mysql',
        'database_name' => 'phpedu',
        'server'        => 'localhost',
        'username'      => 'admin',
        'password'      => '123456',
    ];
    return new StaffModel($config);
}
);

$controller = new StaffController($container);
echo $controller->index('staffs', ['sid', 'name', 'age', 'gender', 'salary', 'birthday'], ['LIMIT' => [20, 10]], 'staffs/list');

效果: 效果)