Ubiquity 2.5.2
php rapid development framework
Loading...
Searching...
No Matches
DbGenerator.php
Go to the documentation of this file.
1<?php
3
11
22
23 protected $nameProtection;
24
26
28
29 protected $fieldMask;
30
31 protected $foreignKeyMask;
32
33 protected $alterTableMask;
34
36
37 protected $autoIncMask;
38
39 protected $selectDbMask;
40
42
43 protected $addFieldMask;
44
45 protected $constraintNames = [];
46
47 protected $sqlScript = [];
48
49 protected $fieldTypes;
50
51 protected $defaultType;
52
53 protected $manyToManys = [];
54
55 protected $tablesToCreate;
56
57 protected $migrationMode;
58
59 public function isInt($fieldType) {
60 return DbTypes::isInt($fieldType);
61 }
62
63 public function __construct() {
64 $this->nameProtection = '`';
65 $this->createDatabaseMask = 'CREATE DATABASE {name}';
66 $this->selectDbMask = "USE {name}";
67 $this->createTableMask = 'CREATE TABLE {name} ({fields}) {attributes}';
68 $this->fieldMask = '{name} {type} {extra}';
69 $this->alterTableMask = 'ALTER TABLE {tableName} {alter}';
70 $this->foreignKeyMask = 'ALTER TABLE {tableName} ADD CONSTRAINT {fkName} FOREIGN KEY ({fkFieldName}) REFERENCES {referencesTableName} ({referencesFieldName}) ON DELETE {onDelete% ON UPDATE {onUpdate}';
71 $this->alterTableAddKey = 'ALTER TABLE {tableName} ADD {type} KEY ({pkFields})';
72 $this->autoIncMask = 'ALTER TABLE {tableName} MODIFY {fieldInfos} AUTO_INCREMENT, AUTO_INCREMENT={value}';
73 $this->addFieldMask='ALTER TABLE {tableName} ADD {fieldName} {attributes}';
74 $this->modifyFieldMask='ALTER TABLE {tableName} MODIFY {fieldName} {attributes}';
75 $this->fieldTypes = DbTypes::TYPES;
76 $this->defaultType = DbTypes::DEFAULT_TYPE;
77 }
78
79 public function setDatabaseWrapper(AbstractDbWrapper $wrapper){
80 $this->nameProtection=$wrapper->quote;
81 $this->createDatabaseMask = $wrapper->migrateOperation(DbOperations::CREATE_DATABASE);
82 $this->selectDbMask = $wrapper->migrateOperation(DbOperations::SELECT_DB);
83 $this->createTableMask = $wrapper->migrateOperation(DbOperations::CREATE_TABLE);
84 $this->fieldMask = $wrapper->migrateOperation(DbOperations::FIELD);
85 $this->alterTableMask = $wrapper->migrateOperation(DbOperations::ALTER_TABLE);
86 $this->foreignKeyMask = $wrapper->migrateOperation(DbOperations::FOREIGN_KEY);
87 $this->alterTableAddKey = $wrapper->migrateOperation(DbOperations::ALTER_TABLE_KEY);
88 $this->autoIncMask = $wrapper->migrateOperation(DbOperations::AUTO_INC);
89 $this->addFieldMask=$wrapper->migrateOperation(DbOperations::ADD_FIELD);
90 $this->modifyFieldMask=$wrapper->migrateOperation(DbOperations::MODIFY_FIELD);
91
92 }
93
94 public function setTablesToCreate(array $tables) {
95 $this->tablesToCreate = $tables;
96 }
97
98 public function createDatabase($name) {
99 $script = $this->replaceMask('name', $name, $this->createDatabaseMask);
100 return $this->addScript('head', $script);
101 }
102
103 public function selectDatabase($name) {
104 $script = $this->replaceMask('name', $name, $this->selectDbMask);
105 return $this->addScript('head', $script);
106 }
107
108 public function createTable($name, $fieldsAttributes, $attributes = []) {
109 $fields = $this->generateFields($fieldsAttributes);
110 $attributes = \implode(" ", $attributes);
111 $script = $this->replaceArrayMask([
112 'name' => $name,
113 'fields' => $fields,
114 'attributes' => $attributes
115 ], $this->createTableMask);
116 return $this->addScript('body', $script);
117 }
118
119 public function addKey($tableName, $fieldNames, $type = 'PRIMARY') {
120 $pks = [];
121 foreach ($fieldNames as $fieldName) {
122 $pks[] = $this->nameProtection . $fieldName . $this->nameProtection;
123 }
124 $script = $this->replaceArrayMask([
125 'tableName' => $tableName,
126 'pkFields' => \implode(",", $pks),
127 'type' => $type
128 ], $this->alterTableAddKey);
129 return $this->addScript('before-constraints', $script);
130 }
131
132 public function addForeignKey($tableName, $fkFieldName, $referencesTableName, $referencesFieldName, $fkName = null, $onDelete = 'CASCADE', $onUpdate = 'NO ACTION') {
133 if (! isset($fkName)) {
134 $fkName = $this->checkConstraintName('fk_' . $tableName . '_' . $referencesTableName);
135 }
136 $script = $this->replaceArrayMask([
137 'tableName' => $tableName,
138 'fkName' => $fkName,
139 'fkFieldName' => $fkFieldName,
140 'referencesTableName' => $referencesTableName,
141 'referencesFieldName' => $referencesFieldName,
142 'onDelete' => $onDelete,
143 'onUpdate' => $onUpdate
144 ], $this->foreignKeyMask);
145 return $this->addScript('constraints', $script);
146 }
147
148 public function addAutoInc($tableName, $fieldName,$fieldInfos, $value = 1) {
149 $script = $this->replaceArrayMask([
150 'tableName' => $tableName,
151 'fieldInfos' => $fieldInfos,
152 'fieldName'=>$fieldName,
153 'seqName'=>'seq_'.$tableName,
154 'value' => $value
155 ], $this->autoIncMask);
156 return $this->addScript('before-constraints', $script);
157 }
158
159 public function addField($tableName,$fieldName,$fieldAttributes){
160 $this->addOrUpdateField($tableName,$fieldName,$fieldAttributes,'addFieldMask');
161 }
162
163 public function modifyField($tableName,$fieldName,$fieldAttributes){
164 $this->addOrUpdateField($tableName,$fieldName,$fieldAttributes,'modifyFieldMask');
165 }
166
167 protected function addScript($key, $script) {
168 if (! isset($this->sqlScript[$key])) {
169 $this->sqlScript[$key] = [];
170 }
171 $this->sqlScript[$key][] = $script;
172 return $script;
173 }
174
175 protected function addOrUpdateField($tableName,$fieldName,$fieldAttributes,$part='addFieldMask'){
176 $fieldAttributes=$this->checkFieldAttributes($fieldAttributes,false);
177 $script = $this->replaceArrayMask([
178 'tableName' => $tableName,
179 'fieldName' => $fieldName,
180 'attributes' => \implode(" ", $fieldAttributes)
181 ], $this->{$part});
182 return $this->addScript('body', $script);
183 }
184
185 protected function checkConstraintName($name) {
186 if (\array_search($name, $this->constraintNames)) {
187 $matches = [];
188 if (\preg_match('@([\s\S]*?)((?:\d)+)$@', $name, $matches)) {
189 if (isset($matches[2])) {
190 $nb = \intval($matches[2]) + 1;
191 $name = $matches[1] . $nb;
192 }
193 } else {
194 $name = $name . "1";
195 }
196 }
197 $this->constraintNames[] = $name;
198 return $name;
199 }
200
201 public function generateField($fieldAttributes, $forPk = false) {
202 $fieldAttributes = $this->checkFieldAttributes($fieldAttributes, $forPk);
203 return $this->replaceArrayMask($fieldAttributes, $this->fieldMask);
204 }
205
206 protected function checkFieldAttributes($fieldAttributes, $forPk = false) {
207 $result = $fieldAttributes;
208 $type = $fieldAttributes['type'];
209 $existingType = false;
210 $strType = DbTypes::getType($type);
211 if (isset($strType)) {
212 if (isset($this->fieldTypes[$strType])) {
213 if (! $forPk && (! isset($fieldAttributes['extra']) || $fieldAttributes['extra'] == '')) {
214 $result['extra'] = 'DEFAULT ' . $this->fieldTypes[$strType];
215 }
216 $existingType = true;
217 }
218 }
219 if (! $existingType) {
220 $result['type'] = $this->defaultType;
221 }
222 return $result;
223 }
224
225 protected function generateFields($fieldsAttributes) {
226 $result = [];
227 foreach ($fieldsAttributes as $fieldAttribute) {
228 $result[] = $this->generateField($fieldAttribute);
229 }
230 return \implode(",", $result);
231 }
232
233 protected function replaceMask($key, $value, $mask) {
234 if (\strstr(\strtolower($key), 'name'))
235 $value = $this->nameProtection . $value . $this->nameProtection;
236 return \str_replace('{'.$key.'}', $value, $mask);
237 }
238
239 protected function replaceArrayMask($keyValues, $mask) {
240 foreach ($keyValues as $key => $value) {
241 $mask = $this->replaceMask($key, $value, $mask);
242 }
243 return $mask;
244 }
245
246 public function getSqlScript() {
247 return $this->sqlScript;
248 }
249
250 public function addManyToMany($jointableInfos, $targetEntity) {
251 $jointable=$jointableInfos['name'];
252 if (! isset($this->manyToManys[$jointable])) {
253 $this->manyToManys[$jointable] = [];
254 }
255 $this->manyToManys[$jointable][] = ['targetEntity'=>$targetEntity,'jointableInfos'=>$jointableInfos];
256 }
257
258 public function generateManyToManys() {
259 foreach ($this->manyToManys as $joinTable => $infos) {
260 if ($this->hasToCreateTable($joinTable)) {
261 $this->generateManyToMany($joinTable,$infos);
262 }
263 }
264 }
265
266 public function hasToCreateTable(string $table) {
267 if (\is_array($this->tablesToCreate)) {
268 return \array_search($table, $this->tablesToCreate) !== false;
269 }
271 }
272
273 protected function generateManyToMany($joinTable, $infos) {
274 $fields = [];
275 $fieldTypes = [];
276 $manyToOnes = [];
277 $invertedJoinColumns = [];
278 foreach ($infos as $info) {
279 $targetEntity=$info['targetEntity'];
280 $joinTableInfos=$info['jointableInfos'];
281 $pk = OrmUtils::getFirstKey($targetEntity);
282 $shortClassName = ClassUtils::getClassSimpleName($targetEntity);
283 $fieldName = $joinTableInfos['inverseJoinColumns']['name']??($pk . \ucfirst($shortClassName));
284 $fields[] = $fieldName;
285 $type = OrmUtils::getFieldType($targetEntity, $pk);
286 $fieldTypes[$fieldName] = $type;
287 $memberName = \lcfirst($shortClassName);
288 $manyToOnes[] = $memberName;
289 $invertedJoinColumns[$fieldName] = [
290 "member" => $memberName,
291 "className" => $targetEntity
292 ];
293 }
294 $metas = [
295 '#tableName' => $joinTable,
296 '#primaryKeys' => \array_combine($fields, $fields),
297 '#nullable' => [],
298 '#notSerializable' => [],
299 '#fieldTypes' => $fieldTypes,
300 '#manyToOne' => $manyToOnes,
301 '#invertedJoinColumn' => $invertedJoinColumns,
302 '#oneToMany' => [],
303 '#joinTable' => [],
304 '#manyToMany' => [],
305 '#fieldNames' => $fields,
306 '#memberNames' => $fields
307 ];
308
309 $tableGenerator = new TableReversor();
310 $tableGenerator->init($metas);
311 $tableGenerator->generateSQL($this);
312 }
313
314 public function getScript(): array {
315 $scripts = \array_merge($this->sqlScript['head']??[], $this->sqlScript['body']??[]);
316 if (isset($this->sqlScript['before-constraints'])) {
317 $scripts = \array_merge($scripts, $this->sqlScript['before-constraints']);
318 }
319 if (isset($this->sqlScript['constraints'])) {
320 $scripts = \array_merge($scripts, $this->sqlScript['constraints']);
321 }
322 return $scripts;
323 }
324
325 public function __toString() {
326 $scripts = $this->getScript();
327 if(\count($scripts)>0) {
328 return \implode(";\n", $scripts) . ';';
329 }
330 return '';
331 }
332
336 public function setMigrationMode($migrationMode): void {
337 $this->migrationMode = $migrationMode;
338 }
339
340}
Manipulates class and namespace names Ubiquity\cache$ClassUtils This class is part of Ubiquity.
Ubiquity Generic database class.
Definition Database.php:25
Ubiquity\db\providers$AbstractDbWrapper This class is part of Ubiquity.
migrateOperation(string $operation)
Returns the SQL string for a migration operation.
replaceMask($key, $value, $mask)
createTable($name, $fieldsAttributes, $attributes=[])
generateFields($fieldsAttributes)
setDatabaseWrapper(AbstractDbWrapper $wrapper)
addField($tableName, $fieldName, $fieldAttributes)
addAutoInc($tableName, $fieldName, $fieldInfos, $value=1)
generateManyToMany($joinTable, $infos)
generateField($fieldAttributes, $forPk=false)
addManyToMany($jointableInfos, $targetEntity)
checkFieldAttributes($fieldAttributes, $forPk=false)
modifyField($tableName, $fieldName, $fieldAttributes)
addKey($tableName, $fieldNames, $type='PRIMARY')
addOrUpdateField($tableName, $fieldName, $fieldAttributes, $part='addFieldMask')
replaceArrayMask($keyValues, $mask)
addForeignKey($tableName, $fkFieldName, $referencesTableName, $referencesFieldName, $fkName=null, $onDelete='CASCADE', $onUpdate='NO ACTION')
Manage Databases types.
Definition DbTypes.php:14
static isInt($fieldType)
Definition DbTypes.php:41
static getType($dbType)
Definition DbTypes.php:61
Object/relational mapping utilities.
Definition OrmUtils.php:17