Ubiquity  2.0.0
php rapid development framework
DbGenerator.php
Go to the documentation of this file.
1 <?php
2 
4 
8 
9 class DbGenerator {
10  protected $nameProtection;
12  protected $createTableMask;
13  protected $fieldMask;
14  protected $foreignKeyMask;
15  protected $alterTableMask;
16  protected $alterTableAddKey;
17  protected $autoIncMask;
18  protected $selectDbMask;
19  protected $constraintNames=[];
20  protected $sqlScript=[];
21  protected $fieldTypes;
22  protected $defaultType;
23  protected $typeMatch='@([\s\S]*?)((?:\((?:\d)+\))*?)$@';
24  protected $intMatch='@^.*?int.*?((?:\((?:\d)+\))*?)$@';
25  protected $manyToManys=[];
26 
27 
28  public function isInt($fieldType){
29  return \preg_match($this->intMatch, $fieldType);
30  }
31  public function __construct(){
32  $this->nameProtection="`";
33  $this->createDatabaseMask="CREATE DATABASE %name%";
34  $this->selectDbMask="USE %name%";
35  $this->createTableMask="CREATE TABLE %name% (%fields%) %attributes%";
36  $this->fieldMask="%name% %type% %extra%";
37  $this->alterTableMask="ALTER TABLE %tableName% %alter%";
38  $this->foreignKeyMask="ALTER TABLE %tableName% ADD CONSTRAINT %fkName% FOREIGN KEY (%fkFieldName%) REFERENCES %referencesTableName% (%referencesFieldName%) ON DELETE %onDelete% ON UPDATE %onUpdate%";
39  $this->alterTableAddKey="ALTER TABLE %tableName% ADD %type% KEY (%pkFields%)";
40  $this->autoIncMask="ALTER TABLE %tableName% MODIFY %field% AUTO_INCREMENT, AUTO_INCREMENT=%value%";
41  $this->fieldTypes=["tinyint"=>0,"int"=>0,"decimal"=>0,"float"=>0,"double"=>0,"smallint"=>0,"mediumint"=>0,"bigint"=>0,
42  "date"=>"NULL","time"=>"NULL","datetime"=>"CURRENT_TIMESTAMP","timestamp"=>"CURRENT_TIMESTAMP","year"=>"'0000'",
43  "tinytext"=>"NULL","text"=>"NULL","mediumtext"=>"NULL","longtext"=>"NULL",
44  "tinyblob"=>"NULL","blob"=>"NULL","mediumblob"=>"NULL","longblob"=>"NULL",
45  "char"=>"NULL","varchar"=>"NULL","binary"=>"NULL","varbinary"=>"NULL",
46  "enum"=>"''","set"=>"''"
47  ];
48  $this->defaultType="varchar(30)";
49  }
50 
51  public function createDatabase($name){
52  $script= $this->replaceMask("name", $name, $this->createDatabaseMask);
53  return $this->addScript("head", $script);
54  }
55 
56  public function selectDatabase($name){
57  $script= $this->replaceMask("name", $name, $this->selectDbMask);
58  return $this->addScript("head", $script);
59  }
60 
61  public function createTable($name,$fieldsAttributes,$attributes=["ENGINE=InnoDB","DEFAULT CHARSET=utf8"]){
62  $fields=$this->generateFields($fieldsAttributes);
63  $attributes=\implode(" ", $attributes);
64  $script=$this->replaceArrayMask(["name"=>$name,"fields"=>$fields,"attributes"=>$attributes], $this->createTableMask);
65  return $this->addScript("body", $script);
66  }
67 
68  public function addKey($tableName,$fieldNames,$type="PRIMARY"){
69  $pks=[];
70  foreach ($fieldNames as $fieldName){
71  $pks[]=$this->nameProtection.$fieldName.$this->nameProtection;
72  }
73  $script= $this->replaceArrayMask(["tableName"=>$tableName,"pkFields"=>\implode(",", $pks),"type"=>$type], $this->alterTableAddKey);
74  return $this->addScript("before-constraints", $script);
75  }
76 
77  public function addForeignKey($tableName,$fkFieldName,$referencesTableName,$referencesFieldName,$fkName=null,$onDelete="CASCADE",$onUpdate="NO ACTION"){
78  if(!isset($fkName)){
79  $fkName=$this->checkConstraintName("fk_".$tableName."_".$referencesTableName);
80  }
81  $script= $this->replaceArrayMask(["tableName"=>$tableName,"fkName"=>$fkName,"fkFieldName"=>$fkFieldName,"referencesTableName"=>$referencesTableName,"referencesFieldName"=>$referencesFieldName,"onDelete"=>$onDelete,"onUpdate"=>$onUpdate], $this->foreignKeyMask);
82  return $this->addScript("constraints", $script);
83  }
84 
85  public function addAutoInc($tableName,$fieldName,$value=1){
86  $script= $this->replaceArrayMask(["tableName"=>$tableName,"field"=>$fieldName,"value"=>$value], $this->autoIncMask);
87  return $this->addScript("before-constraints", $script);
88  }
89 
90  protected function addScript($key,$script){
91  if(!isset($this->sqlScript[$key])){
92  $this->sqlScript[$key]=[];
93  }
94  $this->sqlScript[$key][]=$script;
95  return $script;
96  }
97 
98  protected function checkConstraintName($name){
99  if(\array_search($name, $this->constraintNames)){
100  $matches=[];
101  if (\preg_match('@([\s\S]*?)((?:\d)+)$@', $name,$matches)) {
102  if(isset($matches[2])){
103  $nb=\intval($matches[2])+1;
104  $name= $matches[1].$nb;
105  }
106  }else{
107  $name= $name."1";
108  }
109  }
110  $this->constraintNames[]=$name;
111  return $name;
112  }
113 
114  public function generateField($fieldAttributes){
115  $fieldAttributes=$this->checkFieldAttributes($fieldAttributes);
116  return $this->replaceArrayMask($fieldAttributes,$this->fieldMask);
117  }
118 
119  protected function checkFieldAttributes($fieldAttributes){
120  $result=$fieldAttributes;
121  $type=$fieldAttributes["type"];
122  $existingType=false;
123  $matches=[];
124  if (\preg_match($this->typeMatch, $type,$matches)) {
125  if(isset($matches[1])){
126  $strType=$matches[1];
127  if(isset($this->fieldTypes[$strType])){
128  if(!isset($fieldAttributes["extra"]) || $fieldAttributes["extra"]=="") {
129  $result["extra"]="DEFAULT ".$this->fieldTypes[$strType];
130  }
131  $existingType=true;
132  }
133  }
134  }
135  if(!$existingType){
136  $result["type"]=$this->defaultType;
137  }
138  return $result;
139  }
140 
141  protected function generateFields($fieldsAttributes){
142  $result=[];
143  foreach ($fieldsAttributes as $fieldAttribute){
144  $result[]=$this->generateField($fieldAttribute);
145  }
146  return \implode(",", $result);
147  }
148 
149  protected function replaceMask($key,$value,$mask){
150  if(\strstr(\strtolower($key),"name"))
151  $value=$this->nameProtection.$value.$this->nameProtection;
152  return \str_replace("%".$key."%", $value, $mask);
153  }
154 
155  protected function replaceArrayMask($keyValues,$mask){
156  foreach ($keyValues as $key=>$value){
157  $mask=$this->replaceMask($key, $value, $mask);
158  }
159  return $mask;
160  }
161 
162  public function getSqlScript() {
163  return $this->sqlScript;
164  }
165 
166  public function addManyToMany($jointable,$targetEntity){
167  if(!isset($this->manyToManys[$jointable])){
168  $this->manyToManys[$jointable]=[];
169  }
170  $this->manyToManys[$jointable][]=$targetEntity;
171  }
172 
173  public function generateManyToManys(){
174  foreach ($this->manyToManys as $joinTable=>$targetEntities){
175  $this->generateManyToMany($joinTable, $targetEntities);
176  }
177  }
178 
179  protected function generateManyToMany($joinTable,$targetEntities){
180  $fields=[];
181  $fieldTypes=[];
182  $manyToOnes=[];
183  $invertedJoinColumns=[];
184  foreach ($targetEntities as $targetEntity){
185  $pk=OrmUtils::getFirstKey($targetEntity);
186  $shortClassName=ClassUtils::getClassSimpleName($targetEntity);
187  $fieldName=$pk.\ucfirst($shortClassName);
188  $fields[]=$fieldName;
189  $type=OrmUtils::getFieldType($targetEntity, $pk);
190  $fieldTypes[$fieldName]=$type;
191  $memberName=\lcfirst($shortClassName);
192  $manyToOnes[]=$memberName;
193  $invertedJoinColumns[$fieldName]=["member"=>$memberName,"className"=>$targetEntity];
194  }
195  $metas=["#tableName"=>$joinTable,"#primaryKeys"=>$fields,"#nullable"=>[],
196  "#notSerializable"=>[],"#fieldTypes"=>$fieldTypes,"#manyToOne"=>$manyToOnes,
197  "#invertedJoinColumn"=>$invertedJoinColumns,"#oneToMany"=>[],"#joinTable"=>[],
198  "#manyToMany"=>[],"#fieldNames"=>$fields
199  ];
200  $tableGenerator=new TableReversor();
201  $tableGenerator->init($metas);
202  $tableGenerator->generateSQL($this);
203  }
204 
205  public function __toString(){
206  $scripts=\array_merge($this->sqlScript["head"],$this->sqlScript["body"]);
207  $scripts=\array_merge($scripts,$this->sqlScript["before-constraints"]);
208  $scripts=\array_merge($scripts,$this->sqlScript["constraints"]);
209  return \implode(";\n", $scripts);
210  }
211 }
generateField($fieldAttributes)
static getFieldType($className, $field)
Definition: OrmUtils.php:92
generateManyToMany($joinTable, $targetEntities)
static getFirstKey($class)
Definition: OrmUtils.php:121
replaceMask($key, $value, $mask)
checkFieldAttributes($fieldAttributes)
addAutoInc($tableName, $fieldName, $value=1)
Definition: DbGenerator.php:85
addForeignKey($tableName, $fkFieldName, $referencesTableName, $referencesFieldName, $fkName=null, $onDelete="CASCADE", $onUpdate="NO ACTION")
Definition: DbGenerator.php:77
generateFields($fieldsAttributes)
addKey($tableName, $fieldNames, $type="PRIMARY")
Definition: DbGenerator.php:68
addManyToMany($jointable, $targetEntity)
createTable($name, $fieldsAttributes, $attributes=["ENGINE=InnoDB","DEFAULT CHARSET=utf8"])
Definition: DbGenerator.php:61
replaceArrayMask($keyValues, $mask)
static getClassSimpleName($classnameWithNamespace)
Definition: ClassUtils.php:129