Completed
Push — master ( 489696...eb7080 )
by Jean-Christophe
01:33
created

DbGenerator::isInt()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 0
loc 3
rs 10
cc 1
eloc 2
nc 1
nop 1
1
<?php
2
3
namespace Ubiquity\db\reverse;
4
5
use Ubiquity\orm\reverse\TableReversor;
6
use Ubiquity\orm\OrmUtils;
7
use Ubiquity\cache\ClassUtils;
8
9
class DbGenerator {
10
	protected $nameProtection;
11
	protected $createDatabaseMask;
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
			//$fields[]=$memberName;
0 ignored issues
show
Unused Code Comprehensibility introduced by
84% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
194
			$invertedJoinColumns[$fieldName]=["member"=>$memberName,"className"=>$targetEntity];
195
		}
196
		$metas=["#tableName"=>$joinTable,"#primaryKeys"=>$fields,"#nullable"=>[],
197
				"#notSerializable"=>[],"#fieldTypes"=>$fieldTypes,"#manyToOne"=>$manyToOnes,
198
				"#invertedJoinColumn"=>$invertedJoinColumns,"#oneToMany"=>[],"#joinTable"=>[],
199
				"#manyToMany"=>[],"#fieldNames"=>$fields
200
		];
201
		$tableGenerator=new TableReversor();
202
		$tableGenerator->init($metas);
203
		$tableGenerator->generateSQL($this);
204
	}
205
206
	public function __toString(){
207
		$scripts=\array_merge($this->sqlScript["head"],$this->sqlScript["body"]);
208
		$scripts=\array_merge($scripts,$this->sqlScript["before-constraints"]);
209
		$scripts=\array_merge($scripts,$this->sqlScript["constraints"]);
210
		return \implode(";\n", $scripts);
211
	}
212
}
213