22namespace de \interaapps \ulole \orm ;
33
44use de \interaapps \ulole \orm \migration \Blueprint ;
5+ use PDO ;
6+ use PDOStatement ;
57
68class Database {
7- private $ connection ;
9+ private PDO $ connection ;
810
11+ private const PHP_SQL_TYPES = [
12+ "int " => "INTEGER " ,
13+ "float " => "FLOAT " ,
14+ "string " => "TEXT " ,
15+ "bool " => "TINYINT "
16+ ];
17+
18+ /**
19+ * @param $username
20+ * @param $password
21+ * @param $database
22+ * @param $host
23+ * @param $port
24+ * @param $driver
25+ * @throws \PDOException
26+ */
927 public function __construct ($ username , $ password =false , $ database =false ,$ host ='localhost ' ,$ port =3306 , $ driver ="mysql " ) {
1028 if ($ driver =="sqlite " )
11- $ this ->connection = new \ PDO ($ driver .': ' .$ database );
29+ $ this ->connection = new PDO ($ driver .': ' .$ database );
1230 else
13- $ this ->connection = new \ PDO ($ driver .':host= ' .$ host .';dbname= ' .$ database , $ username , $ password );
31+ $ this ->connection = new PDO ($ driver .':host= ' .$ host .';dbname= ' .$ database , $ username , $ password );
1432 }
1533
16- public function getConnection (){
34+ public function getConnection () : PDO {
1735 return $ this ->connection ;
1836 }
1937
20- public function create ($ name , $ callable , $ ifNotExists = false ){
38+ public function query ($ sql ) : PDOStatement |bool {
39+ return $ this ->connection ->query ($ sql );
40+ }
41+
42+ public function create ($ name , $ callable , $ ifNotExists = false ) : PDOStatement |bool {
2143 $ blueprint = new Blueprint ();
2244 $ callable ($ blueprint );
2345 $ sql = "CREATE TABLE " .($ ifNotExists ? "IF NOT EXISTS " : "" )."` " .$ name ."` ( \n" ;
2446 $ sql .= implode (", \n" , $ blueprint ->getQueries (true ));
2547 $ sql .= "\n) ENGINE = InnoDB; " ;
2648
27- return $ this ->connection -> query ($ sql );
49+ return $ this ->query ($ sql );
2850 }
2951
30- public function edit ($ name , $ callable ){
52+ public function edit ($ name , $ callable ) : PDOStatement | bool {
3153 $ statement = $ this ->connection ->query ("SHOW COLUMNS FROM " .$ name ."; " );
3254 $ existingColumns = [];
3355 foreach ($ statement ->fetchAll (\PDO ::FETCH_NUM ) as $ row ) {
@@ -51,12 +73,85 @@ public function edit($name, $callable){
5173 }
5274 $ sql .= "; " ;
5375
54- return $ this ->connection -> query ($ sql );
76+ return $ this ->query ($ sql );
5577 }
5678
5779
58- public function drop ($ name ){
59- return $ this ->connection ->query ("DROP TABLE ` " .$ name ."`; " );
80+ public function drop ($ name ) : PDOStatement |bool {
81+ return $ this ->query ("DROP TABLE ` " .$ name ."`; " );
82+ }
83+
84+ public function autoMigrate () {
85+ $ tables = [];
86+ foreach ($ this ->query ("SHOW TABLES; " )->fetchAll () as $ r ) {
87+ $ tables [] = $ r [0 ];
88+ }
89+
90+ foreach (UloleORM::getModelInformationList () as $ modelInformation ) {
91+ $ fields = $ modelInformation ->getFields ();
92+ $ columns = array_map (function ($ field ) use ($ modelInformation ) {
93+ $ type = $ field ->getColumnAttribute ()->sqlType ;
94+ if ($ type == null ) {
95+ if (isset (self ::PHP_SQL_TYPES [$ field ->getType ()->getName ()]))
96+ $ type = self ::PHP_SQL_TYPES [$ field ->getType ()->getName ()];
97+ }
98+
99+ if ($ field ->getColumnAttribute ()->size != null )
100+ $ type .= "( " .$ field ->getColumnAttribute ()->size .") " ;
101+
102+ $ isIdentifier = $ modelInformation ->getIdentifier () == $ field ->getFieldName ();
103+
104+ return [
105+ "field " => $ field ->getFieldName (),
106+ "type " => $ type ,
107+ "hasIndex " => $ field ->getColumnAttribute ()->index ,
108+ "identifier " => $ isIdentifier ,
109+ "query " => "` " . $ field ->getFieldName () . "` "
110+ . $ type
111+ . ($ field ->getType ()->allowsNull () ? '' : ' NOT NULL ' )
112+ . ($ type == 'INTEGER ' && $ isIdentifier ? ' AUTO_INCREMENT ' : '' )
113+ ];
114+ }, $ fields );
115+
116+ $ indexes = array_filter ($ columns , fn ($ c ) => $ c ["hasIndex " ]);
117+
118+ if (in_array ($ modelInformation ->getName (), $ tables )) {
119+ $ existingFields = array_map (fn ($ f ) => $ f [0 ], $ this ->query ('SHOW COLUMNS FROM ' .$ modelInformation ->getName ().'; ' )->fetchAll ());
120+ $ existingIndexes = array_map (fn ($ f ) => $ f [4 ], $ this ->query ('SHOW INDEXES FROM ' .$ modelInformation ->getName ().'; ' )->fetchAll ());
121+
122+ $ q = "ALTER TABLE ` " . $ modelInformation ->getName () . "` " ;
123+ $ changes = [];
124+ foreach ($ columns as $ column ) {
125+ if (in_array ($ column ['field ' ], $ existingFields )) {
126+ $ changes [] = "MODIFY COLUMN " . $ column ["query " ];
127+ } else {
128+ $ changes [] = "ADD " . $ column ["query " ];
129+ }
130+ }
131+ foreach ($ indexes as $ index ) {
132+ $ index = $ index ["field " ];
133+ if (!in_array ($ index , $ existingIndexes ))
134+ $ changes [] = 'ADD INDEX (` ' .$ index .'`); ' ;
135+ }
136+
137+ $ q .= implode (", " , $ changes ) . '; ' ;
138+ $ this ->query ($ q );
139+ } else {
140+ $ q = "CREATE TABLE " . $ modelInformation ->getName () . " ( " .
141+ implode (', ' , array_map (fn ($ c ) =>
142+ $ c ['query ' ]
143+ .($ c ['identifier ' ] ? ' PRIMARY KEY ' : ''
144+ ), $ columns )
145+ );
146+
147+ if (count ($ indexes ) > 0 ) {
148+ $ q .= ", INDEX ( " . implode (", " , array_map (fn ($ c ) => $ c ["field " ], $ indexes )) . ") " ;
149+ }
150+
151+ $ q .= "); " ;
152+ $ this ->query ($ q );
153+ }
154+ }
60155 }
61156
62157}
0 commit comments