Created
March 27, 2010 23:50
-
-
Save 13k/346432 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Generates PHP data transfer objects [1] from a MySQL database schema in a 1:1 | |
| relationship between tables and classes. | |
| These DTOs can be used then in several PHP ORM's, but are specifically generated | |
| to be used with ZendFramework's Zend_Db_Table_Abstract and, for this reason, | |
| also data access objects [2] are generated in another 1:1 relationship between | |
| tables and classes, so N tables will generate N * (1DAO + 1DTO) [2N] files. | |
| All classes are named after ZF namespace naming convention, using a default module | |
| name, e.g., if you have a "user" table, the two classes created will be: | |
| "Application_Model_User" and "Application_Model_UserMapper" (DTO and DAO, | |
| respectivelly). | |
| Both classes implement a minimal set of methods (for DTOs, all accessor methods and | |
| for DAOs none, actually) and inherits from abstract classes that should implement | |
| common logic. Sample abstract classes of both kinds are provided in this gist too. | |
| Command-line usage and options available are poorly written, so you'll probably | |
| need to edit this script to fit to your needs. | |
| Usage: $ generate-db-models.php <db_user> <db_pass> <db_name> <output_directory> | |
| Those args are pretty self-explanatory. If you use another db or connection method | |
| (SSL, socket, whatever), edit the line containing the DSN string [3] that looks like | |
| engine://user:pass@host/db_name | |
| This script also uses MySQL-specific SQL queries (like SHOW and DESCRIBE) to inspect | |
| tables, so you might need to change them to fit others db's needs. | |
| [1] http://en.wikipedia.org/wiki/Data_transfer_object | |
| [2] http://en.wikipedia.org/wiki/Data_access_object | |
| [3] http://www.php.net/manual/en/pdo.construct.php ($dsn parameter) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <?php | |
| require_once 'util.php'; | |
| class Application_Model_Abstract | |
| { | |
| public function __construct(array $options = null) | |
| { | |
| if (is_array($options)) { | |
| $this->setFromArray($options); | |
| } | |
| } | |
| public function __set($name, $value) | |
| { | |
| $method = 'set' . $name; | |
| if (('mapper' == $name) || !method_exists($this, $method)) { | |
| throw new Exception('Invalid property'); | |
| } | |
| $this->$method($value); | |
| } | |
| public function __get($name) | |
| { | |
| $method = 'get' . $name; | |
| if (('mapper' == $name) || !method_exists($this, $method)) { | |
| throw new Exception('Invalid property'); | |
| } | |
| return $this->$method(); | |
| } | |
| public function setFromArray(array $options) | |
| { | |
| $methods = get_class_methods($this); | |
| foreach ($options as $key => $value) { | |
| $method = 'set' . camelize($key); | |
| if (in_array($method, $methods)) { | |
| $this->$method($value); | |
| } | |
| } | |
| return $this; | |
| } | |
| public function toArray() | |
| { | |
| $methods = get_class_methods($this); | |
| $values = array(); | |
| foreach ($methods as $method) { | |
| $isGetter = preg_match('/^get([A-Z]\w+)/', $method, $matches); | |
| if ($isGetter) { | |
| $key = underline($matches[1]); | |
| $value = $this->$method(); | |
| $values[$key] = $value; | |
| } | |
| } | |
| return $values; | |
| } | |
| } | |
| ?> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <?php | |
| class Application_Model_AbstractMapper | |
| { | |
| protected $_dbTable; | |
| protected $_modelName; | |
| public function setDbTable($dbTable) | |
| { | |
| if (is_string($dbTable)) { | |
| $dbTable = new $dbTable(); | |
| } | |
| if (!$dbTable instanceof Zend_Db_Table_Abstract) { | |
| throw new Exception('Invalid table data gateway provided'); | |
| } | |
| $this->_dbTable = $dbTable; | |
| return $this; | |
| } | |
| public function getDbTable() | |
| { | |
| if (null === $this->_dbTable) { | |
| $this->setDbTable("Application_Model_DbTable_$this->_modelName"); | |
| } | |
| return $this->_dbTable; | |
| } | |
| public function save($obj) | |
| { | |
| $clazz = "Application_Model_$this->_modelName"; | |
| if (!$obj instanceof $clazz) { | |
| throw new Exception("Argument 1 passed to save() must be an instance of $clazz"); | |
| } | |
| $data = $obj->toArray(); | |
| if (null === ($id = $obj->getId())) { | |
| unset($data['id']); | |
| $this->getDbTable()->insert($data); | |
| } else { | |
| $this->getDbTable()->update($data, array('id = ?' => $id)); | |
| } | |
| } | |
| public function find($id, $obj) | |
| { | |
| $clazz = "Application_Model_$this->_modelName"; | |
| if (!$obj instanceof $clazz) { | |
| throw new Exception("Argument 2 passed to save() must be an instance of $clazz"); | |
| } | |
| $result = $this->getDbTable()->find($id); | |
| if (count($result) < 1) { | |
| return false; | |
| } | |
| $row = $result->current(); | |
| $obj->setFromArray($row->toArray()); | |
| return $obj; | |
| } | |
| public function fetchAll() | |
| { | |
| $clazz = "Application_Model_$this->_modelName"; | |
| $resultSet = $this->getDbTable()->fetchAll(); | |
| $entries = array(); | |
| foreach ($resultSet as $row) { | |
| $entry = new $clazz(); | |
| $entry->setFromArray($row->toArray()); | |
| $entries[] = $entry; | |
| } | |
| return $entries; | |
| } | |
| } | |
| ?> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <?php | |
| /*** | |
| * | |
| * Generates PHP data transfer objects [1] from a MySQL database schema in a 1:1 | |
| * relationship between tables and classes. | |
| * These DTOs can be used then in several PHP ORM's, but are specifically generated | |
| * to be used with ZendFramework's Zend_Db_Table_Abstract and, for this reason, | |
| * also data access objects [2] are generated in another 1:1 relationship between | |
| * tables and classes, so N tables will generate N * (1DAO + 1DTO) [2N] files. | |
| * | |
| * All classes are named after ZF namespace naming convention, using a default module | |
| * name, e.g., if you have a "user" table, the two classes created will be: | |
| * "Application_Model_User" and "Application_Model_UserMapper" (DTO and DAO, | |
| * respectivelly). | |
| * | |
| * Both classes implement a minimal set of methods (for DTOs, all accessor methods and | |
| * for DAOs none, actually) and inherits from abstract classes that should implement | |
| * common logic. Sample abstract classes of both kinds are provided in this gist too. | |
| * | |
| * Command-line usage and options available are poorly written, so you'll probably | |
| * need to edit this script to fit to your needs. | |
| * | |
| * Usage: $ generate-db-models.php <db_user> <db_pass> <db_name> <output_directory> | |
| * | |
| * Those args are pretty self-explanatory. If you use another db or connection method | |
| * (SSL, socket, whatever), edit the line containing the DSN string [3] that looks like | |
| * | |
| * engine://user:pass@host/db_name | |
| * | |
| * This script also uses MySQL-specific SQL queries (like SHOW and DESCRIBE) to inspect | |
| * tables, so you might need to change them to fit others db's needs. | |
| * | |
| * [1] http://en.wikipedia.org/wiki/Data_transfer_object | |
| * [2] http://en.wikipedia.org/wiki/Data_access_object | |
| * [3] http://www.php.net/manual/en/pdo.construct.php ($dsn parameter) | |
| * | |
| */ | |
| require_once("util.php"); | |
| $tables = array(); | |
| $models = array(); | |
| $user = $_SERVER['argv'][1]; | |
| $pass = $_SERVER['argv'][2]; | |
| $database = $_SERVER['argv'][3]; | |
| $outdir = $_SERVER['argv'][4]; | |
| $dbh = new PDO("mysql:host=localhost;dbname=$database", $user, $pass); | |
| foreach($dbh->query("SHOW TABLES") as $tblrow) { | |
| $table = $tblrow[0]; | |
| $models[$table] = camelize($table); | |
| $tables[$table] = array(); | |
| print "- $table\n"; | |
| foreach($dbh->query("DESCRIBE $table") as $colrow) { | |
| $col = $colrow['Field']; | |
| $tables[$table][$col] = camelize($col); | |
| print " * $col\n"; | |
| } | |
| } | |
| $dbh = null; | |
| foreach($tables as $table => $cols) { | |
| $model = $models[$table]; | |
| $model_file = <<<EOT | |
| <?php | |
| class Application_Model_${model} extends Application_Model_Abstract | |
| { | |
| EOT; | |
| foreach($cols as $col => $accessor) { | |
| $model_file .= " protected \$_$col;\n"; | |
| } | |
| foreach($cols as $col => $accessor) { | |
| $model_file .= <<<EOT | |
| public function set$accessor(\$value) | |
| { | |
| \$this->_$col = \$value; | |
| return \$this; | |
| } | |
| public function get$accessor() | |
| { | |
| return \$this->_$col; | |
| } | |
| EOT; | |
| } | |
| $model_file .= "}\n\n"; | |
| $mapper_file = <<<EOT | |
| <?php | |
| class Application_Model_${model}Mapper extends Application_Model_AbstractMapper | |
| { | |
| protected \$_modelName = '$model'; | |
| } | |
| EOT; | |
| /* | |
| $mapper_file .= <<<EOT | |
| public function save(Application_Model_$model \$obj) | |
| { | |
| \$data = array( | |
| EOT; | |
| foreach($cols as $col => $accessor) { | |
| $mapper_file .= <<<EOT | |
| '$col' => \$obj->get$accessor(), | |
| EOT; | |
| } | |
| $mapper_file .= <<<EOT | |
| ); | |
| if (null === (\$id = \$obj->getId())) { | |
| unset(\$data['id']); | |
| \$this->getDbTable()->insert(\$data); | |
| } else { | |
| \$this->getDbTable()->update(\$data, array('id = ?' => \$id)); | |
| } | |
| } | |
| public function find(\$id, Application_Model_$model \$obj) | |
| { | |
| \$result = \$this->getDbTable()->find(\$id); | |
| if (0 == count(\$result)) { | |
| return; | |
| } | |
| \$row = \$result->current(); | |
| \$obj->setId(\$row->id) | |
| EOT; | |
| foreach($cols as $col => $accessor) { | |
| if ($col == 'id') { continue; } | |
| $mapper_file .= <<<EOT | |
| ->set$accessor(\$row->$col) | |
| EOT; | |
| } | |
| $mapper_file = rtrim($mapper_file); | |
| $mapper_file .= ";\n }\n\n"; | |
| $mapper_file .= <<<EOT | |
| public function fetchAll() | |
| { | |
| \$resultSet = \$this->getDbTable()->fetchAll(); | |
| \$entries = array(); | |
| foreach (\$resultSet as \$row) { | |
| \$entry = new Application_Model_$model(); | |
| \$entry->setId(\$row->id) | |
| EOT; | |
| foreach($cols as $col => $accessor) { | |
| if ($col == 'id') { continue; } | |
| $mapper_file .= <<<EOT | |
| ->set$accessor(\$row->$col) | |
| EOT; | |
| } | |
| $mapper_file = rtrim($mapper_file); | |
| $mapper_file .= ";\n"; | |
| $mapper_file .= <<<EOT | |
| \$entries[] = \$entry; | |
| } | |
| return \$entries; | |
| } | |
| } | |
| EOT; | |
| */ | |
| $fd = fopen(implode(DIRECTORY_SEPARATOR, array($outdir, "${model}.php")), 'w'); | |
| fwrite($fd, $model_file); | |
| fclose($fd); | |
| $fd = fopen(implode(DIRECTORY_SEPARATOR, array($outdir, "${model}Mapper.php")), 'w'); | |
| fwrite($fd, $mapper_file); | |
| fclose($fd); | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <?php | |
| function camelize($str) | |
| { | |
| return implode('', explode(' ', ucwords(implode(' ', explode('_', $str))))); | |
| } | |
| function underline($str) | |
| { | |
| $words = array(); | |
| $split = preg_split('/([A-Z])/', $str, -1, PREG_SPLIT_DELIM_CAPTURE|PREG_SPLIT_NO_EMPTY); | |
| for ($i = 0; $i < count($split); $i += 2) { | |
| $words[] = strtolower($split[$i] . $split[$i+1]); | |
| } | |
| return implode('_', $words); | |
| } | |
| ?> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment