Completed
Push — master ( f40723...0452ba )
by mw
90:24 queued 55:06
created

DependencyLinksTableUpdater::getId()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 17
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2

Importance

Changes 0
Metric Value
cc 2
eloc 10
nc 2
nop 2
dl 0
loc 17
ccs 4
cts 4
cp 1
crap 2
rs 9.4285
c 0
b 0
f 0
1
<?php
2
3
namespace SMW\SQLStore\QueryDependency;
4
5
use SMW\DIWikiPage;
6
use SMW\SQLStore\SQLStore;
7
use SMW\Store;
8
9
/**
10
 * @license GNU GPL v2+
11
 * @since 2.4
12
 *
13
 * @author mwjames
14
 */
15
class DependencyLinksTableUpdater {
16
17
	/**
18
	 * @var array
19
	 */
20
	private static $updateList = array();
21
22
	/**
23
	 * @var Store
24
	 */
25
	private $store = null;
26
27
	/**
28
	 * @var Database
29
	 */
30
	private $connection = null;
31
32
	/**
33
	 * @since 2.4
34
	 *
35
	 * @param Store $store
36
	 */
37 186
	public function __construct( Store $store ) {
38 186
		$this->store = $store;
39 186
		$this->connection = $this->store->getConnection( 'mw.db' );
40 186
	}
41
42
	/**
43
	 * @since 2.4
44
	 *
45
	 * @return Store
46
	 */
47 180
	public function getStore() {
48 180
		return $this->store;
49
	}
50
51
	/**
52
	 * @since 2.4
53
	 */
54 2
	public function clear() {
55 2
		self::$updateList = array();
56 2
	}
57
58
	/**
59
	 * @since 2.4
60
	 *
61
	 * @param integer $sid
62
	 * @param array|null $dependencyList
63
	 */
64 71
	public function addToUpdateList( $sid, array $dependencyList = null ) {
65
66 71
		if ( $sid == 0 || $dependencyList === null || $dependencyList === array() ) {
67 69
			return null;
68
		}
69
70 66
		if ( !isset( self::$updateList[$sid] ) ) {
71 66
			return self::$updateList[$sid] = $dependencyList;
72
		}
73
74 60
		self::$updateList[$sid] = array_merge( self::$updateList[$sid], $dependencyList );
75 60
	}
76
77
	/**
78
	 * @since 2.4
79
	 */
80 68
	public function doUpdate() {
81 68
		foreach ( self::$updateList as $sid => $dependencyList ) {
82
83 68
			if ( $dependencyList === array() ) {
84 66
				continue;
85
			}
86
87 66
			$this->updateDependencyList( $sid, $dependencyList );
88 66
			self::$updateList[$sid] = array();
89
		}
90 68
	}
91
92
	/**
93
	 * @since 2.4
94
	 *
95
	 * @param array $dependencyList
0 ignored issues
show
Bug introduced by
There is no parameter named $dependencyList. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
96
	 */
97 72
	public function deleteDependenciesFromList( array $deleteIdList ) {
98
99 72
		wfDebugLog( 'smw', __METHOD__ . ' ' . implode( ' ,', $deleteIdList ) . "\n" );
100
101 72
		$this->connection->beginAtomicTransaction( __METHOD__ );
102
103 72
		$this->connection->delete(
104 72
			SQLStore::QUERY_LINKS_TABLE,
105
			array(
106 72
				's_id' => $deleteIdList
107
			),
108 72
			__METHOD__
109
		);
110
111 72
		$this->connection->endAtomicTransaction( __METHOD__ );
112 72
	}
113
114
	/**
115
	 * @since 2.4
116
	 *
117
	 * @param integer $sid
118
	 * @param array $dependencyList
119
	 */
120 66
	private function updateDependencyList( $sid, array $dependencyList ) {
121
122 66
		$this->connection->beginAtomicTransaction( __METHOD__ );
123
124
		// Before an insert, delete all entries that for the criteria which is
125
		// cheaper then doing an individual upsert or selectRow, this also ensures
126
		// that entries are self-corrected for dependencies matched
127 66
		$this->connection->delete(
128 66
			SQLStore::QUERY_LINKS_TABLE,
129
			array(
130 66
				's_id' => $sid
131
			),
132 66
			__METHOD__
133
		);
134
135 66
		if ( $sid == 0 ) {
136
			return $this->connection->endAtomicTransaction( __METHOD__ );
137
		}
138
139 66
		$inserts = array();
140
141 66
		foreach ( $dependencyList as $dependency ) {
142
143 66
			if ( !$dependency instanceof DIWikiPage ) {
144
				continue;
145
			}
146
147 66
			$oid = $this->getId( $dependency );
148
149
			// If the ID_TABLE didn't contained an valid ID then we create one ourselves
150
			// to ensure that object entities are tracked from the start
151
			// This can happen when a query is added with object reference that have not
152
			// yet been referenced as annotation and therefore do not recognized as
153
			// value annotation
154 66
			if ( $oid < 1 && ( ( $oid = $this->createId( $dependency ) ) < 1 ) ) {
155 10
				continue;
156
			}
157
158 66
			$inserts[$sid . $oid] = array(
159 66
				's_id' => $sid,
160 66
				'o_id' => $oid
161
			);
162
		}
163
164 66
		if ( $inserts === array() ) {
165
			return $this->connection->endAtomicTransaction( __METHOD__ );
166
		}
167
168
		// MW's multi-array insert needs a numeric dimensional array but the key
169
		// was used with a hash to avoid duplicate entries hence the re-copy
170 66
		$inserts = array_values( $inserts );
171
172 66
		wfDebugLog( 'smw', __METHOD__ . ' insert for SID ' . $sid . "\n" );
173
174 66
		$this->connection->insert(
175 66
			SQLStore::QUERY_LINKS_TABLE,
176
			$inserts,
177 66
			__METHOD__
178
		);
179
180 66
		$this->connection->endAtomicTransaction( __METHOD__ );
181 66
	}
182
183
	/**
184
	 * @since 2.4
185
	 *
186
	 * @param DIWikiPage $subject, $subobjectName
0 ignored issues
show
Documentation introduced by
There is no parameter named $subject,. Did you maybe mean $subject?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function. It has, however, found a similar but not annotated parameter which might be a good fit.

Consider the following example. The parameter $ireland is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $ireland
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was changed, but the annotation was not.

Loading history...
187
	 * @param string $subobjectName
188
	 */
189 68
	public function getId( DIWikiPage $subject, $subobjectName = '' ) {
190
191 68
		if ( $subobjectName !== '' ) {
192
			$subject = new DIWikiPage(
193
				$subject->getDBkey(),
194
				$subject->getNamespace(),
195 68
				$subject->getInterwiki(),
196
				$subobjectName
197
			);
198
		}
199
200
		$id = $this->store->getObjectIds()->getIDFor(
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class SMW\Store as the method getObjectIds() does only exist in the following sub-classes of SMW\Store: SMWSQLStore3, SMWSparqlStore, SMW\SPARQLStore\SPARQLStore. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
201
			$subject
202
		);
203
204 13
		return $id;
205
	}
206 13
207 10
	/**
208
	 * @since 2.4
209
	 *
210 3
	 * @param DIWikiPage $subject, $subobjectName
0 ignored issues
show
Documentation introduced by
There is no parameter named $subject,. Did you maybe mean $subject?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function. It has, however, found a similar but not annotated parameter which might be a good fit.

Consider the following example. The parameter $ireland is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $ireland
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was changed, but the annotation was not.

Loading history...
211 3
	 * @param string $subobjectName
212 3
	 */
213 3
	public function createId( DIWikiPage $subject, $subobjectName = '' ) {
214
215 3
		$id = $this->store->getObjectIds()->makeSMWPageID(
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class SMW\Store as the method getObjectIds() does only exist in the following sub-classes of SMW\Store: SMWSQLStore3, SMWSparqlStore, SMW\SPARQLStore\SPARQLStore. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
216
			$subject->getDBkey(),
217
			$subject->getNamespace(),
218 3
			$subject->getInterwiki(),
219
			$subobjectName,
220 3
			false
221
		);
222
223
		wfDebugLog( 'smw', __METHOD__ . " add new {$id} ID for " . $subject->getHash() . " {$subobjectName}" );
224
225
		return $id;
226
	}
227
228
}
229