PHP CRUD快速生成

wen PHP项目 4

本文目录导读:

PHP CRUD快速生成

  1. 通用CRUD类 (BaseCrud.php)
  2. 数据库连接类 (Database.php)
  3. CRUD生成器 (CrudGenerator.php)
  4. 使用示例

我来帮你创建一个PHP CRUD快速生成器,可以自动生成增删改查的代码。

通用CRUD类 (BaseCrud.php)

<?php
/**
 * 通用CRUD操作类
 * 自动生成增删改查功能
 */
class BaseCrud {
    private $conn;
    private $table;
    private $primaryKey = 'id';
    private $allowedFields = [];
    private $searchFields = [];
    private $uploadFields = [];
    public function __construct($connection, $table, $config = []) {
        $this->conn = $connection;
        $this->table = $table;
        if (isset($config['primaryKey'])) {
            $this->primaryKey = $config['primaryKey'];
        }
        if (isset($config['allowedFields'])) {
            $this->allowedFields = $config['allowedFields'];
        }
        if (isset($config['searchFields'])) {
            $this->searchFields = $config['searchFields'];
        }
        if (isset($config['uploadFields'])) {
            $this->uploadFields = $config['uploadFields'];
        }
        // 如果没有指定允许的字段,自动获取所有字段
        if (empty($this->allowedFields)) {
            $this->getTableFields();
        }
    }
    // 自动获取数据表字段
    private function getTableFields() {
        $sql = "SHOW COLUMNS FROM {$this->table}";
        $result = $this->conn->query($sql);
        while ($row = $result->fetch_assoc()) {
            $this->allowedFields[] = $row['Field'];
        }
    }
    // 创建记录
    public function create($data) {
        $filteredData = $this->filterFields($data);
        // 处理上传文件
        $filteredData = $this->handleUploads($filteredData);
        $columns = implode(', ', array_keys($filteredData));
        $placeholders = implode(', ', array_fill(0, count($filteredData), '?'));
        $types = $this->getDataTypes($filteredData);
        $values = array_values($filteredData);
        $sql = "INSERT INTO {$this->table} ($columns) VALUES ($placeholders)";
        $stmt = $this->conn->prepare($sql);
        $stmt->bind_param($types, ...$values);
        if ($stmt->execute()) {
            return $this->conn->insert_id;
        }
        return false;
    }
    // 读取记录(分页)
    public function read($id = null, $page = 1, $limit = 10, $search = '') {
        $offset = ($page - 1) * $limit;
        if ($id) {
            // 获取单条记录
            $sql = "SELECT * FROM {$this->table} WHERE {$this->primaryKey} = ?";
            $stmt = $this->conn->prepare($sql);
            $stmt->bind_param("i", $id);
            $stmt->execute();
            $result = $stmt->get_result();
            return $result->fetch_assoc();
        } else {
            // 获取列表
            $where = '';
            $params = [];
            $types = '';
            if ($search && !empty($this->searchFields)) {
                $searchConditions = [];
                foreach ($this->searchFields as $field) {
                    $searchConditions[] = "$field LIKE ?";
                    $params[] = "%$search%";
                    $types .= "s";
                }
                $where = " WHERE " . implode(" OR ", $searchConditions);
            }
            // 获取总数
            $countSql = "SELECT COUNT(*) as total FROM {$this->table}" . $where;
            $stmt = $this->conn->prepare($countSql);
            if (!empty($params)) {
                $stmt->bind_param($types, ...$params);
            }
            $stmt->execute();
            $total = $stmt->get_result()->fetch_assoc()['total'];
            // 获取数据
            $sql = "SELECT * FROM {$this->table}" . $where . " LIMIT ? OFFSET ?";
            if (!empty($params)) {
                $types .= "ii";
                $params[] = $limit;
                $params[] = $offset;
            } else {
                $types = "ii";
                $params = [$limit, $offset];
            }
            $stmt = $this->conn->prepare($sql);
            $stmt->bind_param($types, ...$params);
            $stmt->execute();
            $result = $stmt->get_result();
            $rows = $result->fetch_all(MYSQLI_ASSOC);
            return [
                'data' => $rows,
                'total' => $total,
                'page' => $page,
                'limit' => $limit,
                'total_pages' => ceil($total / $limit)
            ];
        }
    }
    // 更新记录
    public function update($id, $data) {
        $filteredData = $this->filterFields($data);
        $filteredData = $this->handleUploads($filteredData);
        $sets = [];
        $params = [];
        $types = '';
        foreach ($filteredData as $key => $value) {
            $sets[] = "$key = ?";
            $params[] = $value;
            $types .= $this->getFieldType($value);
        }
        // 添加ID
        $types .= "i";
        $params[] = $id;
        $sql = "UPDATE {$this->table} SET " . implode(', ', $sets) . " WHERE {$this->primaryKey} = ?";
        $stmt = $this->conn->prepare($sql);
        $stmt->bind_param($types, ...$params);
        return $stmt->execute();
    }
    // 删除记录
    public function delete($id) {
        $sql = "DELETE FROM {$this->table} WHERE {$this->primaryKey} = ?";
        $stmt = $this->conn->prepare($sql);
        $stmt->bind_param("i", $id);
        return $stmt->execute();
    }
    // 批量删除
    public function batchDelete($ids) {
        $placeholders = implode(',', array_fill(0, count($ids), '?'));
        $types = str_repeat('i', count($ids));
        $sql = "DELETE FROM {$this->table} WHERE {$this->primaryKey} IN ($placeholders)";
        $stmt = $this->conn->prepare($sql);
        $stmt->bind_param($types, ...$ids);
        return $stmt->execute();
    }
    // 过滤字段
    private function filterFields($data) {
        $filtered = [];
        foreach ($this->allowedFields as $field) {
            if (isset($data[$field])) {
                $filtered[$field] = $data[$field];
            }
        }
        return $filtered;
    }
    // 获取数据类型
    private function getDataTypes($data) {
        $types = '';
        foreach ($data as $value) {
            $types .= $this->getFieldType($value);
        }
        return $types;
    }
    // 判断字段类型
    private function getFieldType($value) {
        if (is_int($value)) return 'i';
        if (is_double($value)) return 'd';
        if (is_string($value)) return 's';
        return 's';
    }
    // 处理文件上传
    private function handleUploads($data) {
        $uploadDir = __DIR__ . '/../../uploads/';
        if (!is_dir($uploadDir)) {
            mkdir($uploadDir, 0777, true);
        }
        foreach ($this->uploadFields as $field) {
            if (isset($_FILES[$field]) && $_FILES[$field]['error'] === 0) {
                $file = $_FILES[$field];
                $filename = time() . '_' . basename($file['name']);
                $targetPath = $uploadDir . $filename;
                if (move_uploaded_file($file['tmp_name'], $targetPath)) {
                    $data[$field] = 'uploads/' . $filename;
                }
            }
        }
        return $data;
    }
}

数据库连接类 (Database.php)

<?php
/**
 * 数据库连接类(单例模式)
 */
class Database {
    private static $instance = null;
    private $conn;
    private function __construct($config) {
        $this->conn = new mysqli(
            $config['host'],
            $config['username'],
            $config['password'],
            $config['database'],
            $config['port'] ?? 3306
        );
        if ($this->conn->connect_error) {
            die("Connection failed: " . $this->conn->connect_error);
        }
        $this->conn->set_charset($config['charset'] ?? 'utf8mb4');
    }
    public static function getInstance($config = null) {
        if (self::$instance === null && $config) {
            self::$instance = new self($config);
        }
        return self::$instance;
    }
    public function getConnection() {
        return $this->conn;
    }
    public function close() {
        if ($this->conn) {
            $this->conn->close();
        }
    }
}

CRUD生成器 (CrudGenerator.php)

<?php
/**
 * CRUD代码生成器
 * 根据数据库表自动生成CRUD代码
 */
class CrudGenerator {
    private $conn;
    public function __construct($connection) {
        $this->conn = $connection;
    }
    // 获取所有表
    public function getTables() {
        $sql = "SHOW TABLES";
        $result = $this->conn->query($sql);
        $tables = [];
        while ($row = $result->fetch_row()) {
            $tables[] = $row[0];
        }
        return $tables;
    }
    // 获取表结构
    public function getTableStructure($table) {
        $sql = "SHOW COLUMNS FROM $table";
        $result = $this->conn->query($sql);
        $fields = [];
        while ($row = $result->fetch_assoc()) {
            $fields[] = [
                'name' => $row['Field'],
                'type' => $row['Type'],
                'null' => $row['Null'],
                'key' => $row['Key'],
                'default' => $row['Default'],
                'extra' => $row['Extra']
            ];
        }
        return $fields;
    }
    // 生成配置数组
    public function generateConfig($table) {
        $fields = $this->getTableStructure($table);
        $config = [
            'table' => $table,
            'primaryKey' => 'id',
            'allowedFields' => [],
            'searchFields' => [],
            'uploadFields' => []
        ];
        foreach ($fields as $field) {
            $config['allowedFields'][] = $field['name'];
            if ($field['key'] === 'PRI') {
                $config['primaryKey'] = $field['name'];
            }
            // 判断字段类型,选择搜索字段
            if (strpos($field['type'], 'varchar') !== false || 
                strpos($field['type'], 'text') !== false) {
                $config['searchFields'][] = $field['name'];
            }
            // 判断上传字段
            if (strpos($field['name'], 'image') !== false || 
                strpos($field['name'], 'picture') !== false ||
                strpos($field['name'], 'file') !== false) {
                $config['uploadFields'][] = $field['name'];
            }
        }
        return $config;
    }
    // 生成控制器文件
    public function generateController($table) {
        $config = $this->generateConfig($table);
        $className = $this->toCamelCase($table);
        $controllerName = $className . 'Controller';
        $code = "<?php\n";
        $code .= "/**\n";
        $code .= " * {$controllerName} - 自动生成\n";
        $code .= " */\n";
        $code .= "class {$controllerName} {\n";
        $code .= "    private \$crud;\n";
        $code .= "    \n";
        $code .= "    public function __construct(\$db) {\n";
        $code .= "        \$config = " . var_export($config, true) . ";\n";
        $code .= "        \$this->crud = new BaseCrud(\$db, '{$table}', \$config);\n";
        $code .= "    }\n";
        $code .= "    \n";
        $code .= "    // 创建记录\n";
        $code .= "    public function create(\$data) {\n";
        $code .= "        \$id = \$this->crud->create(\$data);\n";
        $code .= "        return ['success' => true, 'id' => \$id];\n";
        $code .= "    }\n";
        $code .= "    \n";
        $code .= "    // 读取记录\n";
        $code .= "    public function read(\$id = null, \$page = 1, \$limit = 10, \$search = '') {\n";
        $code .= "        return \$this->crud->read(\$id, \$page, \$limit, \$search);\n";
        $code .= "    }\n";
        $code .= "    \n";
        $code .= "    // 更新记录\n";
        $code .= "    public function update(\$id, \$data) {\n";
        $code .= "        return \$this->crud->update(\$id, \$data);\n";
        $code .= "    }\n";
        $code .= "    \n";
        $code .= "    // 删除记录\n";
        $code .= "    public function delete(\$id) {\n";
        $code .= "        return \$this->crud->delete(\$id);\n";
        $code .= "    }\n";
        $code .= "}\n";
        return $code;
    }
    // 生成前端页面
    public function generateView($table) {
        $fields = $this->getTableStructure($table);
        $config = $this->generateConfig($table);
        $html = "<!DOCTYPE html>\n";
        $html .= "<html lang='zh-CN'>\n";
        $html .= "<head>\n";
        $html .= "    <meta charset='UTF-8'>\n";
        $html .= "    <title>{$table}管理</title>\n";
        $html .= "    <link href='https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css' rel='stylesheet'>\n";
        $html .= "</head>\n";
        $html .= "<body>\n";
        $html .= "    <div class='container mt-4'>\n";
        $html .= "        <h2>{$table}管理</h2>\n";
        // 搜索表单
        $html .= "        <div class='row mb-3'>\n";
        $html .= "            <div class='col-md-6'>\n";
        $html .= "                <form class='d-flex' method='GET'>\n";
        $html .= "                    <input type='text' name='search' class='form-control me-2' placeholder='搜索...'>\n";
        $html .= "                    <button type='submit' class='btn btn-primary'>搜索</button>\n";
        $html .= "                </form>\n";
        $html .= "            </div>\n";
        $html .= "            <div class='col-md-6 text-end'>\n";
        $html .= "                <button class='btn btn-success' onclick='showAddModal()'>添加记录</button>\n";
        $html .= "            </div>\n";
        $html .= "        </div>\n";
        // 数据表格
        $html .= "        <table class='table table-striped'>\n";
        $html .= "            <thead>\n";
        $html .= "                <tr>\n";
        foreach ($fields as $field) {
            $html .= "                    <th>{$field['name']}</th>\n";
        }
        $html .= "                    <th>操作</th>\n";
        $html .= "                </tr>\n";
        $html .= "            </thead>\n";
        $html .= "            <tbody id='dataTable'>\n";
        $html .= "            </tbody>\n";
        $html .= "        </table>\n";
        // 分页
        $html .= "        <nav>\n";
        $html .= "            <ul class='pagination' id='pagination'>\n";
        $html .= "            </ul>\n";
        $html .= "        </nav>\n";
        // 添加/编辑模态框
        $html .= "        <div class='modal' id='editModal'>\n";
        $html .= "            <div class='modal-dialog'>\n";
        $html .= "                <div class='modal-content'>\n";
        $html .= "                    <div class='modal-header'>\n";
        $html .= "                        <h5 class='modal-title' id='modalTitle'>添加记录</h5>\n";
        $html .= "                        <button type='button' class='btn-close' data-bs-dismiss='modal'></button>\n";
        $html .= "                    </div>\n";
        $html .= "                    <div class='modal-body'>\n";
        $html .= "                        <form id='editForm'>\n";
        foreach ($fields as $field) {
            if ($field['key'] === 'PRI' || $field['extra'] === 'auto_increment') continue;
            $html .= "                            <div class='mb-3'>\n";
            $html .= "                                <label class='form-label'>{$field['name']}</label>\n";
            if (strpos($field['type'], 'text') !== false && strpos($field['type'], 'int') === false) {
                $html .= "                                <textarea class='form-control' name='{$field['name']}'></textarea>\n";
            } else {
                $html .= "                                <input class='form-control' name='{$field['name']}' type='text'>\n";
            }
            $html .= "                            </div>\n";
        }
        $html .= "                            <button type='submit' class='btn btn-primary'>保存</button>\n";
        $html .= "                        </form>\n";
        $html .= "                    </div>\n";
        $html .= "                </div>\n";
        $html .= "            </div>\n";
        $html .= "        </div>\n";
        $html .= "    </div>\n";
        // JavaScript代码
        $html .= "    <script src='https://code.jquery.com/jquery-3.6.0.min.js'></script>\n";
        $html .= "    <script src='https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js'></script>\n";
        $html .= "    <script>\n";
        $html .= "        let currentId = null;\n";
        $html .= "        \n";
        $html .= "        function loadData(page = 1) {\n";
        $html .= "            let search = $('input[name=search]').val() || '';\n";
        $html .= "            $.get('api.php?action=list&page='+page+'&search='+search, function(response) {\n";
        $html .= "                if (response.success) {\n";
        $html .= "                    renderTable(response.data.data);\n";
        $html .= "                    renderPagination(response.data);\n";
        $html .= "                }\n";
        $html .= "            });\n";
        $html .= "        }\n";
        $html .= "        \n";
        $html .= "        function renderTable(data) {\n";
        $html .= "            let html = '';\n";
        $html .= "            data.forEach(function(row) {\n";
        $html .= "                html += '<tr>';\n";
        foreach ($fields as $field) {
            $html .= "                html += '<td>'+row.{$field['name']}+'</td>';\n";
        }
        $html .= "                html += '<td>';\n";
        $html .= "                html += '<button class=\"btn btn-sm btn-primary\" onclick=\"editRecord('+\"" . "'" . "'"+'+row.{$config['primaryKey']}+')">编辑</button> ';\n";
        $html .= "                html += '<button class=\"btn btn-sm btn-danger\" onclick=\"deleteRecord('+\"" . "'" . "'"+'+row.{$config['primaryKey']}+')">删除</button>';\n";
        $html .= "                html += '</td>';\n";
        $html .= "                html += '</tr>';\n";
        $html .= "            });\n";
        $html .= "            $('#dataTable').html(html);\n";
        $html .= "        }\n";
        $html .= "        \n";
        $html .= "        function renderPagination(data) {\n";
        $html .= "            let html = '';\n";
        $html .= "            for (let i = 1; i <= data.total_pages; i++) {\n";
        $html .= "                html += '<li class=\"page-item' + (i === data.page ? ' active' : '') + '\">';\n";
        $html .= "                html += '<a class=\"page-link\" href=\"javascript:void(0)\" onclick=\"loadData('+i+')\">'+i+'</a>';\n";
        $html .= "                html += '</li>';\n";
        $html .= "            }\n";
        $html .= "            $('#pagination').html(html);\n";
        $html .= "        }\n";
        $html .= "        \n";
        $html .= "        function showAddModal() {\n";
        $html .= "            currentId = null;\n";
        $html .= "            $('#modalTitle').text('添加记录');\n";
        $html .= "            $('#editForm')[0].reset();\n";
        $html .= "            new bootstrap.Modal(document.getElementById('editModal')).show();\n";
        $html .= "        }\n";
        $html .= "        \n";
        $html .= "        function editRecord(id) {\n";
        $html .= "            currentId = id;\n";
        $html .= "            $.get('api.php?action=one&id='+id, function(response) {\n";
        $html .= "                if (response.success) {\n";
        $html .= "                    let row = response.data;\n";
        foreach ($fields as $field) {
            if ($field['key'] === 'PRI' || $field['extra'] === 'auto_increment') continue;
            $html .= "                    $('input[name={$field['name']}], textarea[name={$field['name']}]').val(row.{$field['name']});\n";
        }
        $html .= "                    $('#modalTitle').text('编辑记录');\n";
        $html .= "                    new bootstrap.Modal(document.getElementById('editModal')).show();\n";
        $html .= "                }\n";
        $html .= "            });\n";
        $html .= "        }\n";
        $html .= "        \n";
        $html .= "        $('#editForm').on('submit', function(e) {\n";
        $html .= "            e.preventDefault();\n";
        $html .= "            let data = $(this).serialize();\n";
        $html .= "            let url = currentId ? 'api.php?action=update&id='+currentId : 'api.php?action=create';\n";
        $html .= "            \n";
        $html .= "            $.post(url, data, function(response) {\n";
        $html .= "                if (response.success) {\n";
        $html .= "                    new bootstrap.Modal(document.getElementById('editModal')).hide();\n";
        $html .= "                    loadData();\n";
        $html .= "                }\n";
        $html .= "            });\n";
        $html .= "        });\n";
        $html .= "        \n";
        $html .= "        function deleteRecord(id) {\n";
        $html .= "            if (confirm('确定删除这条记录吗?')) {\n";
        $html .= "                $.post('api.php?action=delete&id='+id, function(response) {\n";
        $html .= "                    if (response.success) {\n";
        $html .= "                        loadData();\n";
        $html .= "                    }\n";
        $html .= "                });\n";
        $html .= "            }\n";
        $html .= "        }\n";
        $html .= "        \n";
        $html .= "        // 初始加载\n";
        $html .= "        loadData();\n";
        $html .= "    </script>\n";
        $html .= "</body>\n";
        $html .= "</html>\n";
        return $html;
    }
    // 生成API接口文件
    public function generateApi($table) {
        $config = $this->generateConfig($table);
        $code = "<?php\n";
        $code .= "/**\n";
        $code .= " * API接口 - {$table}\n";
        $code .= " */\n";
        $code .= "require_once 'config.php';\n";
        $code .= "require_once 'Database.php';\n";
        $code .= "require_once 'BaseCrud.php';\n";
        $code .= "require_once '{$this->toCamelCase($table)}Controller.php';\n";
        $code .= "\n";
        $code .= "// 初始化数据库连接\n";
        $code .= "\$db = Database::getInstance(\$config)->getConnection();\n";
        $code .= "\$controller = new {$this->toCamelCase($table)}Controller(\$db);\n";
        $code .= "\n";
        $code .= "// 处理请求\n";
        $code .= "\$action = \$_GET['action'] ?? 'list';\n";
        $code .= "\n";
        $code .= "switch (\$action) {\n";
        $code .= "    case 'list':\n";
        $code .= "        \$page = \$_GET['page'] ?? 1;\n";
        $code .= "        \$limit = \$_GET['limit'] ?? 10;\n";
        $code .= "        \$search = \$_GET['search'] ?? '';\n";
        $code .= "        \$result = \$controller->read(null, \$page, \$limit, \$search);\n";
        $code .= "        echo json_encode(['success' => true, 'data' => \$result]);\n";
        $code .= "        break;\n";
        $code .= "        \n";
        $code .= "    case 'one':\n";
        $code .= "        \$id = \$_GET['id'];\n";
        $code .= "        \$result = \$controller->read(\$id);\n";
        $code .= "        echo json_encode(['success' => true, 'data' => \$result]);\n";
        $code .= "        break;\n";
        $code .= "        \n";
        $code .= "    case 'create':\n";
        $code .= "        \$result = \$controller->create(\$_POST);\n";
        $code .= "        echo json_encode(\$result);\n";
        $code .= "        break;\n";
        $code .= "        \n";
        $code .= "    case 'update':\n";
        $code .= "        \$id = \$_GET['id'];\n";
        $code .= "        \$result = \$controller->update(\$id, \$_POST);\n";
        $code .= "        echo json_encode(['success' => \$result]);\n";
        $code .= "        break;\n";
        $code .= "        \n";
        $code .= "    case 'delete':\n";
        $code .= "        \$id = \$_GET['id'];\n";
        $code .= "        \$result = \$controller->delete(\$id);\n";
        $code .= "        echo json_encode(['success' => \$result]);\n";
        $code .= "        break;\n";
        $code .= "}\n";
        return $code;
    }
    // 生成所有文件
    public function generateAll($table, $outputDir) {
        $files = [
            $outputDir . '/' . $this->toCamelCase($table) . 'Controller.php' => $this->generateController($table),
            $outputDir . '/' . $table . '.html' => $this->generateView($table),
            $outputDir . '/api_' . $table . '.php' => $this->generateApi($table)
        ];
        foreach ($files as $path => $content) {
            file_put_contents($path, $content);
        }
        return $files;
    }
    // 表名转驼峰
    private function toCamelCase($string) {
        $words = explode('_', $string);
        $className = '';
        foreach ($words as $word) {
            $className .= ucfirst($word);
        }
        return $className;
    }
}

使用示例

<?php
// 配置文件 config.php
$config = [
    'host' => 'localhost',
    'username' => 'root',
    'password' => '',
    'database' => 'test_db',
    'port' => 3306,
    'charset' => 'utf8mb4'
];
?>
<?php
// 使用示例 index.php
require_once 'Database.php';
require_once 'BaseCrud.php';
require_once 'CrudGenerator.php';
// 初始化数据库
$db = Database::getInstance($config)->getConnection();
// 方式1:直接使用BaseCrud类
$crud = new BaseCrud($db, 'users', [
    'primaryKey' => 'id',
    'allowedFields' => ['name', 'email', 'phone', 'status'],
    'searchFields' => ['name', 'email', 'phone'],
    'uploadFields' => [] // 如果有上传字段
]);
// 创建记录
$newId = $crud->create([
    'name' => '张三',
    'email' => 'zhangsan@example.com',
    'phone' => '13800138000',
    'status' => 1
]);
// 读取记录(分页)
$result = $crud->read(null, 1, 10, '张三');
print_r($result);
// 更新记录
$crud->update($newId, ['status' => 0]);
// 删除记录
$crud->delete($newId);
// 方式2:使用CRUD生成器自动生成代码
$generator = new CrudGenerator($db);
// 获取所有表
$tables = $generator->getTables();
// 获取表结构
$structure = $generator->getTableStructure('users');
// 生成所有CRUD文件
$files = $generator->generateAll('users', __DIR__ . '/generated');
print_r($files);
?>

这个PHP CRUD生成器提供了:

  1. 自动字段识别 - 自动获取数据库表结构
  2. 完整CRUD操作 - 增删改查、分页、搜索
  3. 代码生成器 - 自动生成控制器、视图、API接口
  4. 安全处理 - 使用预处理语句防止SQL注入
  5. 灵活配置 - 可以自定义字段、搜索条件、上传文件等
  6. 前端页面生成 - 自动生成Bootstrap风格的页面

抱歉,评论功能暂时关闭!