Passed
Push — master ( 61e57b...69ef8d )
by Jean-Christophe
04:35
created

DbGenerator::generateManyToMany()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 24
Code Lines 21

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 22
CRAP Score 2

Importance

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