Completed
Push — master ( 335380...3837d1 )
by mw
132:18 queued 97:45
created

TableSchemaManager::newPropertyTable()   C

Complexity

Conditions 10
Paths 160

Size

Total Lines 72
Code Lines 34

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 10
eloc 34
nc 160
nop 3
dl 0
loc 72
rs 5.5474
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace SMW\SQLStore;
4
5
use Onoi\MessageReporter\NullMessageReporter;
6
use Onoi\MessageReporter\MessageReporter;
7
use Onoi\MessageReporter\MessageReporterAware;
8
use SMW\SQLStore\TableBuilder\Table;
9
use SMWDataItem as DataItem;
10
11
/**
12
 * @private
13
 *
14
 * Database type agnostic schema installer
15
 *
16
 * @license GNU GPL v2+
17
 * @since 2.5
18
 *
19
 * @author mwjames
20
 */
21
class TableSchemaManager implements MessageReporterAware {
22
23
	/**
24
	 * @var SQLStore
25
	 */
26
	private $store;
27
28
	/**
29
	 * @var TableBuilder
30
	 */
31
	private $tableBuilder;
32
33
	/**
34
	 * @var TableIntegrityChecker
35
	 */
36
	private $tableIntegrityChecker;
37
38
	/**
39
	 * @var MessageReporter
40
	 */
41
	private $messageReporter;
42
43
	/**
44
	 * @var Table[]
45
	 */
46
	private $tables = array();
47
48
	/**
49
	 * @since 2.5
50
	 *
51
	 * @param SQLStore $store
52
	 * @param TableBuilder $tableBuilder
53
	 * @param TableIntegrityChecker $tableIntegrityChecker
54
	 */
55
	public function __construct( SQLStore $store, TableBuilder $tableBuilder, TableIntegrityChecker $tableIntegrityChecker ) {
56
		$this->store = $store;
57
		$this->tableBuilder = $tableBuilder;
58
		$this->tableIntegrityChecker = $tableIntegrityChecker;
59
		$this->messageReporter = new NullMessageReporter();
60
	}
61
62
	/**
63
	 * @see MessageReporterAware::setMessageReporter
64
	 *
65
	 * @since 2.5
66
	 *
67
	 * @param MessageReporter $messageReporter
68
	 */
69
	public function setMessageReporter( MessageReporter $messageReporter ) {
70
		$this->messageReporter = $messageReporter;
71
	}
72
73
	/**
74
	 * @since 2.5
75
	 */
76
	public function create() {
77
78
		$this->messageReporter->reportMessage( "Setting up standard database configuration for SMW ...\n" );
79
		$this->messageReporter->reportMessage( "Selected storage engine is \"SMWSQLStore3\" (or an extension thereof)\n\n" );
80
81
		$this->tableBuilder->setMessageReporter(
82
			$this->messageReporter
83
		);
84
85
		foreach ( $this->getTables() as $table ) {
86
			$this->tableBuilder->create( $table );
87
		}
88
89
		$this->tableIntegrityChecker->setMessageReporter(
90
			$this->messageReporter
91
		);
92
93
		$this->tableIntegrityChecker->checkOnPostCreation( $this->tableBuilder );
94
95
		$this->messageReporter->reportMessage( "\nDatabase initialized successfully.\n" );
96
	}
97
98
	/**
99
	 * @since 2.5
100
	 */
101
	public function drop() {
102
103
		$this->messageReporter->reportMessage( "Deleting all database content and tables generated by SMW ...\n\n" );
104
		$this->messageReporter->reportMessage( "Selected storage engine is \"SMWSQLStore3\" (or an extension thereof)\n\n" );
105
106
		$this->tableBuilder->setMessageReporter(
107
			$this->messageReporter
108
		);
109
110
		foreach ( $this->getTables() as $table ) {
111
			$this->tableBuilder->drop( $table );
112
		}
113
114
		\Hooks::run( 'SMW::SQLStore::AfterDropTablesComplete', array( $this->store, $this->tableBuilder ) );
115
116
		$this->messageReporter->reportMessage( "\nStandard and auxiliary tables with its data have been removed successfully.\n" );
117
	}
118
119
	private function getTables() {
120
121
		$this->addTable( $this->newEntityIdTable() );
122
		$this->addTable( $this->newConceptCacheTable() );
123
		$this->addTable( $this->newQueryLinksTable() );
124
		$this->addTable( $this->newFulltextSearchTable() );
125
		$this->addTable( $this->newPropertyStatisticsTable() );
126
127
		// TODO Replace listed types with something like FieldType::BOOLEAN ...
128
		$dbTypes = array(
129
			'b' => $this->tableBuilder->getStandardFieldType( 'boolean' ),
130
			't' => $this->tableBuilder->getStandardFieldType( 'title' ),
131
			's' => $this->tableBuilder->getStandardFieldType( 'sort' ),
132
			'l' => $this->tableBuilder->getStandardFieldType( 'blob' ),
133
			'f' => $this->tableBuilder->getStandardFieldType( 'double' ),
134
			'i' => $this->tableBuilder->getStandardFieldType( 'integer' ),
135
			'j' => $this->tableBuilder->getStandardFieldType( 'integer unsigned' ),
136
			'u' => $this->tableBuilder->getStandardFieldType( 'usage count' ),
137
			'p' => $this->tableBuilder->getStandardFieldType( 'id' ),
138
			'n' => $this->tableBuilder->getStandardFieldType( 'namespace' ),
139
			'w' => $this->tableBuilder->getStandardFieldType( 'iw' )
140
		);
141
142
		foreach ( $this->store->getPropertyTables() as $propertyTable ) {
143
144
			// Only extensions that aren't setup correctly can force an exception
145
			// and to avoid a failure during setup, ensure that standard tables
146
			// are correctly initialized otherwise SMW can't recover
147
			try {
148
				$diHandler = $this->store->getDataItemHandlerForDIType( $propertyTable->getDiType() );
149
			} catch ( \Exception $e ) {
150
				continue;
151
			}
152
153
			$this->addTable( $this->newPropertyTable( $propertyTable, $diHandler, $dbTypes ) );
154
		}
155
156
		return $this->tables;
157
	}
158
159
	private function newEntityIdTable() {
160
161
		// ID_TABLE
162
		$table = new Table( SQLStore::ID_TABLE );
163
164
		$table->addColumn( 'smw_id', $this->tableBuilder->getStandardFieldType( 'id primary' ) );
0 ignored issues
show
Security Bug introduced by
It seems like $this->tableBuilder->get...FieldType('id primary') targeting SMW\SQLStore\TableBuilder::getStandardFieldType() can also be of type false; however, SMW\SQLStore\TableBuilder\Table::addColumn() does only seem to accept string, did you maybe forget to handle an error condition?
Loading history...
165
		$table->addColumn( 'smw_namespace', $this->tableBuilder->getStandardFieldType( 'namespace' ) . ' NOT NULL' );
166
		$table->addColumn( 'smw_title', $this->tableBuilder->getStandardFieldType( 'title' ) . ' NOT NULL' );
167
		$table->addColumn( 'smw_iw', $this->tableBuilder->getStandardFieldType( 'iw' ) . ' NOT NULL' );
168
		$table->addColumn( 'smw_subobject', $this->tableBuilder->getStandardFieldType( 'title' ) . ' NOT NULL' );
169
		$table->addColumn( 'smw_sortkey', $this->tableBuilder->getStandardFieldType( 'title' ) . ' NOT NULL' );
170
		$table->addColumn( 'smw_proptable_hash', $this->tableBuilder->getStandardFieldType( 'blob' ) );
0 ignored issues
show
Security Bug introduced by
It seems like $this->tableBuilder->getStandardFieldType('blob') targeting SMW\SQLStore\TableBuilder::getStandardFieldType() can also be of type false; however, SMW\SQLStore\TableBuilder\Table::addColumn() does only seem to accept string, did you maybe forget to handle an error condition?
Loading history...
171
172
		$table->addIndex( 'smw_id' );
173
		$table->addIndex( 'smw_id,smw_sortkey' );
174
		$table->addIndex( 'smw_iw' ); // iw match lookup
175
		$table->addIndex( 'smw_title,smw_namespace,smw_iw,smw_subobject' ); // id lookup
176
		$table->addIndex( 'smw_sortkey' ); // select by sortkey (range queries)
177
178
		return $table;
179
	}
180
181
	private function newConceptCacheTable() {
182
183
		// CONCEPT_CACHE_TABLE (member elements (s)->concepts (o) )
0 ignored issues
show
Unused Code Comprehensibility introduced by
37% 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...
184
		$table = new Table( SQLStore::CONCEPT_CACHE_TABLE );
185
186
		$table->addColumn( 's_id', $this->tableBuilder->getStandardFieldType( 'id' ) . ' NOT NULL' );
187
		$table->addColumn( 'o_id', $this->tableBuilder->getStandardFieldType( 'id' ) . ' NOT NULL' );
188
189
		$table->addIndex( 'o_id' );
190
191
		return $table;
192
	}
193
194
	private function newQueryLinksTable() {
195
196
		// QUERY_LINKS_TABLE
197
		$table = new Table( SQLStore::QUERY_LINKS_TABLE );
198
199
		$table->addColumn( 's_id', $this->tableBuilder->getStandardFieldType( 'id' ) . ' NOT NULL' );
200
		$table->addColumn( 'o_id', $this->tableBuilder->getStandardFieldType( 'id' ) . ' NOT NULL' );
201
202
		$table->addIndex( 's_id' );
203
		$table->addIndex( 'o_id' );
204
		$table->addIndex( 's_id,o_id' );
205
206
		return $table;
207
	}
208
209
	private function newFulltextSearchTable() {
0 ignored issues
show
Coding Style introduced by
newFulltextSearchTable uses the super-global variable $GLOBALS which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
210
211
		// FT_SEARCH_TABLE
212
		// TEXT and BLOB is stored off the table with the table just having a pointer
213
		// VARCHAR is stored inline with the table
214
		$table = new Table( SQLStore::FT_SEARCH_TABLE );
215
216
		$table->addColumn( 's_id', $this->tableBuilder->getStandardFieldType( 'id' ) . ' NOT NULL' );
217
		$table->addColumn( 'p_id', $this->tableBuilder->getStandardFieldType( 'id' ) . ' NOT NULL' );
218
		$table->addColumn( 'o_text', 'TEXT' );
219
		$table->addColumn( 'o_sort', $this->tableBuilder->getStandardFieldType( 'title' ) );
0 ignored issues
show
Security Bug introduced by
It seems like $this->tableBuilder->get...ndardFieldType('title') targeting SMW\SQLStore\TableBuilder::getStandardFieldType() can also be of type false; however, SMW\SQLStore\TableBuilder\Table::addColumn() does only seem to accept string, did you maybe forget to handle an error condition?
Loading history...
220
221
		$table->addIndex( 's_id' );
222
		$table->addIndex( 'p_id' );
223
		$table->addIndex( 'o_sort' );
224
		$table->addIndex( array( 'o_text', 'FULLTEXT' ) );
225
226
		$table->addOption(
227
			'ftSearchOptions',
228
			$GLOBALS['smwgFulltextSearchTableOptions']
229
		);
230
231
		return $table;
232
	}
233
234
	private function newPropertyStatisticsTable() {
235
236
		// PROPERTY_STATISTICS_TABLE
237
		$table = new Table( SQLStore::PROPERTY_STATISTICS_TABLE );
238
239
		$table->addColumn( 'p_id', $this->tableBuilder->getStandardFieldType( 'id' ) );
0 ignored issues
show
Security Bug introduced by
It seems like $this->tableBuilder->getStandardFieldType('id') targeting SMW\SQLStore\TableBuilder::getStandardFieldType() can also be of type false; however, SMW\SQLStore\TableBuilder\Table::addColumn() does only seem to accept string, did you maybe forget to handle an error condition?
Loading history...
240
		$table->addColumn( 'usage_count', $this->tableBuilder->getStandardFieldType( 'usage count' ) );
0 ignored issues
show
Security Bug introduced by
It seems like $this->tableBuilder->get...ieldType('usage count') targeting SMW\SQLStore\TableBuilder::getStandardFieldType() can also be of type false; however, SMW\SQLStore\TableBuilder\Table::addColumn() does only seem to accept string, did you maybe forget to handle an error condition?
Loading history...
241
242
		$table->addIndex( array( 'p_id', 'UNIQUE INDEX' ) );
243
		$table->addIndex( 'usage_count' );
244
245
		return $table;
246
	}
247
248
	private function newPropertyTable( $propertyTable, $diHandler, $dbTypes ) {
249
		$addedCustomTypeSignatures = false;
250
251
		// Prepare indexes. By default, property-value tables
252
		// have the following indexes:
253
		//
254
		// sp: getPropertyValues(), getSemanticData(), getProperties()
0 ignored issues
show
Unused Code Comprehensibility introduced by
50% 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...
255
		// po: ask, getPropertySubjects()
256
		//
257
		// The "p" component is omitted for tables with fixed property.
258
		$indexes = array();
259
		if ( $propertyTable->usesIdSubject() ) {
260
			$fieldarray = array(
261
				's_id' => $this->tableBuilder->getStandardFieldType( 'id' ) . ' NOT NULL'
262
			);
263
264
			$indexes['sp'] = 's_id';
265
		} else {
266
			$fieldarray = array(
267
				's_title' => $this->tableBuilder->getStandardFieldType( 'title' ) . ' NOT NULL',
268
				's_namespace' => $this->tableBuilder->getStandardFieldType( 'namespace' ) . ' NOT NULL'
269
			);
270
271
			$indexes['sp'] = 's_title,s_namespace';
272
		}
273
274
		$indexes['po'] = $diHandler->getIndexField();
275
276
		if ( !$propertyTable->isFixedPropertyTable() ) {
277
			$fieldarray['p_id'] = $this->tableBuilder->getStandardFieldType( 'id' ) . ' NOT NULL';
278
			$indexes['po'] = 'p_id,' . $indexes['po'];
279
			$indexes['sp'] = $indexes['sp'] . ',p_id';
280
		}
281
282
		// TODO Special handling; concepts should be handled differently
283
		// in the future. See comments in SMW_DIHandler_Concept.php.
284
		if ( $propertyTable->getDiType() === DataItem::TYPE_CONCEPT ) {
285
			unset( $indexes['po'] );
286
		}
287
288
		$indexes = array_merge( $indexes, $diHandler->getTableIndexes() );
289
		$indexes = array_unique( $indexes );
290
291
		foreach ( $diHandler->getTableFields() as $fieldname => $typeid ) {
292
			// If the type signature is not recognized and the custom signatures have not been added, add them.
293
			if ( !$addedCustomTypeSignatures && !array_key_exists( $typeid, $dbTypes ) ) {
294
295
				// @Depreceated since 2.5
296
				\Hooks::run( 'SMWCustomSQLStoreFieldType', array( &$dbTypes ) );
297
298
				\Hooks::run( 'SMW::SQLStore::AddCustomDatabaseFieldType', array( &$dbTypes ) );
299
				$addedCustomTypeSignatures = true;
300
			}
301
302
			// Only add the type when the signature was recognized, otherwise ignore it silently.
303
			if ( array_key_exists( $typeid, $dbTypes ) ) {
304
				$fieldarray[$fieldname] = $dbTypes[$typeid];
305
			}
306
		}
307
308
		$table = new Table( $propertyTable->getName() );
309
310
		foreach ( $fieldarray as $key => $value ) {
311
			$table->addColumn( $key, $value );
312
		}
313
314
		foreach ( $indexes as $key => $index ) {
315
			$table->addIndexWithKey( $key, $index );
316
		}
317
318
		return $table;
319
	}
320
321
	private function addTable( Table $table ) {
322
		$this->tables[] = $table;
323
	}
324
325
}
326