热搜:NVER 

依据表结构自动生成一个PHP类

2024-04-29 21:24:01
 依据表结构自动生成一个PHP类

根据表结构自动生成一个PHP类

Zend framework提供了一种class和table映射起来的方式,创建一个继承Zend_Db_Table的class。查询时,zend自动将表字段做处理,生成一个对象,对象属性都是动态创建,所以是public的。这有两个大问题,一是class的属性是public,二是class的属性只有代码执行后才确定。于是乎,自己写了一个程序,根据表信息生成对应的class。

?

?

<?php
/**
 * 这个类的作用是从数据库里读出表结构,然后生成一个bean类,并将其属性与类一一映射。
 * 具体生成的内容包括:
 * 1. 私有变量
 * 2. 表字段与属性的映射关系
 * 3. 表字段的信息,用于server的验证
 */
class TableClassGenerator {
	const DEFAULT_DIR = 'classes';
	const DEFAULT_INDENT = 4;
	const DEFAULT_MIN = 2;
	private $excludedProperties;
    private $database;
    private $file;
    private $givenTables;
    private $parentClass;
    
    public function __construct($config) {
    	if (!isset($config) || empty($config) || ! is_array($config)) {
    		die('Invalid config: '. print_r($config, true));
    	}
    	
    	$this->database = $config['database'];
    	$conn = isset($config['password'])
        	? mysql_connect($config['host'], $config['user'], $config['password'])
    		: mysql_connect($config['host'], $config['user']);
    	if (! isset($conn)) {
    		die('Failed to connect.' . mysql_error());
    	}
    	
    	$this->givenTables = $config['tables'];
    	if (isset($this->givenTables)
    			&& (!is_array($this->givenTables)
    					|| empty($this->givenTables))) {
    		die("Tables($this->givenTables) in config is not an array or it is empty.");
    	}
    	
    	$this->parentClass = $config['parentClass'];
    	
    	if ($config['excludedProperties']) {
    		$this->excludedProperties = $config['excludedProperties'];
    		if (!is_array($this->excludedProperties)
    				|| empty($this->excludedProperties)) {
    			die('excludedProperties should be an array and shoudnot be empty.');
    		}
    	}
    	
    	if (! file_exists(self::DEFAULT_DIR)) {
    		mkdir(self::DEFAULT_DIR);
    	}
    }
    
    public function __destroy() {
        mysql_close();
    }
    
	public function generateClasses() {
		$allTables = $this->getTables();
		var_dump($allTables);

		$tables = $this->givenTables
			? $this->givenTables
			: $allTables;

    	if (empty($tables)) {
    		die("Empty given tables");
    	}
    	
    	foreach ($tables as $table) {
    		$index = array_search($table, $allTables);
    		if (!is_int($index)) {
    			echo "Table($table) not found in database({$this->database}).\n";
    			continue;
    		}
    		
    		$this->generateClassForTable($table);
    	}
    }
    
	private function generateClassForTable($table) {
        $class = ucfirst($this->transform($table));
        $fileName = self::DEFAULT_DIR . "/$class.php";
        if (file_exists($fileName)) {
        	echo "The file($fileName) already exists. You need delete if first.\n";
        	//return;
        }
        
        $columns = $this->getTableColumns($table);
        if (!isset($columns) || empty($columns)) {
		  	echo "The table($table) doesn't have columns.\n";
        	return;  	
        }
        
        $this->file = fopen($fileName, 'w');
        if (! isset($this->file)) {
        	die("Failed to open file: $fileName");
        }
        
        echo "Generating class for table: $table.\n";

        $this->writeToFile("<?php");
        if ($this->parentClass) {
        	$this->writeToFile("class $class extends {$this->parentClass} {");
        } else {
        	$this->writeToFile("class $class {");
        }

        $this->generateConst($table);
        $this->generateColumnPropMapping($columns);
        $this->generateValidateConfig($table, $columns);
        $this->generateProperties($columns);
        $this->generateGetters($columns);
        $this->generateSetters($columns);
        $this->writeToFile("}");
        $this->writeToFile("?>");

        fclose($this->file);
        echo "Class($class) was created in the file($fileName).\n\n";
    }
    
	private function generateColumnPropMapping($columns) {
		$this->writeToFile('private static $_colPropMapping = array(', 1);
		
		foreach ($columns as $key => $value) {
			$prop = $this->transform($key);
			$this->writeToFile("'$key' => '$prop',", 2);
		}
		
		$this->writeToFile(');', 1);
		$this->writeNewLine();
    }
    
    private function generateConst($table) {
    	$this->writeToFile("const TABLE_NAME = '$table';", 1);
    	$this->writeNewLine();
    }
    
	private function generateGetters($columns) {
        foreach ($columns as $key => $value) {
            $prop = $this->transform($key);
        	if ($this->shouldExcludeProp($prop)) {
            	continue;
            }
            
            $method = 'get' . ucfirst($prop);
            $this->writeToFile("public function $method() {", 1);
            $this->writeToFile('return $' . "this->$prop;", 2);
            $this->writeToFile("}", 1);
            $this->writeNewLine();
        }
    }
    
    private function generateProperties($columns) {
        $keys = array_keys($columns);
        foreach ($keys as $key) {
            $prop = $this->transform($key);
            if ($this->shouldExcludeProp($prop)) {
            	continue;
            }
            $this->writeToFile("private $prop;", 1);
        }
        $this->writeNewLine();
    }
    
    private function generateSetters($columns) {
        foreach ($columns as $key => $value) {
            $prop = $this->transform($key);
        	if ($this->shouldExcludeProp($prop)) {
            	continue;
            }

            $method = 'set' . ucfirst($prop);
            $this->writeToFile("public function $method ($$prop) {", 1);
            $this->writeToFile('$' . "this->$prop = $" . "$prop;", 2);
            $this->writeToFile("}", 1);
            $this->writeNewLine();
        }
    }
    
    private function generateValidateConfig($table, $columns) {
    	$this->writeToFile('private static $_validator = array(', 1);
		$this->writeToFile("'$table' => array(", 2);
		foreach ($columns as $key => $value) {
			$this->writeToFile("'$key' => array(", 3);
			foreach ($value as $k => $v) {
				if (is_string($v)) {
					$this->writeToFile("'$k' => '$v',", 4);
				} else {
					$this->writeToFile("'$k' => $v,", 4);
				}
			}
			$this->writeToFile("),", 3);
		}
		$this->writeToFile("), // $table", 2);
		$this->writeToFile(');', 1);
		$this->writeNewLine();
    }
    
    private function getMin($max, $type) {
    	if (!isset($max)) {
    		return null;
    	}
    	
    	$min = self::DEFAULT_MIN;
    	if ($type == 'date' || $min > $max) {
    		$min = $max;
    	}
    	return $min;
    }
    
    public function getTableColumns($table) {
        $fields = mysql_list_fields($this->database, $table);
        $count = mysql_num_fields($fields);
        if (! isset($fields)) {
            die("Failed to get fields" . mysql_error());
        }

        $columns = array();
        for ($i = 0; $i < $count; $i++) {
            $flags = mysql_field_flags($fields, $i);
            $isRequired = preg_match('/not_null/', $flags);

            $col = mysql_field_name($fields, $i);
            $max = mysql_field_len($fields, $i);
            $type = mysql_field_type($fields, $i);
            $min = $this->getMin($max, $type);
            
            $columns[$col] = array(
                'isRequired' => $isRequired,
                'max' => $max,
            	'min' => $min,
                'type' => $type,
            );
        }
        
        $sortedColumns = array();
        $keys = array_keys($columns);
        sort($keys);
        foreach ($keys as $key) {
            $sortedColumns[$key] = $columns[$key];
        }
        return $sortedColumns;
    }
    
    private function getTables() {
    	$sql = "SHOW TABLES FROM {$this->database}";
    	$result = mysql_query($sql);
    	$tables = array();
    	for ($i = 0; $i < mysql_num_rows($result); $i++) {
    		$tables[] = mysql_tablename($result, $i);
    	}
    	return $tables;
    }
    
    private function shouldExcludeProp($prop) {
    	if (! isset($this->excludedProperties)) {
    		return false;
    	}
    	
        $index = array_search($prop, $this->excludedProperties);
        return is_int($index);
    }
    
	private function transform($name) {
        $words = explode('_', $name);
        $newName = null;
        foreach ($words as $word) {
            if ($newName == null) {
                $newName = $word;
            } else {
                $newName .= ucfirst($word);
            }
        }
        
        return $newName;
    }
    
    private function writeNewLine() {
    	$this->writeToFile('');
    }
    
    private function writeToFile($str, $count = 0) {
        $space = null;
        $count *= self::DEFAULT_INDENT;
        while ($count) {
            if ($space == null) {
                $space = ' ';
            } else {
                $space .= ' ';
            }
            $count--;
        }
        fwrite($this->file, $space);
        fwrite($this->file, "$str\n");
    }
} // TableClassGenerator

$gen = new TableClassGenerator(array(
    'excludedProperties' => array('id', 'userId'),
    'database' => 'mydb',
    'host' => 'localhost',
    'parentClass' => 'Base',
    'password' => 'pwd',
    // 'tables' => array('user'),
    'user' => 'userId',
));
    	
$gen->generateClasses();