DescriptionMatchFinder::getEntityIdsFromResult()   A
last analyzed

Complexity

Conditions 3
Paths 3

Size

Total Lines 14
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 14
rs 9.4285
c 0
b 0
f 0
cc 3
eloc 7
nc 3
nop 1
1
<?php
2
3
namespace Wikibase\QueryEngine\SQLStore\Engine;
4
5
use Ask\Language\Description\Description;
6
use Ask\Language\Description\SomeProperty;
7
use Ask\Language\Description\ValueDescription;
8
use Ask\Language\Option\QueryOptions;
9
use Doctrine\DBAL\Connection;
10
use Doctrine\DBAL\DBALException;
11
use Doctrine\DBAL\Query\QueryBuilder;
12
use InvalidArgumentException;
13
use Iterator;
14
use Wikibase\DataModel\Entity\EntityId;
15
use Wikibase\DataModel\Entity\EntityIdParser;
16
use Wikibase\DataModel\Entity\EntityIdParsingException;
17
use Wikibase\DataModel\Entity\EntityIdValue;
18
use Wikibase\DataModel\Entity\PropertyId;
19
use Wikibase\QueryEngine\PropertyDataValueTypeLookup;
20
use Wikibase\QueryEngine\QueryEngineException;
21
use Wikibase\QueryEngine\QueryNotSupportedException;
22
use Wikibase\QueryEngine\SQLStore\DataValueHandler;
23
use Wikibase\QueryEngine\SQLStore\StoreSchema;
24
25
/**
26
 * Simple query engine that works on top of the SQLStore.
27
 *
28
 * @since 0.1
29
 *
30
 * @licence GNU GPL v2+
31
 * @author Jeroen De Dauw < [email protected] >
32
 */
33
class DescriptionMatchFinder {
34
35
	private $connection;
36
	private $schema;
37
	private $propertyDataValueTypeLookup;
38
	private $idParser;
39
40
	/**
41
	 * @var QueryBuilder
42
	 */
43
	private $queryBuilder;
44
45
	public function __construct(
46
		Connection $connection,
47
		StoreSchema $schema,
48
		PropertyDataValueTypeLookup $propertyDataValueTypeLookup,
49
		EntityIdParser $idParser
50
	) {
51
		$this->connection = $connection;
52
		$this->schema = $schema;
53
		$this->propertyDataValueTypeLookup = $propertyDataValueTypeLookup;
54
		$this->idParser = $idParser;
55
	}
56
57
	/**
58
	 * Finds all entities that match the selection criteria.
59
	 * The matching entities are returned as an array of internal entity ids.
60
	 *
61
	 * @param Description $description
62
	 * @param QueryOptions $options
63
	 *
64
	 * @return EntityId[]
65
	 * @throws QueryNotSupportedException
66
	 */
67
	public function findMatchingEntities( Description $description, QueryOptions $options ) {
68
		$this->queryBuilder = new QueryBuilder( $this->connection );
69
70
		if ( $description instanceof SomeProperty ) {
71
			return $this->findMatchingSomeProperty( $description, $options );
72
		}
73
74
		throw new QueryNotSupportedException( $description );
75
	}
76
77
	/**
78
	 * @param SomeProperty $description
79
	 * @param QueryOptions $options
80
	 *
81
	 * @return EntityId[]
82
	 * @throws InvalidArgumentException
83
	 * @throws QueryNotSupportedException
84
	 */
85
	private function findMatchingSomeProperty( SomeProperty $description, QueryOptions $options ) {
86
		$subDescription = $description->getSubDescription();
87
88
		if ( !( $subDescription instanceof ValueDescription ) ) {
89
			throw new QueryNotSupportedException( $description );
90
		}
91
92
		$this->addPropertyAndValueDescription(
93
			$this->getPropertyIdFrom( $description ),
94
			$subDescription
95
		);
96
97
		$this->addOptions( $options );
98
99
		return $this->getEntityIdsFromResult( $this->getResultFromQueryBuilder() );
0 ignored issues
show
Documentation introduced by
$this->getResultFromQueryBuilder() is of type object<Doctrine\DBAL\Driver\Statement>|integer, but the function expects a object<Iterator>|array<integer,array>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
100
	}
101
102
	/**
103
	 * @param SomeProperty $description
104
	 *
105
	 * @throws InvalidArgumentException
106
	 * @return PropertyId
107
	 */
108
	private function getPropertyIdFrom( SomeProperty $description ) {
109
		$propertyId = $description->getPropertyId();
110
111
		if ( !( $propertyId instanceof EntityIdValue ) ) {
112
			throw new InvalidArgumentException( 'All property ids provided to the SQLStore should be EntityIdValue objects' );
113
		}
114
115
		return $propertyId->getEntityId();
116
	}
117
118
	private function addOptions( QueryOptions $options ) {
119
		$this->queryBuilder->setMaxResults( $options->getLimit() );
120
		$this->queryBuilder->setFirstResult( $options->getOffset() );
121
	}
122
123
	private function addPropertyAndValueDescription( PropertyId $propertyId, ValueDescription $description ) {
124
		$dvHandler = $this->getDataValueHandlerFor( $propertyId );
125
126
		$this->addFieldsToSelect(
127
			$this->queryBuilder,
128
			array( 'subject_id' ),
129
			$dvHandler
130
		);
131
132
		$this->queryBuilder->andWhere( 'property_id = :property_id' );
133
		$this->queryBuilder->setParameter( ':property_id', $propertyId->getSerialization() );
134
135
		$dvHandler->addMatchConditions( $this->queryBuilder, $description );
136
	}
137
138
	private function getDataValueHandlerFor( PropertyId $propertyId ) {
139
		$dataTypeId = $this->propertyDataValueTypeLookup->getDataValueTypeForProperty( $propertyId );
140
141
		return $this->schema->getDataValueHandlers()->getMainSnakHandler( $dataTypeId );
142
	}
143
144
	private function addFieldsToSelect( QueryBuilder $builder, array $fieldNames, DataValueHandler $dvHandler ) {
145
		foreach ( $fieldNames as $fieldName ) {
146
			$builder->select( $fieldName );
147
		}
148
149
		$builder->from( $dvHandler->getTableName() );
150
	}
151
152
	private function getResultFromQueryBuilder() {
153
		try {
154
			return $this->queryBuilder->execute();
155
		}
156
		catch ( DBALException $ex ) {
157
			throw new QueryEngineException( $ex->getMessage(), $ex->getCode(), $ex );
158
		}
159
	}
160
161
	/**
162
	 * @param Iterator|array[] $resultRows
163
	 *
164
	 * @return EntityId[]
165
	 */
166
	private function getEntityIdsFromResult( $resultRows ) {
167
		$entityIds = array();
168
169
		foreach ( $resultRows as $resultRow ) {
170
			try {
171
				$entityIds[] = $this->idParser->parse( $resultRow['subject_id'] );
172
			}
173
			catch ( EntityIdParsingException $ex ) {
174
				// Reporting invalid IDs would not be helpful at this point, just skip them.
175
			}
176
		}
177
178
		return $entityIds;
179
	}
180
181
}
182