|
1
|
|
|
<?php |
|
2
|
|
|
namespace micro\orm\creator; |
|
3
|
|
|
|
|
4
|
|
|
use micro\orm\creator\Model; |
|
5
|
|
|
use micro\orm\creator\Member; |
|
6
|
|
|
use micro\annotations\JoinColumnAnnotation; |
|
7
|
|
|
use micro\cache\CacheManager; |
|
8
|
|
|
use micro\controllers\Startup; |
|
9
|
|
|
use micro\utils\FsUtils; |
|
10
|
|
|
|
|
11
|
|
|
|
|
12
|
|
|
class ModelsCreator { |
|
13
|
|
|
private static $config; |
|
14
|
|
|
private static $pdoObject; |
|
15
|
|
|
private static $tables=array(); |
|
16
|
|
|
private static $classes=array(); |
|
17
|
|
|
|
|
18
|
|
|
private static function init($config){ |
|
19
|
|
|
self::$config=$config["database"]; |
|
20
|
|
|
self::connect($config["database"]); |
|
21
|
|
|
} |
|
22
|
|
|
/** |
|
23
|
|
|
* Réalise la connexion à la base de données |
|
24
|
|
|
*/ |
|
25
|
|
|
private static function connect($config) { |
|
26
|
|
|
try { |
|
27
|
|
|
self::$pdoObject = new \PDO( |
|
28
|
|
|
$config["type"].':host=' . $config["serverName"] . ';dbname=' |
|
29
|
|
|
. $config["dbName"] . ';port:' . $config["port"], |
|
30
|
|
|
$config["user"], $config["password"]); |
|
31
|
|
|
self::$pdoObject->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION); |
|
32
|
|
|
self::$pdoObject->exec("SET CHARACTER SET utf8"); |
|
33
|
|
|
|
|
34
|
|
|
} catch (\PDOException $e) { |
|
35
|
|
|
print "Error!: " . $e->getMessage() . "<br/>"; |
|
36
|
|
|
die(); |
|
|
|
|
|
|
37
|
|
|
} |
|
38
|
|
|
} |
|
39
|
|
|
|
|
40
|
|
|
public static function create($config,$initCache=true,$singleTable=null){ |
|
41
|
|
|
self::init($config); |
|
42
|
|
|
$modelsDir=Startup::getModelsCompletePath(); |
|
43
|
|
|
if(FsUtils::safeMkdir($modelsDir)){ |
|
44
|
|
|
self::$tables=self::getTablesName(); |
|
45
|
|
|
CacheManager::checkCache($config); |
|
46
|
|
|
|
|
47
|
|
|
foreach (self::$tables as $table){ |
|
48
|
|
|
$class=new Model($table,$config["mvcNS"]["models"]); |
|
49
|
|
|
$fieldsInfos=self::getFieldsInfos($table); |
|
50
|
|
|
$keys=self::getPrimaryKeys($table); |
|
51
|
|
|
foreach ($fieldsInfos as $field=>$info){ |
|
52
|
|
|
$member=new Member($field); |
|
53
|
|
|
if(in_array($field, $keys)){ |
|
54
|
|
|
$member->setPrimary(); |
|
55
|
|
|
} |
|
56
|
|
|
$member->setDbType($info); |
|
57
|
|
|
$class->addMember($member); |
|
58
|
|
|
} |
|
59
|
|
|
self::$classes[$table]=$class; |
|
60
|
|
|
} |
|
61
|
|
|
self::createRelations(); |
|
62
|
|
|
if(isset($singleTable)){ |
|
63
|
|
|
self::createOneClass($singleTable,$modelsDir); |
|
64
|
|
|
}else{ |
|
65
|
|
|
foreach (self::$classes as $table=>$class){ |
|
66
|
|
|
$name=$class->getSimpleName(); |
|
67
|
|
|
echo "Creating the {$name} class\n"; |
|
68
|
|
|
self::writeFile($modelsDir.DS.$name.".php", $class); |
|
69
|
|
|
} |
|
70
|
|
|
} |
|
71
|
|
|
if($initCache===true){ |
|
72
|
|
|
CacheManager::initCache($config,"models"); |
|
73
|
|
|
} |
|
74
|
|
|
} |
|
75
|
|
|
} |
|
76
|
|
|
|
|
77
|
|
|
private static function createOneClass($singleTable,$modelsDir){ |
|
78
|
|
|
if(isset(self::$classes[$singleTable])){ |
|
79
|
|
|
$class=self::$classes[$singleTable]; |
|
80
|
|
|
echo "Creating the {$class->getName()} class\n"; |
|
81
|
|
|
self::writeFile($modelsDir.DS.$singleTable.".php", $class); |
|
82
|
|
|
}else{ |
|
83
|
|
|
echo "The {$singleTable} table does not exist in the database\n"; |
|
84
|
|
|
} |
|
85
|
|
|
} |
|
86
|
|
|
|
|
87
|
|
|
private static function createRelations(){ |
|
88
|
|
|
foreach (self::$classes as $table=>$class){ |
|
89
|
|
|
$keys=self::getPrimaryKeys($table); |
|
90
|
|
|
foreach ($keys as $key){ |
|
91
|
|
|
$fks=self::getForeignKeys($table, $key); |
|
92
|
|
|
foreach ($fks as $fk){ |
|
93
|
|
|
$field=strtolower($table); |
|
94
|
|
|
$fkTable=$fk["TABLE_NAME"]; |
|
95
|
|
|
self::$classes[$table]->addOneToMany($fkTable."s",$table, self::$classes[$fkTable]->getName()); |
|
96
|
|
|
self::$classes[$fkTable]->addManyToOne($field, $fk["COLUMN_NAME"], $class->getName()); |
|
97
|
|
|
} |
|
98
|
|
|
} |
|
99
|
|
|
} |
|
100
|
|
|
self::createManyToMany(); |
|
101
|
|
|
} |
|
102
|
|
|
|
|
103
|
|
|
private static function getTableName($classname){ |
|
104
|
|
|
$posSlash=strrpos($classname, '\\'); |
|
105
|
|
|
$tablename=substr($classname, $posSlash+ 1); |
|
106
|
|
|
return lcfirst($tablename); |
|
107
|
|
|
} |
|
108
|
|
|
|
|
109
|
|
|
private static function createManyToMany(){ |
|
110
|
|
|
foreach (self::$classes as $table=>$class){ |
|
111
|
|
|
if($class->isAssociation()===true){ |
|
112
|
|
|
$members=$class->getManyToOneMembers(); |
|
113
|
|
|
if(sizeof($members)==2){ |
|
114
|
|
|
$manyToOne1=$members[0]->getManyToOne(); |
|
115
|
|
|
$manyToOne2=$members[1]->getManyToOne(); |
|
116
|
|
|
$table1=self::getTableName($manyToOne1->className); |
|
117
|
|
|
$table2=self::getTableName($manyToOne2->className); |
|
118
|
|
|
$class1=self::$classes[$table1]; |
|
119
|
|
|
$class2=self::$classes[$table2]; |
|
120
|
|
|
$joinTable1=self::getJoinTableArray($class1, $manyToOne1); |
|
121
|
|
|
$joinTable2=self::getJoinTableArray($class2, $manyToOne2); |
|
122
|
|
|
$class1->addManyToMany($table2."s", $manyToOne2->className, $table1."s", $table,$joinTable1,$joinTable2); |
|
123
|
|
|
$class1->removeMember($table."s"); |
|
124
|
|
|
|
|
125
|
|
|
$class2->addManyToMany($table1."s", $manyToOne1->className, $table2."s", $table,$joinTable2,$joinTable1); |
|
126
|
|
|
$class2->removeMember($table."s"); |
|
127
|
|
|
unset(self::$classes[$table]); |
|
128
|
|
|
}else{ |
|
129
|
|
|
return; |
|
130
|
|
|
} |
|
131
|
|
|
} |
|
132
|
|
|
} |
|
133
|
|
|
} |
|
134
|
|
|
|
|
135
|
|
|
private static function getJoinTableArray(Model $class,JoinColumnAnnotation $joinColumn){ |
|
136
|
|
|
$pk=$class->getPrimaryKey(); |
|
137
|
|
|
$fk=$joinColumn->name; |
|
138
|
|
|
$dFk=$class->getDefaultFk(); |
|
139
|
|
|
if($fk!==$dFk){ |
|
140
|
|
|
if($pk!==null && $fk!==null && $pk!==null) |
|
141
|
|
|
return ["name"=>$fk, "referencedColumnName"=>$pk]; |
|
142
|
|
|
} |
|
143
|
|
|
return []; |
|
144
|
|
|
} |
|
145
|
|
|
|
|
146
|
|
|
private static function getTablesName(){ |
|
147
|
|
|
$sql = 'SHOW TABLES'; |
|
148
|
|
|
$query = self::$pdoObject->query($sql); |
|
149
|
|
|
return $query->fetchAll(\PDO::FETCH_COLUMN); |
|
150
|
|
|
} |
|
151
|
|
|
|
|
152
|
|
|
private static function getFieldsInfos($tableName) { |
|
153
|
|
|
$fieldsInos=array(); |
|
154
|
|
|
$recordset = self::$pdoObject->query("SHOW COLUMNS FROM `{$tableName}`"); |
|
155
|
|
|
$fields = $recordset->fetchAll(\PDO::FETCH_ASSOC); |
|
156
|
|
|
foreach ($fields as $field) { |
|
157
|
|
|
$fieldsInos[$field['Field']] = ["Type"=>$field['Type'],"Nullable"=>$field["Null"]]; |
|
158
|
|
|
} |
|
159
|
|
|
return $fieldsInos; |
|
160
|
|
|
} |
|
161
|
|
|
|
|
162
|
|
|
private static function getPrimaryKeys($tableName){ |
|
163
|
|
|
$fieldkeys=array(); |
|
164
|
|
|
$recordset = self::$pdoObject->query("SHOW KEYS FROM `{$tableName}` WHERE Key_name = 'PRIMARY'"); |
|
165
|
|
|
$keys = $recordset->fetchAll(\PDO::FETCH_ASSOC); |
|
166
|
|
|
foreach ($keys as $key) { |
|
167
|
|
|
$fieldkeys[] = $key['Column_name']; |
|
168
|
|
|
} |
|
169
|
|
|
return $fieldkeys; |
|
170
|
|
|
} |
|
171
|
|
|
|
|
172
|
|
|
private static function getForeignKeys($tableName,$pkName){ |
|
173
|
|
|
$recordset = self::$pdoObject->query("SELECT * |
|
174
|
|
|
FROM |
|
175
|
|
|
information_schema.KEY_COLUMN_USAGE |
|
176
|
|
|
WHERE |
|
177
|
|
|
REFERENCED_TABLE_NAME = '".$tableName."' |
|
178
|
|
|
AND REFERENCED_COLUMN_NAME = '".$pkName."' |
|
179
|
|
|
AND TABLE_SCHEMA = '".self::$config["dbName"]."';"); |
|
180
|
|
|
return $recordset->fetchAll(\PDO::FETCH_ASSOC); |
|
181
|
|
|
} |
|
182
|
|
|
|
|
183
|
|
|
private static function writeFile($filename,$data){ |
|
184
|
|
|
return file_put_contents($filename,$data); |
|
185
|
|
|
} |
|
186
|
|
|
} |
|
187
|
|
|
|
An exit expression should only be used in rare cases. For example, if you write a short command line script.
In most cases however, using an
exitexpression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.