@@ -14,26 +14,33 @@ public function __construct()
1414 parent ::__construct (self ::$ defaultName );
1515 }
1616
17- public static function isForeignKeyColumn (\ReflectionProperty $ property ) : bool
17+ public static function getForeignKeyReference (\ReflectionProperty $ property ) : ? array
1818 {
1919 if (!\str_contains ($ property ->getName (), '_ ' )) {
20- return false ;
20+ return null ;
2121 }
2222
2323 $ type = $ property ->getType ();
2424
2525 if (!$ type instanceof \ReflectionNamedType || $ type ->isBuiltin ()) {
26- return false ;
26+ return null ;
2727 }
2828
29- $ typeReflection = new \ReflectionClass ($ type ->getName ());
29+ $ class = new \ReflectionClass ($ type ->getName ());
3030
31- return $ typeReflection ->isSubclassOf (\CoolBeans \Contract \PrimaryKey::class);
32- }
31+ if (!$ class ->isSubclassOf (\CoolBeans \Contract \PrimaryKey::class)) {
32+ return null ;
33+ }
3334
34- public static function getForeignKeyFromName (string $ columnName ) : array
35- {
36- $ parts = \explode ('_ ' , $ columnName );
35+ $ foreignKeyAttribute = $ property ->getAttributes (\CoolBeans \Attribute \ForeignKey::class);
36+
37+ if (\count ($ foreignKeyAttribute ) > 0 ) {
38+ $ foreignKey = $ foreignKeyAttribute [0 ]->newInstance ();
39+
40+ return [$ foreignKey ->table , $ foreignKey ->column ];
41+ }
42+
43+ $ parts = \explode ('_ ' , $ property ->getName ());
3744 $ column = \array_pop ($ parts );
3845
3946 return [\implode ('_ ' , $ parts ), $ column ];
@@ -98,57 +105,69 @@ private function generateBean(string $className) : string
98105 $ this ->validateBean ($ bean );
99106
100107 $ beanName = \Infinityloop \Utils \CaseConverter::toSnakeCase ($ bean ->getShortName ());
101- $ toReturn = 'CREATE TABLE ` ' . $ beanName . '`( ' . \PHP_EOL ;
102- $ foreignKeys = [];
103- $ unique = [];
104- $ data = [];
105-
106- $ classUnique = $ this ->getClassUnique ($ bean );
107- $ classIndex = $ this ->getClassIndex ($ bean );
108+ $ columns = [];
109+ $ indexes = $ this ->getClassIndex ($ bean );
110+ $ foreignKeyConstraints = [];
111+ $ uniqueConstraints = $ this ->getClassUnique ($ bean );
112+ $ checkConstraints = $ this ->getClassCheck ($ bean );
108113
109114 foreach ($ bean ->getProperties (\ReflectionProperty::IS_PUBLIC ) as $ property ) {
110115 if (!$ property ->getType () instanceof \ReflectionNamedType) {
111116 continue ;
112117 }
113118
114- $ data [] = [
115- 'name ' => $ this -> getPropertyName ( $ property ) ,
119+ $ columns [] = [
120+ 'name ' => ' ` ' . $ property -> getName () . ' ` ' ,
116121 'dataType ' => $ this ->getDataType ($ property ),
117- 'notNull ' => $ this ->getNotNull ($ property ),
122+ 'notNull ' => $ property ->getType ()->allowsNull () === false
123+ ? 'NOT NULL '
124+ : ' ' ,
118125 'default ' => $ this ->getDefault ($ property , $ bean ),
119126 'comment ' => $ this ->getComment ($ property ),
120127 ];
121128
122- $ foreignKey = $ this ->getForeignKey ($ property , $ bean );
129+ $ foreignKey = $ this ->getForeignKey ($ property );
130+
131+ if (\is_string ($ foreignKey )) {
132+ $ foreignKeyConstraints [] = $ foreignKey ;
133+ }
134+
123135 $ uniqueConstraint = $ this ->getUnique ($ property , $ beanName );
124136
125137 if (\is_string ($ uniqueConstraint )) {
126- $ unique [] = $ uniqueConstraint ;
138+ $ uniqueConstraints [] = $ uniqueConstraint ;
127139 }
128140
129- if (\is_string ($ foreignKey )) {
130- $ foreignKeys [] = $ foreignKey ;
141+ $ checkConstraint = $ this ->getCheck ($ property , $ beanName );
142+
143+ if (\is_string ($ checkConstraint )) {
144+ $ checkConstraints [] = $ checkConstraint ;
131145 }
132146 }
133147
134- $ toReturn .= $ this ->buildTable ($ data );
135- $ toReturn .= $ this ->printSection ($ classIndex );
136- $ toReturn .= $ this ->printSection ($ classUnique );
137- $ toReturn .= $ this ->printSection ($ unique );
138- $ toReturn .= $ this ->printSection ($ foreignKeys );
139- $ toReturn .= \PHP_EOL . ') ' . \PHP_EOL ;
140- $ toReturn .= self ::INDENTATION . $ this ->getTableCharset ($ bean ) . \PHP_EOL ;
141- $ toReturn .= self ::INDENTATION . $ this ->getTableCollation ($ bean );
142- $ toReturn .= $ this ->getTableComment ($ bean );
143- $ toReturn .= '; ' ;
144-
145- return $ toReturn ;
148+ return 'CREATE TABLE ` ' . $ beanName . '`( ' . \PHP_EOL
149+ . $ this ->buildTable ($ columns )
150+ . $ this ->printSection ($ indexes )
151+ . $ this ->printSection ($ foreignKeyConstraints )
152+ . $ this ->printSection ($ uniqueConstraints )
153+ . $ this ->printSection ($ checkConstraints ). \PHP_EOL
154+ . ') ' . \PHP_EOL
155+ . self ::INDENTATION . $ this ->getTableCharset ($ bean ) . \PHP_EOL
156+ . self ::INDENTATION . $ this ->getTableCollation ($ bean )
157+ . $ this ->getTableComment ($ bean )
158+ . '; ' ;
146159 }
147160
148161 private function buildTable (array $ data ) : string
149162 {
150- $ longestNameLength = $ this ->getLongestByType ($ data , 'name ' );
151- $ longestDataTypeLength = $ this ->getLongestByType ($ data , 'dataType ' );
163+ $ longestNameLength = 0 ;
164+ $ longestDataTypeLength = 0 ;
165+
166+ foreach ($ data as $ row ) {
167+ $ longestNameLength = \max (\mb_strlen ($ row ['name ' ]), $ longestNameLength );
168+ $ longestDataTypeLength = \max (\mb_strlen ($ row ['dataType ' ]), $ longestDataTypeLength );
169+ }
170+
152171 $ toReturn = [];
153172
154173 foreach ($ data as $ row ) {
@@ -165,21 +184,6 @@ private function buildTable(array $data) : string
165184 return \implode (', ' . \PHP_EOL , $ toReturn );
166185 }
167186
168- private function getLongestByType (array $ data , string $ type ) : int
169- {
170- $ maxLength = 0 ;
171-
172- foreach ($ data as $ row ) {
173- $ length = \mb_strlen ($ row [$ type ]);
174-
175- if ($ length > $ maxLength ) {
176- $ maxLength = $ length ;
177- }
178- }
179-
180- return $ maxLength ;
181- }
182-
183187 private function getComment (\ReflectionProperty $ property ) : string
184188 {
185189 $ commentAttribute = $ property ->getAttributes (\CoolBeans \Attribute \Comment::class);
@@ -285,13 +289,6 @@ private function getDefault(\ReflectionProperty $property, \ReflectionClass $bea
285289 };
286290 }
287291
288- private function getNotNull (\ReflectionProperty $ property ) : string
289- {
290- return $ property ->getType ()->allowsNull () === false
291- ? 'NOT NULL '
292- : ' ' ;
293- }
294-
295292 private function isBuiltInEnum (\ReflectionProperty $ property ) : bool
296293 {
297294 if (!$ property ->getType ()->isBuiltin ()) {
@@ -347,21 +344,16 @@ private function getDataType(\ReflectionProperty $property) : string
347344 ? $ typeOverride [0 ]->newInstance ()->getType ()
348345 : match ($ type ->getName ()) {
349346 'string ' => 'VARCHAR(255) ' ,
350- \Infinityloop \Utils \Json::class => 'JSON ' ,
351347 'int ' => 'INT(11) ' ,
352348 'float ' => 'DOUBLE ' ,
353349 'bool ' => 'TINYINT(1) ' ,
350+ \Infinityloop \Utils \Json::class => 'JSON ' ,
354351 \CoolBeans \PrimaryKey \IntPrimaryKey::class => 'INT(11) UNSIGNED ' ,
355352 \DateTime::class, \Nette \Utils \DateTime::class => 'DATETIME ' ,
356353 default => throw new \CoolBeans \Exception \DataTypeNotSupported ('Data type ' . $ type ->getName () . ' is not supported. ' ),
357354 };
358355 }
359356
360- private function getPropertyName (\ReflectionProperty $ property ) : string
361- {
362- return '` ' . $ property ->getName () . '` ' ;
363- }
364-
365357 private function getClassUnique (\ReflectionClass $ bean ) : array
366358 {
367359 if (\count ($ bean ->getAttributes (\CoolBeans \Attribute \ClassUniqueConstraint::class)) === 0 ) {
@@ -400,6 +392,11 @@ private function getClassUnique(\ReflectionClass $bean) : array
400392 return $ constrains ;
401393 }
402394
395+ private function getClassCheck (\ReflectionClass $ bean ) : array
396+ {
397+ return [];
398+ }
399+
403400 private function getClassIndex (\ReflectionClass $ bean ) : array
404401 {
405402 if (\count ($ bean ->getAttributes (\CoolBeans \Attribute \ClassIndex::class)) === 0 ) {
@@ -481,6 +478,11 @@ private function getUnique(\ReflectionProperty $property, string $beanName) : ?s
481478 : null ;
482479 }
483480
481+ private function getCheck (\ReflectionProperty $ property , string $ beanName ) : ?string
482+ {
483+ return null ;
484+ }
485+
484486 private function printSection (array $ data ) : string
485487 {
486488 if (\count ($ data ) === 0 ) {
@@ -522,24 +524,16 @@ private function validateBean(\ReflectionClass $bean) : void
522524 }
523525 }
524526
525- private function getForeignKey (\ReflectionProperty $ property, \ ReflectionClass $ bean ) : ?string
527+ private function getForeignKey (\ReflectionProperty $ property ) : ?string
526528 {
527- if (!self ::isForeignKeyColumn ($ property )) {
528- return null ;
529- }
530-
531- $ hasPrimaryKeyAttribute = self ::hasPrimaryKeyAttribute ($ bean );
532- $ attributeColumns = $ hasPrimaryKeyAttribute
533- ? $ bean ->getAttributes (\CoolBeans \Attribute \PrimaryKey::class)[0 ]->newInstance ()->columns
534- : [];
529+ $ reference = self ::getForeignKeyReference ($ property );
535530
536- if ($ property -> getName () === ' id ' || ( $ this -> hasPrimaryKeyAttribute ( $ bean ) && \in_array ( $ property -> getName (), $ attributeColumns , true ) )) {
531+ if (! \is_array ( $ reference )) {
537532 return null ;
538533 }
539534
540- $ foreignKeyAttribute = $ property -> getAttributes (\ CoolBeans \ Attribute \ForeignKey::class) ;
535+ [ $ table , $ column ] = $ reference ;
541536 $ foreignKeyConstraintAttribute = $ property ->getAttributes (\CoolBeans \Attribute \ForeignKeyConstraint::class);
542-
543537 $ foreignKeyConstraintResult = '' ;
544538
545539 if (\count ($ foreignKeyConstraintAttribute ) > 0 ) {
@@ -557,17 +551,6 @@ private function getForeignKey(\ReflectionProperty $property, \ReflectionClass $
557551 $ foreignKeyConstraintResult .= ' ON DELETE ' . \CoolBeans \Attribute \Types \ForeignKeyConstraintType::getDefault ();
558552 }
559553
560- if (\count ($ foreignKeyAttribute ) > 0 ) {
561- $ foreignKey = $ foreignKeyAttribute [0 ]->newInstance ();
562-
563- $ table = $ foreignKey ->table ;
564- $ column = $ foreignKey ->column ;
565- } elseif (\str_contains ($ property ->getName (), '_ ' )) {
566- [$ table , $ column ] = self ::getForeignKeyFromName ($ property ->getName ());
567- } else {
568- return null ;
569- }
570-
571554 return self ::INDENTATION . 'FOREIGN KEY (` ' . $ property ->getName () . '`) REFERENCES ` ' . $ table . '`(` ' . $ column . '`) '
572555 . $ foreignKeyConstraintResult ;
573556 }
0 commit comments