PHP实体类生成器

31

我正在创建实体(entity-view-controller的模型)类,理论上与我拥有的数据库表匹配。是否有一种工具可以读取MySQL表并创建模型类代码?(不是在执行时,需要一个代码输出)

class{
public $columnname1;
public $columnname2;
public $columnname3;
public $columnname4;
public $columnname5;
public $columnname6;
function __construct(&$columnname1, &$columnname2){...}
function insert(&$columnname1, &$columnname2){}
function delete(&$columnname1){}
...
}

一个能够创建根据id进行插入、更新和删除的工具对我非常有帮助。

这个工具可以是免费或付费的。


1
有一些相反的东西,可以看看RedBeanPHP。还有一个类似的是Doctrine ORM,但是也有propel,这可能是你正在寻找的:现有数据库 - hakre
@mogria 我期望输出一个导出的文本文件(php或其他格式)。 - Uğur Gümüşhan
1
强烈建议您采用另一种方式:先设计您的模型,然后基于模型设计数据访问和数据库表。 - Nazar Merza
1
@NazarMerza 这是什么让它不仅仅是个人偏好? - Uğur Gümüşhan
有没有想过使用Codeigniter来实现相同的功能,而不是使用ORM? - Ramaraju.d
显示剩余5条评论
10个回答

17

PDO可以将结果提取到一个对象中

设计一个与你的数据库/查询结构匹配的类,并使用PDO::FETCH_INTO将结果集提取到已经实例化的对象中。我误解了问题,我的错。


为了从数据库结构生成类本身,有几个项目可用(我没有测试过,但这是一个非常简单的搜索结果)。


1
我正在寻找一种自动完成此操作的解决方案,因为它可以自动完成。我知道如何做所有这些事情,就像知道数学和购买计算器一样。 - Uğur Gümüşhan
等一下,你想从表格生成类吗? - Madara's Ghost
是的,如问题所述。 - Uğur Gümüşhan
我之前一直在使用NetBeans,不过我想现在换用db2php,看起来很有用。 - Uğur Gümüşhan
PHP MySQL类生成器与php 8不兼容。 - Yehuda

10
以下是我长期使用的用于创建MySQL和DB2表的PHP模型的代码。我已经为MSSQL、PGSQL和SQLite放置了存根,但从未需要完成它们。
这是代码生成器类:
<?php
/**
 * @license http://opensource.org/licenses/MIT The MIT License
 * @version 1.0.0_20130220000000
 */

/**
 * This class will generate PHP source code for a "model" that interfaces with 
 * a database table.
 * 
 * @license http://opensource.org/licenses/MIT The MIT License
 * @version 1.0.0_20130220000000
 */
class db_code_generator{
    private $closing_tag;
    private $columns;
    private $database;
    private $host;
    private $password;
    private $port;
    private $table;
    private $type;
    private $username;

    /**
     * Constructor. By default we will try to connect to a MySQL database on 
     * localhost.
     * 
     * @param string $database The name of the database the user wants to connect
     * to.
     * 
     * @param string $table The name of the table to generate code for.
     * 
     * @param string $username The username we should use to connect to the 
     * database.
     * 
     * @param string $password The password we need to connect to the database.
     * 
     * @param string $host The host or server we will try to connect to. If the 
     * user doesn't give us a host we default to localhost.
     * 
     * @param string $port The port we should try to connect to. Typically this 
     * will not be passed so we default to NULL.
     * 
     * @param string $type The type of database we are connecting to. Valid 
     * values are: db2, mssql, mysql, pgsql, sqlite.
     */
    public function __construct($database = NULL,
                                         $table = NULL,
                                         $username = NULL,
                                         $password = NULL,
                                         $host = 'localhost',
                                         $type = 'mysql',
                                         $port = NULL,
                                         $closing_tag = TRUE){
        $this->database = $database;
        $this->table = $table;
        $this->username = $username;
        $this->password = $password;
        $this->host = $host;
        $this->port = $port;
        $this->type = $type;
        $this->closing_tag = $closing_tag;
    }

    /**
     * Generate the code for a model that represents a record in a table.
     * 
     * @return string The PHP code generated for this model.
     */
    public function get_code(){
        $this->get_data_definition();
        $code = $this->get_file_head();
        $code .= $this->get_properties();
        $code .= $this->get_ctor();
        $code .= $this->get_dtor();
        $code .= $this->get_method_stubs();
        $code .= $this->get_file_foot();
        return $code;
    }

    /**
     * Create the code needed for the __construct function.
     * 
     * @return string The PHP code for the __construct function.
     */
    private function get_ctor(){
        $code = "\t/**\n";
        $code .= "\t * Constructor.\n";
        $code .= "\t *\n";
        $code .= "\t * @param mixed \$id The unique id for a record in this table. Defaults to NULL\n";
        if ('db2' === $this->type){
            $code .= "\n\t * @param string \$library The library where the physical file resides. Defaults to LIBRARY\n";
        }
        $code .= "\t *\n";
        $code .= "\t * @see base_$this->type::__construct\n";
        $code .= "\t */\n";
        if ('db2' === $this->type){
            $code .= "\tpublic function __construct(\$id = NULL, \$library = 'LIBRARY'){\n";
            $code .= "\t\tparent::__construct(\$id, \$library);\n";
        }else{
            $code .= "\tpublic function __construct(\$id = NULL){\n";
            $code .= "\t\tparent::__construct(\$id);\n";
        }
        $code .= "\t}\n\n";
        return $code;
    }

    /**
     * Connect to the requested database and get the data definition for the
     * requested table.
     */
    private function get_data_definition(){
        try{
            switch ($this->type){
                case 'db2':
                    $this->get_data_definition_db2();
                    break;
                case 'mssql':
                    $this->get_data_definition_mssql();
                    break;
                case 'mysql':
                    $this->get_data_definition_mysql();
                    break;
                case 'pgsql':
                    $this->get_data_definition_pgsql();
                    break;
                case 'sqlite':
                    $this->get_data_definition_sqlite();
                    break;
            }
        }catch(PDOException $e){
        }
    }

    /**
     * Get data definition information for a DB2 table.
     */
    private function get_data_definition_db2(){
        $con = new PDO("odbc:DRIVER={iSeries Access ODBC Driver};SYSTEM=$this->host;PROTOCOL=TCPIP", $this->username, $this->password);
        $sql = "SELECT COLUMN_NAME, COLUMN_SIZE, COLUMN_TEXT, DECIMAL_DIGITS, ORDINAL_POSITION, TYPE_NAME FROM SYSIBM.SQLCOLUMNS WHERE TABLE_SCHEM = '". strtoupper($this->database) ."' AND TABLE_NAME = '". strtoupper($this->table) ."'";
        $statement = $con->prepare($sql);
        if ($statement->execute()){
            while ($row = $statement->fetch()){
                if (NULL !== $row['DECIMAL_DIGITS']){
                    $decimal = $row['DECIMAL_DIGITS'];
                }else{
                    $decimal = NULL;
                }
                if ('DECIMAL' === $row['TYPE_NAME'] && NULL !== $row['DECIMAL_DIGITS'] && '0' !== $row['DECIMAL_DIGITS']){
                    $type = 'float';
                }else if ('DECIMAL' === $row['TYPE_NAME']){
                    $type = 'integer';
                }else{
                    $type = strtolower($row['TYPE_NAME']);
                }
                if ('1' === $row['ORDINAL_POSITION']){
                    $key = 'PRI';
                }else{
                    $key = NULL;
                }
                $this->columns[$row['COLUMN_NAME']] = array('allow_null' => TRUE,
                                                                          'decimal' => $decimal,
                                                                          'default' => NULL,
                                                                          'extra' => NULL,
                                                                          'key' => $key,
                                                                          'length' => $row['COLUMN_SIZE'],
                                                                          'name' => $row['COLUMN_NAME'],
                                                                          'text' => $row['COLUMN_TEXT'],
                                                                          'type' => $type);
            }
            ksort($this->columns);
        }
    }

    /**
     * Get data definition information for a MS SQL table.
     */
    private function get_data_definition_mssql(){
        return "The code for generating MS SQL models is not yet implemented.\n";
    }

    /**
     * Get data definition information for a MySQL table.
     */
    private function get_data_definition_mysql(){
        $dsn = "mysql:host=$this->host;";
        if (NULL !== $this->port){
            $dsn .= "port=$this->port;";
        }
        $dsn .= "dbname=$this->database";
        $con = new PDO($dsn, $this->username, $this->password);
        $sql = "SHOW COLUMNS FROM $this->table";
        $statement = $con->prepare($sql);
        if ($statement->execute()){
            while ($row = $statement->fetch()){
                $this->columns[$row['Field']] = array('allow_null' => $row['Null'],
                                                                  'decimal' => NULL,
                                                                  'default' => $row['Default'],
                                                                  'extra' => $row['Extra'],
                                                                  'key' => $row['Key'],
                                                                  'length' => NULL,
                                                                  'name' => $row['Field'],
                                                                  'text' => NULL,
                                                                  'type' => $row['Type']);
            }
            ksort($this->columns);
        }
    }

    /**
     * Get data definition information for a PostgreSQL table.
     */
    private function get_data_definition_pgsql(){
        return "The code for generating PostgreSQL models is not yet implemented.\n";
    }

    /**
     * Get data definition information for a SQLite table.
     */
    private function get_data_definition_sqlite(){
        return "The code for generating SQLite models is not yet implemented.\n";
    }

    /**
     * Create the code needed for the __destruct function.
     * 
     * @return string The PHP code for the __destruct function.
     */
    private function get_dtor(){
        $code = "\t/**\n";
        $code .= "\t * Destructor.\n";
        $code .= "\t */\n";
        $code .= "\tpublic function __destruct(){\n";
        $code .= "\t\tparent::__destruct();\n";
        $code .= "\t}\n\n";
        return $code;
    }

    /**
     * Generate the code found at the end of the file - the closing brace, the 
     * ending PHP tag and a new line. Some PHP programmers prefer to not have a 
     * closing PHP tag while others want the closing tag and trailing newline - 
     * it probably just depends on their programming background. Regardless it's 
     * best to let everyone have things the way they want.
     */
    private function get_file_foot(){
        $code = '';
        if ($this->closing_tag){
            $code .= "}\n?>\n";
        }else{
            $code .= '}';
        }
        return $code;
    }

    /**
     * Generate the code found at the beginning of the file - the PHPDocumentor 
     * doc block, the require_once for the correct base class and the class name.
     * 
     * @return string The code generated for the beginning of the file.
     */
    private function get_file_head(){
        $code  = "<?php\n";
        $code .= "/**\n";
        $code .= " * Please enter a description of this class.\n";
        $code .= " *\n";
        $code .= " * @author XXX <XXX@domain.com>\n";
        $code .= " * @copyright Copyright (c) ". date('Y') ."\n";
        $code .= " * @license http://www.gnu.org/licenses/gpl-3.0.html GPLv3\n";
        $code .= " * @version ". date('Ymd') ."\n";
        $code .= " */\n\n";
        $code .= "require_once('base_$this->type.php');\n\n";
        $code .= "class ". strtolower($this->table) ." extends base_$this->type{\n";
        return $code;
    }

    /**
     * Generate the code for a delete method stub.
     * 
     * @return string The PHP code for the method stub.
     */
    private function get_method_stub_delete(){
        $code  = "\t/**\n";
        $code .= "\t * Override the delete method found in the base class.\n";
        $code .= "\t *\n";
        $code .= "\t * @param mixed \$id The unique record ID to be deleted.\n";
        $code .= "\t *\n";
        $code .= "\t * @return bool TRUE if a record was successfully deleted from the table, FALSE otherwise.\n";
        $code .= "\t */\n";
        $code .= "\tpublic function delete(\$id){\n";
        $code .= "\t\treturn parent::delete(\$id);\n";
        $code .= "\t}\n\n";
        return $code;
    }

    /**
     * Generate the code for an insert method stub.
     * 
     * @return string The PHP code for the method stub.
     */
    private function get_method_stub_insert(){
        $code  = "\t/**\n";
        $code .= "\t * Override the insert method found in the base class.\n";
        $code .= "\t *\n";
        $code .= "\t * @param array \$parms An array of data, probably the \$_POST array.\n";
        $code .= "\t * @param bool \$get_insert_id A flag indicating if we should get the autoincrement value of the record just created.\n";
        $code .= "\t *\n";
        $code .= "\t * @return bool TRUE if a record was successfully inserted into the table, FALSE otherwise.\n";
        $code .= "\t */\n";
        $code .= "\tpublic function insert(\$parms, \$get_insert_id = FALSE){\n";
        $code .= "\t\treturn parent::insert(\$parms, \$get_insert_id);\n";
        $code .= "\t}\n\n";
        return $code;
    }

    /**
     * Generate the code for an update method stub.
     * 
     * @return string The PHP code for the method stub.
     */
    private function get_method_stub_update(){
        $code  = "\t/**\n";
        $code .= "\t * Override the update method found in the base class.\n";
        $code .= "\t *\n";
        $code .= "\t * @param array &\$parms An array of key=>value pairs - most likely the \$_POST array.\n";
        $code .= "\t *\n";
        $code .= "\t * @param integer \$limit The number of records to update. Defaults to NULL.\n";
        $code .= "\t *\n";
        $code .= "\t * @return bool TRUE if a record was successfully updated, FALSE otherwise.\n";
        $code .= "\t */\n";
        $code .= "\tpublic function update(\$parms, \$limit = NULL){\n";
        $code .= "\t\treturn parent::update(\$parms, \$limit);\n";
        $code .= "\t}\n\n";
        return $code;
    }

    /**
     * Create method stubs for create, delete and update.
     * 
     * @return string The PHP code for these stubs.
     */
    private function get_method_stubs(){
        $code = $this->get_method_stub_delete();
        $code .= $this->get_method_stub_insert();
        $code .= $this->get_method_stub_update();
        return $code;
    }

    private function get_properties(){
        $code = '';
        if (count($this->columns)){
            foreach ($this->columns AS $index => $col){
                $code .= "\t/**\n";
                if (NULL !== $col['text']){
                    $code .= "\t * $col[text]\n";
                }else{
                    $code .= "\t * Description\n";
                }
                $code .= "\t * @var ". $col['type'];
                if (NULL !== $col['length']){
                    $code .= " ($col[length]";
                    if (NULL !== $col['decimal']){
                        $code .= ",$col[decimal]";
                    }
                    $code .= ")";
                }
                $code .= "\n\t */\n";
                $temp_name = str_replace('#', '_', $col['name']);
                $code .= "\tpublic \$$temp_name;\n\n";
            }
        }
        return $code;
    }
}
?>

这是一个简单的页面,用于演示:

<?php
/**
 * @license GPLv3 (http://www.gnu.org/licenses/gpl-3.0.html)
 * @version 1.0.0_20130220000000
 */

require_once('db_code_generator.php');

$table_type = array();
$table_type['db2'] = 'DB2/400 (db2)';
$table_type['mssql'] = 'Microsoft SQL Server (mssql)';
$table_type['mysql'] = 'MySQL (mysql)';
$table_type['pgsql'] = 'PostGRESQL (pgsql)';
$table_type['sqlite'] = 'SQLite (sqlite)';

$database = (isset($_POST['database'])) ? $_POST['database'] : 'my_database';
$host = (isset($_POST['host'])) ? $_POST['host'] : 'localhost';
$username = (isset($_POST['username'])) ? $_POST['username'] : 'root';
$password = (isset($_POST['password'])) ? $_POST['password'] : '';
$table = (isset($_POST['table'])) ? $_POST['table'] : '';
$type = (isset($_POST['type'])) ? $_POST['type'] : 'mysql';

$library = (isset($_POST['library'])) ? $_POST['library'] : 'LIBRARY';
$file = (isset($_POST['file'])) ? $_POST['file'] : 'STATES';
//---------------------------------------------------------------------------
?>
<div class="data_input">
    <form action="" method="post">
        <fieldset class="top">
            <legend>Code Generator</legend>
            <label for="host">Hostname or IP:
            <input id="host" maxlength="32" name="host" tabindex="<?php echo $tabindex++; ?>" title="Enter the database host name" type="text" value="<?php echo $host; ?>" />
            </label>
            <br />

            <label for="username">Username:
            <input id="username" maxlength="32" name="username" tabindex="<?php echo $tabindex++; ?>" title="Enter the database username" type="text" value="<?php echo $username; ?>" />
            </label>
            <br />

            <label for="password">Password:
            <input id="password" maxlength="32" name="password" tabindex="<?php echo $tabindex++; ?>" title="Enter the database password" type="password" value="<?php echo $password; ?>" />
            </label>
            <br />

            <label for="type">Type:
            <select id="type" name="type" tabindex="<?php echo $tabindex++; ?>">
                <?php
                foreach ($table_type AS $key=>$value){
                    echo('<option ');
                    if ($key == $type){
                        echo 'selected="selected" ';
                    }
                    echo 'value="'. $key .'">'. $value .'</option>';
                }
                ?>
            </select>
            </label>
            <br />

        </fieldset>

        <fieldset class="top">
            <legend>PostGRESQL/MSSQL/MySQL Parameters</legend>

            <label for="database">Database:
            <input id="database" maxlength="100" name="database" tabindex="<?php echo $tabindex++; ?>" title="Enter the database name" type="text" value="<?php echo $database; ?>" />
            </label>
            <br />

            <label for="table">Table:
            <input id="table" maxlength="100" name="table" tabindex="<?php echo $tabindex++; ?>" title="Enter the table name" type="text" value="<?php echo $table; ?>" />
            </label>
            <br />

        </fieldset>
        <fieldset class="top">
            <legend>DB2 Parameters</legend>

            <label for="library">Library:
            <input id="library" maxlength="10" name="library" tabindex="<?php echo $tabindex++; ?>" title="Enter the library name" type="text" value="<?php echo $library; ?>" />
            </label>
            <br />

            <label for="file">Physical File:
            <input id="file" maxlength="10" name="file" tabindex="<?php echo $tabindex++; ?>" title="Enter the file name" type="text" value="<?php echo $file; ?>" />
            </label>
            <br />

        </fieldset>
        <fieldset class="bottom">
            <button tabindex="<?php echo $tabindex++; ?>" type="submit">Generate!</button>
        </fieldset>
    </form>
</div>
<?php

if (isset($_POST['host'])){
    if ('db2' == $_POST['type']){
        $_POST['database'] = strtoupper($_POST['library']); // Library
        $_POST['table'] = strtoupper($_POST['file']); // Physical file
        $_POST['host'] = 'db2_host';
        $_POST['username'] = 'db2_username';
        $_POST['password'] = 'db2_password';
    }
    $object = new db_code_generator($_POST['database'], $_POST['table'], $_POST['username'], $_POST['password'], $_POST['host'], $_POST['type']);
    echo('<textarea rows="75" style="margin-left : 50px; width : 90%;" onfocus="select()">'. $object->get_code() .'</textarea>');
}
?>

太酷了!你能分享一下base_mysql类吗? - Grynn
@Grynn - base_mysql 类超过 700 行,它的父类 (base) 大约有 650 行。我可以通过电子邮件发送给你。 - Benny Hill
您可以通过电子邮件发送给我(vishal.doshi@gmail.com),或者将其粘贴到gist.github.com上。我很乐意从您的代码中创建一个GitHub或其他项目(当然要归功于您),以便它可以得到维护。 - Grynn
@Grynn - 电子邮件已发送。 - Benny Hill
嗨,我很高兴收到这封邮件:clashnco@gmail.com - Dan M. CISSOKHO
显示剩余2条评论

6

5

试试这个:https://github.com/rcarvello/mysqlreflection

这是一个有用的工具,用于MySQL数据库的对象关系映射。

该工具会自动生成给定数据库模式下任何表的PHP类。

该软件包从我的个人PHP Web MVC框架中提取而来。


3

就代码而言,Rafael Rocha 在这里分享了代码 here

不过,我强烈建议使用 ORM。将 MySQL 结构转换回数据库抽象层绝非明智之举...


3

那么symfony呢?它正好可以实现你所说的,并且你可以得到一个非常好的框架。

symfony会基于你提供的数据模型为你“编译”类。它将确保编译后的类和MySQL数据库结构是同步的。

Reflection方法相比,这种方法更受欢迎,因为Reflection方法太慢了。


1

是的,Doctrine是你需要的。

  1. 运行命令,你可以获得所有表格的元数据,以XML或YML格式(选择由你决定)

    $ php app/console doctrine:mapping:convert xml ./src/Bundle/Resources/config/doctrine/metadata/orm --from-database --force

  2. 一旦你生成了Metadata,使用Doctrine指令导入模式来构建你需要的相关实体类。你将找到所有GET和SET功能(读取SELECTUPDATEINSERT)。

    1.$ php app/console doctrine:mapping:import Bundle annotation

    2.$ php app/console doctrine:generate:entities Bundle

    在此处阅读详细内容及示例


"在“doctrine:mapping”命名空间中没有定义任何命令。" - Scott

1
我编写了一段PHP代码,它可以自动检测MYSQL数据库中的所有数据库,选择任何一个数据库后,将加载其所有相关表。您可以选择所有表或任何相应的表来生成模态类。
以下是我的存储库链接。

https://github.com/channaveer/EntityGenerator

这将自动创建实体文件夹并将所有实体类倾倒到该文件夹中。
注意 - 目前仅支持MYSQL。
希望能帮到你。编码愉快!

1

无脂框架允许您使用以下代码与现有表格一起工作:

$user=new DB\SQL\Mapper($db,'users');
// or $user=new DB\Mongo\Mapper($db,'users');
// or $user=new DB\Jig\Mapper($db,'users');
$user->userID='jane';
$user->password=md5('secret');
$user->visits=0;
$user->save();

上面的代码在 users 表中创建了新记录。

-1

我认为你应该自己解决。在我看来,每个 Model Code 项目和需求都是不同的。两个mysql查询将让您感到轻松。

  1. SHOW TABLES FROM db_NAME //这会给出表列表,因此它是 Master Looper
  2. DESC tbl_name //详细查询,获取给定表的列信息

DESC tbl_name 将提供字段、类型、Null、Key、默认值和额外列。

例如,用竖线 (|) 分隔的值:

Id | int(11) | NO | PRI | NULL | auto_increment |

我遵循了这些步骤,在 Codeigniter 2 中创建了支持 CRUD 操作的 Model、Controller 和 Viewer 文件。它完全正常运行。


我宁愿自动生成基础内容,然后在拥有的基础上进行操作。 - Uğur Gümüşhan
是的,如果您已经建立了标准,基本的CRUD操作总是相似的。我想我的话可能不太清楚,但重点是,这两个查询将为您提供表列信息,这可以用来生成MVC类和文件。 - Mrigesh Raj Shrestha

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接