Completed
Push — master ( 24a86a...771b97 )
by Aimeos
10:31
created

TablesCreateMShop   A

Complexity

Total Complexity 36

Size/Duplication

Total Lines 311
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 12

Importance

Changes 0
Metric Value
dl 0
loc 311
rs 9.52
c 0
b 0
f 0
wmc 36
lcom 1
cbo 12

9 Methods

Rating   Name   Duplication   Size   Complexity  
A getPreDependencies() 0 4 1
A getPostDependencies() 0 4 1
A clean() 0 34 1
A migrate() 0 34 1
B getSchemaObjects() 0 33 7
B setupSchema() 0 50 7
B setup() 0 38 7
B exclude() 0 30 8
A remove() 0 16 3
1
<?php
2
3
/**
4
 * @license LGPLv3, http://opensource.org/licenses/LGPL-3.0
5
 * @copyright Metaways Infosystems GmbH, 2011
6
 * @copyright Aimeos (aimeos.org), 2015-2017
7
 */
8
9
10
namespace Aimeos\MW\Setup\Task;
11
12
13
/**
14
 * Creates all required tables.
15
 */
16
class TablesCreateMShop extends \Aimeos\MW\Setup\Task\Base
17
{
18
	/**
19
	 * Returns the list of task names which this task depends on.
20
	 *
21
	 * @return array List of task names
22
	 */
23
	public function getPreDependencies()
24
	{
25
		return [];
26
	}
27
28
29
	/**
30
	 * Returns the list of task names which depends on this task.
31
	 *
32
	 * @return array List of task names
33
	 */
34
	public function getPostDependencies()
35
	{
36
		return [];
37
	}
38
39
40
	/**
41
	 * Removes old columns and sequences
42
	 */
43
	public function clean()
44
	{
45
		$this->msg( 'Cleaning base tables', 0 );
46
		$this->status( '' );
47
48
		$ds = DIRECTORY_SEPARATOR;
49
50
		$files = array(
51
			'db-locale' => 'default' . $ds . 'schema' . $ds . 'locale.php',
52
			'db-attribute' => 'default' . $ds . 'schema' . $ds . 'attribute.php',
53
			'db-customer' => 'default' . $ds . 'schema' . $ds . 'customer.php',
54
			'db-media' => 'default' . $ds . 'schema' . $ds . 'media.php',
55
			'db-order' => 'default' . $ds . 'schema' . $ds . 'order.php',
56
			'db-plugin' => 'default' . $ds . 'schema' . $ds . 'plugin.php',
57
			'db-price' => 'default' . $ds . 'schema' . $ds . 'price.php',
58
			'db-product' => 'default' . $ds . 'schema' . $ds . 'product.php',
59
			'db-stock' => 'default' . $ds . 'schema' . $ds . 'stock.php',
60
			'db-service' => 'default' . $ds . 'schema' . $ds . 'service.php',
61
			'db-supplier' => 'default' . $ds . 'schema' . $ds . 'supplier.php',
62
			'db-text' => 'default' . $ds . 'schema' . $ds . 'text.php',
63
			'db-coupon' => 'default' . $ds . 'schema' . $ds . 'coupon.php',
64
			'db-catalog' => 'default' . $ds . 'schema' . $ds . 'catalog.php',
65
			'db-tag' => 'default' . $ds . 'schema' . $ds . 'tag.php',
66
		);
67
68
		$this->setupSchema( $files, true );
69
70
		$files = array(
71
			'db-product' => 'default' . $ds . 'schema' . $ds . 'index.php',
72
			'db-order' => 'default' . $ds . 'schema' . $ds . 'subscription.php',
73
		);
74
75
		$this->setupSchema( $files, true );
76
	}
77
78
79
	/**
80
	 * Creates the MShop tables
81
	 */
82
	public function migrate()
83
	{
84
		$this->msg( 'Creating base tables', 0 );
85
		$this->status( '' );
86
87
		$ds = DIRECTORY_SEPARATOR;
88
89
		$files = array(
90
			'db-locale' => 'default' . $ds . 'schema' . $ds . 'locale.php',
91
			'db-attribute' => 'default' . $ds . 'schema' . $ds . 'attribute.php',
92
			'db-customer' => 'default' . $ds . 'schema' . $ds . 'customer.php',
93
			'db-media' => 'default' . $ds . 'schema' . $ds . 'media.php',
94
			'db-order' => 'default' . $ds . 'schema' . $ds . 'order.php',
95
			'db-plugin' => 'default' . $ds . 'schema' . $ds . 'plugin.php',
96
			'db-price' => 'default' . $ds . 'schema' . $ds . 'price.php',
97
			'db-product' => 'default' . $ds . 'schema' . $ds . 'product.php',
98
			'db-stock' => 'default' . $ds . 'schema' . $ds . 'stock.php',
99
			'db-service' => 'default' . $ds . 'schema' . $ds . 'service.php',
100
			'db-supplier' => 'default' . $ds . 'schema' . $ds . 'supplier.php',
101
			'db-text' => 'default' . $ds . 'schema' . $ds . 'text.php',
102
			'db-coupon' => 'default' . $ds . 'schema' . $ds . 'coupon.php',
103
			'db-catalog' => 'default' . $ds . 'schema' . $ds . 'catalog.php',
104
			'db-tag' => 'default' . $ds . 'schema' . $ds . 'tag.php',
105
		);
106
107
		$this->setupSchema( $files );
108
109
		$files = array(
110
			'db-product' => 'default' . $ds . 'schema' . $ds . 'index.php',
111
			'db-order' => 'default' . $ds . 'schema' . $ds . 'subscription.php',
112
		);
113
114
		$this->setupSchema( $files );
115
	}
116
117
118
	/**
119
	 * Returns the schema objects for the given type and relative path
120
	 *
121
	 * @param string $type Schema type, e.g. "table" or "sequence"
122
	 * @param string $relpath Relative path to the scheme file
123
	 * @return \Doctrine\DBAL\Schema\Schema[] Associative list of names as keys and schema objects as values
124
	 */
125
	protected function getSchemaObjects( $type, $relpath )
126
	{
127
		$schemaList = [];
128
		$dbalschema = new \Doctrine\DBAL\Schema\Schema();
129
130
		foreach( $this->getSetupPaths() as $abspath )
131
		{
132
			$filepath = $abspath . DIRECTORY_SEPARATOR . $relpath;
133
134
			if( !file_exists( $filepath ) ) {
135
				continue;
136
			}
137
138
			if( ( $list = include( $filepath ) ) === false ) {
139
				throw new \Aimeos\MW\Setup\Exception( sprintf( 'Unable to get list from file "%1$s"', $filepath ) );
140
			}
141
142
			if( !isset( $list[$type] ) ) {
143
				continue;
144
			}
145
146
			foreach( (array) $list[$type] as $name => $fcn )
147
			{
148
				if( !isset( $schemaList[$name] ) ) {
149
					$schemaList[$name] = clone $dbalschema;
150
				}
151
152
				$schemaList[$name] = $fcn( $schemaList[$name] );
153
			}
154
		}
155
156
		return $schemaList;
157
	}
158
159
160
	/**
161
	 * Creates all required tables from schema if they don't exist
162
	 *
163
	 * @param array $files Associative list of resource names as keys and file paths as values
164
	 * @param boolean $clean True to remove left over columns or indexes, false to keep them untouched
165
	 */
166
	protected function setupSchema( array $files, $clean = false )
167
	{
168
		foreach( $files as $rname => $relpath )
169
		{
170
			$this->msg( 'Using schema from ' . basename( $relpath ), 1 ); $this->status( '' );
171
172
			$dbal = $this->getConnection( $rname )->getRawObject();
173
174
			if( !( $dbal instanceof \Doctrine\DBAL\Connection ) ) {
175
				throw new \Aimeos\MW\Setup\Exception( 'Not a DBAL connection' );
176
			}
177
178
			$dbalManager = $dbal->getSchemaManager();
179
			$platform = $dbal->getDatabasePlatform();
180
			$schema = $this->getSchema( $rname );
181
182
183
			foreach( $this->getSchemaObjects( 'table', $relpath ) as $name => $dbalschema )
184
			{
185
				$this->msg( sprintf( 'Checking table "%1$s": ', $name ), 2 );
186
187
				$table = $dbalManager->listTableDetails( $name );
188
				$tables = ( $table->getColumns() !== [] ? array( $table ) : [] );
189
190
				$tableSchema = new \Doctrine\DBAL\Schema\Schema( $tables );
191
				$schemaDiff = \Doctrine\DBAL\Schema\Comparator::compareSchemas( $tableSchema, $dbalschema );
192
				$stmts = $this->remove( $this->exclude( $schemaDiff, $relpath ), $clean )->toSaveSql( $platform );
193
194
				$this->executeList( $stmts, $rname );
195
				$this->status( 'done' );
196
			}
197
198
			if( $schema->supports( $schema::HAS_SEQUENCES ) )
199
			{
200
				$sequences = $dbalManager->listSequences();
201
202
				foreach( $this->getSchemaObjects( 'sequence', $relpath ) as $name => $dbalschema )
203
				{
204
					$this->msg( sprintf( 'Checking sequence "%1$s": ', $name ), 2 );
205
206
					$seqSchema = new \Doctrine\DBAL\Schema\Schema( [], $sequences );
207
					$schemaDiff = \Doctrine\DBAL\Schema\Comparator::compareSchemas( $seqSchema, $dbalschema );
208
					$stmts = $this->remove( $schemaDiff, $clean )->toSaveSql( $platform );
209
210
					$this->executeList( $stmts, $rname );
211
					$this->status( 'done' );
212
				}
213
			}
214
		}
215
	}
216
217
218
	/**
219
	 * Creates all required tables from SQL statements if they don't exist
220
	 *
221
	 * @param array $files Associative list of resource names as keys and file paths as values
222
	 * @deprecated Use setupSchema() instead
223
	 */
224
	protected function setup( array $files )
225
	{
226
		foreach( $files as $rname => $filepath )
227
		{
228
			$this->msg( 'Using tables from ' . basename( $filepath ), 1 ); $this->status( '' );
229
230
			if( ( $content = file_get_contents( $filepath ) ) === false ) {
231
				throw new \Aimeos\MW\Setup\Exception( sprintf( 'Unable to get content from file "%1$s"', $filepath ) );
232
			}
233
234
			$schema = $this->getSchema( $rname );
235
236
			foreach( $this->getTableDefinitions( $content ) as $name => $sql )
237
			{
238
				$this->msg( sprintf( 'Checking table "%1$s": ', $name ), 2 );
239
240
				if( $schema->tableExists( $name ) !== true ) {
241
					$this->execute( $sql, $rname );
242
					$this->status( 'created' );
243
				} else {
244
					$this->status( 'OK' );
245
				}
246
			}
247
248
			foreach( $this->getIndexDefinitions( $content ) as $name => $sql )
249
			{
250
				$parts = explode( '.', $name );
251
				$this->msg( sprintf( 'Checking index "%1$s": ', $name ), 2 );
252
253
				if( $schema->indexExists( $parts[0], $parts[1] ) !== true ) {
254
					$this->execute( $sql, $rname );
255
					$this->status( 'created' );
256
				} else {
257
					$this->status( 'OK' );
258
				}
259
			}
260
		}
261
	}
262
263
264
	/**
265
	 * Removes excluded indexes from DBAL schema diff
266
	 *
267
	 * @param \Doctrine\DBAL\Schema\SchemaDiff $schemaDiff DBAL schema diff object
268
	 * @param string $relpath Relative path to the scheme file
269
	 * @return \Doctrine\DBAL\Schema\SchemaDiff Modified DBAL schema diff object
270
	 */
271
	private function exclude( \Doctrine\DBAL\Schema\SchemaDiff $schemaDiff, $relpath )
272
	{
273
		foreach( $this->getSetupPaths() as $abspath )
274
		{
275
			$filepath = $abspath . DIRECTORY_SEPARATOR . $relpath;
276
277
			if( !file_exists( $filepath ) ) {
278
				continue;
279
			}
280
281
			if( ( $list = include( $filepath ) ) === false ) {
282
				throw new \Aimeos\MW\Setup\Exception( sprintf( 'Unable to get list from file "%1$s"', $filepath ) );
283
			}
284
285
			if( isset( $list['exclude'] ) )
286
			{
287
				foreach( $schemaDiff->changedTables as $tableDiff )
288
				{
289
					foreach( $tableDiff->removedIndexes as $idx => $index )
290
					{
291
						if( in_array( $index->getName(), $list['exclude'] ) ) {
292
							unset( $tableDiff->removedIndexes[$idx] );
293
						}
294
					}
295
				}
296
			}
297
		}
298
299
		return $schemaDiff;
300
	}
301
302
303
	/**
304
	 * Keeps removed columns and sequences if not in cleanup mode
305
	 *
306
	 * @param \Doctrine\DBAL\Schema\SchemaDiff $schemaDiff DBAL schema diff object
307
	 * @param boolean $clean If old columns and sequences should be removed
308
	 * @return \Doctrine\DBAL\Schema\SchemaDiff Modified DBAL schema diff object
309
	 */
310
	private function remove( \Doctrine\DBAL\Schema\SchemaDiff $schemaDiff, $clean )
311
	{
312
		if( $clean !== true )
313
		{
314
			foreach( $schemaDiff->changedTables as $tableDiff )
315
			{
316
				$tableDiff->removedColumns = [];
317
				$tableDiff->removedIndexes = [];
318
				$tableDiff->renamedIndexes = [];
319
			}
320
321
			$schemaDiff->removedSequences = [];
322
		}
323
324
		return $schemaDiff;
325
	}
326
}
327