Passed
Push — master ( 088fa8...588638 )
by Aimeos
06:37
created

TablesMigrateSiteid::getPreDependencies()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
c 0
b 0
f 0
nc 1
nop 0
dl 0
loc 3
rs 10
1
<?php
2
3
/**
4
 * @license LGPLv3, https://opensource.org/licenses/LGPL-3.0
5
 * @copyright Aimeos (aimeos.org), 2019-2021
6
 */
7
8
9
namespace Aimeos\MW\Setup\Task;
10
11
12
/**
13
 * Updates site ID columns
14
 */
15
class TablesMigrateSiteid extends \Aimeos\MW\Setup\Task\Base
16
{
17
	private $resources = [
18
		'db-attribute' => [
19
			'mshop_attribute_type', 'mshop_attribute_list_type', 'mshop_attribute_property_type',
20
			'mshop_attribute_list', 'mshop_attribute_property', 'mshop_attribute'
21
		],
22
		'db-cache' => [
23
			'madmin_cache_tag', 'madmin_cache'
24
		],
25
		'db-catalog' => [
26
			'mshop_catalog_list_type', 'mshop_catalog_list', 'mshop_catalog'
27
		],
28
		'db-coupon' => [
29
			'mshop_coupon_code', 'mshop_coupon'
30
		],
31
		'db-customer' => [
32
			'mshop_customer_list_type', 'mshop_customer_property_type', 'mshop_customer_group',
33
			'mshop_customer_property', 'mshop_customer_list', 'mshop_customer_address', 'mshop_customer',
34
		],
35
		'db-job' => [
36
			'madmin_job',
37
		],
38
		'db-locale' => [
39
			'mshop_locale_site', 'mshop_locale',
40
		],
41
		'db-log' => [
42
			'madmin_log',
43
		],
44
		'db-media' => [
45
			'mshop_media_type', 'mshop_media_list_type', 'mshop_media_property_type',
46
			'mshop_media_list', 'mshop_media_property', 'mshop_media'
47
		],
48
		'db-order' => [
49
			'mshop_order_base_product_attr', 'mshop_order_base_service_attr', 'mshop_order_base_coupon',
50
			'mshop_order_base_product', 'mshop_order_base_service', 'mshop_order_base_address',
51
			'mshop_order_base', 'mshop_order_status', 'mshop_order'
52
		],
53
		'db-plugin' => [
54
			'mshop_plugin_type', 'mshop_plugin'
55
		],
56
		'db-price' => [
57
			'mshop_price_type', 'mshop_price_list_type', 'mshop_price_list', 'mshop_price'
58
		],
59
		'db-product' => [
60
			'mshop_index_attribute', 'mshop_index_catalog', 'mshop_index_price', 'mshop_index_supplier', 'mshop_index_text',
61
			'mshop_product_list_type', 'mshop_product_property_type', 'mshop_product_type',
62
			'mshop_product_list', 'mshop_product_property', 'mshop_product'
63
		],
64
		'db-service' => [
65
			'mshop_service_type', 'mshop_service_list_type', 'mshop_service_list', 'mshop_service'
66
		],
67
		'db-stock' => [
68
			'mshop_stock_type', 'mshop_stock'
69
		],
70
		'db-subscription' => [
71
			'mshop_subscription'
72
		],
73
		'db-supplier' => [
74
			'mshop_supplier_list_type', 'mshop_supplier_list', 'mshop_supplier_address', 'mshop_supplier'
75
		],
76
		'db-tag' => [
77
			'mshop_tag_type', 'mshop_tag'
78
		],
79
		'db-text' => [
80
			'mshop_text_type', 'mshop_text_list_type', 'mshop_text_list', 'mshop_text'
81
		],
82
	];
83
84
85
	/**
86
	 * Returns the list of task names which this task depends on.
87
	 *
88
	 * @return string[] List of task names
89
	 */
90
	public function getPreDependencies() : array
91
	{
92
		return ['IndexMigrateTextInnodb'];
93
	}
94
95
96
	/**
97
	 * Returns the list of task names which this task depends on.
98
	 *
99
	 * @return string[] List of task names
100
	 */
101
	public function getPostDependencies() : array
102
	{
103
		return ['TablesCreateMShop'];
104
	}
105
106
107
	/**
108
	 * Executes the task
109
	 */
110
	public function migrate()
111
	{
112
		$this->msg( 'Update "siteid" columns', 0, '' );
113
114
		$this->process( $this->resources );
115
	}
116
117
118
	protected function addLocaleSiteColumn()
119
	{
120
		$rname = 'db-locale';
121
		$table = 'mshop_locale_site';
122
		$schema = $this->getSchema( $rname );
123
124
		if( $schema->columnExists( $table, 'siteid' ) === false )
125
		{
126
			$this->msg( 'Adding "siteid" column to "mshop_locale_site" table', 1 );
127
128
			$dbm = $this->additional->getDatabaseManager();
129
			$conn = $dbm->acquire( $rname );
130
131
			$dbal = $conn->getRawObject();
132
133
			if( !( $dbal instanceof \Doctrine\DBAL\Connection ) ) {
134
				throw new \Aimeos\MW\Setup\Exception( 'Not a DBAL connection' );
135
			}
136
137
			$dbalManager = $dbal->getSchemaManager();
138
			$config = $dbalManager->createSchemaConfig();
139
140
			$tabledef = $dbalManager->listTableDetails( $table );
141
			$newdef = clone $tabledef;
142
			$newdef->addColumn( 'siteid', 'integer', ['default' => 0] );
143
144
			$src = new \Doctrine\DBAL\Schema\Schema( [$tabledef], [], $config );
145
			$dest = new \Doctrine\DBAL\Schema\Schema( [$newdef], [], $config );
146
147
			$this->update( $src, $dest, $rname );
148
			$this->execute( 'UPDATE "mshop_locale_site" SET "siteid"="id"' );
149
150
			$dbm->release( $conn, $rname );
151
152
			$this->status( 'done' );
153
		}
154
	}
155
156
157
	protected function getSites()
158
	{
159
		$map = []; $site = '';
0 ignored issues
show
Unused Code introduced by
The assignment to $site is dead and can be removed.
Loading history...
160
161
		$dbm = $this->additional->getDatabaseManager();
162
		$conn = $dbm->acquire( 'db-locale' );
163
		$tconn = $dbm->acquire( 'db-locale' );
164
165
		$type = \Aimeos\MW\DB\Statement\Base::PARAM_INT;
166
		$roots = $conn->create( 'SELECT id, nleft, nright FROM mshop_locale_site WHERE level = 0' )->execute();
167
168
		while( $root = $roots->fetch() )
169
		{
170
			$sql = 'SELECT id, nleft, nright FROM mshop_locale_site WHERE nleft >= ? and nright <= ? ORDER BY nleft';
171
			$result = $tconn->create( $sql )->bind( 1, $root['nleft'], $type )->bind( 2, $root['nright'], $type )->execute();
172
173
			while( $row = $result->fetch() )
0 ignored issues
show
Unused Code introduced by
The assignment to $row is dead and can be removed.
Loading history...
174
			{
175
				$map[$root['id']] = $root['id'] . '.';
176
				$this->map( $result, $root, $map, $root['id'] . '.' );
177
			}
178
		}
179
180
		$dbm->release( $tconn, 'db-locale' );
181
		$dbm->release( $conn, 'db-locale' );
182
183
		return $map;
184
	}
185
186
187
	protected function isChild( array $row, array $parent )
188
	{
189
		return $row['nleft'] > $parent['nleft'] && $row['nright'] < $parent['nright'];
190
	}
191
192
193
	protected function map( \Aimeos\MW\DB\Result\Iface $result, array $parent, array &$map, string $site )
194
	{
195
		while( $row = $result->fetch() )
196
		{
197
			while( $this->isChild( $row, $parent ) )
198
			{
199
				$map[$row['id']] = $site . $row['id'] . '.';
200
201
				if( ( $row = $this->map( $result, $row, $map, $site . $row['id'] . '.' ) ) === null ) {
202
					return null;
203
				}
204
			}
205
206
			return $row;
207
		}
208
209
		return null;
210
	}
211
212
213
	protected function process( array $resources )
214
	{
215
		if( $this->getSchema( 'db-locale' )->tableExists( 'mshop_locale_site' ) === false ) {
216
			return;
217
		}
218
219
		$this->addLocaleSiteColumn();
220
221
		foreach( $resources as $rname => $tables )
222
		{
223
			$schema = $this->getSchema( $rname );
224
225
			$dbm = $this->additional->getDatabaseManager();
226
			$conn = $dbm->acquire( $rname );
227
228
			$dbal = $conn->getRawObject();
229
230
			if( !( $dbal instanceof \Doctrine\DBAL\Connection ) ) {
231
				throw new \Aimeos\MW\Setup\Exception( 'Not a DBAL connection' );
232
			}
233
234
			$dbalManager = $dbal->getSchemaManager();
235
			$config = $dbalManager->createSchemaConfig();
236
237
			if( $schema->tableExists( 'mshop_locale_site' ) ) { // PostgreSQL workaround
238
				$dbalManager->tryMethod( 'dropForeignKey', 'mshop_locale_site_siteid_key', 'mshop_locale_site' );
239
			}
240
241
			foreach( $tables as $table )
242
			{
243
				$this->msg( sprintf( 'Checking table %1$s', $table ), 1 );
244
				$colname = null;
245
246
				if( $schema->tableExists( $table ) && $schema->columnExists( $table, 'siteid' )
247
					&& $schema->getColumnDetails( $table, 'siteid' )->getDataType() === 'integer'
248
				) {
249
					$colname = 'siteid';
250
				}
251
252
				if( $schema->tableExists( $table ) && $schema->columnExists( $table, 'tsiteid' )
253
					&& $schema->getColumnDetails( $table, 'tsiteid' )->getDataType() === 'integer'
254
				) {
255
					$colname = 'tsiteid';
256
				}
257
258
				if( $colname )
259
				{
260
					$tabledef = $dbalManager->listTableDetails( $table );
261
					$newdef = clone $tabledef;
262
263
					foreach( ['fk_macac_tid_tsid', 'fk_mslocla_siteid', 'fk_msloccu_siteid', 'fk_msloc_siteid'] as $foreignkey )
264
					{
265
						if( $newdef->hasForeignKey( $foreignkey ) ) {
266
							$newdef->removeForeignKey( $foreignkey );
267
						}
268
					}
269
270
					$type = new \Doctrine\DBAL\Types\StringType();
271
					$newdef->changeColumn( $colname, ['type' => $type, 'length' => 255] );
272
273
					$src = new \Doctrine\DBAL\Schema\Schema( [$tabledef], [], $config );
274
					$dest = new \Doctrine\DBAL\Schema\Schema( [$newdef], [], $config );
275
276
					$this->update( $src, $dest, $rname );
277
278
					foreach( $this->getSites() as $siteid => $site )
279
					{
280
						$stmt = $conn->create( sprintf( 'UPDATE "%1$s" SET "%2$s" = ? WHERE "%2$s" = ? OR "%2$s" = \'\'', $table, $colname ) );
281
						$result = $stmt->bind( 1, $site )->bind( 2, $siteid )->execute();
282
					}
283
284
					$this->status( 'done' );
285
				}
286
				else
287
				{
288
					$this->status( 'OK' );
289
				}
290
			}
291
292
			$dbm->release( $conn, $rname );
293
		}
294
	}
295
}
296