Completed
Push — master ( f2f6e8...470987 )
by mw
33:59
created

SubSemanticData::removeSubSemanticData()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 16
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 8
nc 4
nop 1
dl 0
loc 16
rs 9.2
c 0
b 0
f 0
1
<?php
2
3
namespace SMW\DataModel;
4
5
use SMW\Exception\SubSemanticDataException;
6
use SMW\SemanticData;
7
use SMW\DIWikiPage;
8
9
/**
10
 * @private
11
 *
12
 * Internal handling of the SubSemanticData container and its subsequent
13
 * add and remove operations.
14
 *
15
 * @license GNU GPL v2+
16
 * @since 2.5
17
 *
18
 * @author Markus Krötzsch
19
 * @author Jeroen De Dauw
20
 * @author mwjames
21
 */
22
class SubSemanticData {
23
24
	/**
25
	 * States whether repeated values should be avoided. Not needing
26
	 * duplicate elimination (e.g. when loading from store) can save some
27
	 * time, especially in subclasses like SMWSqlStubSemanticData, where
28
	 * the first access to a data item is more costy.
29
	 *
30
	 * @note This setting is merely for optimization. The SMW data model
31
	 * never cares about the multiplicity of identical data assignments.
32
	 *
33
	 * @var boolean
34
	 */
35
	private $noDuplicates;
36
37
	/**
38
	 * DIWikiPage object that is the subject of this container.
39
	 * Subjects can never be null (and this is ensured in all methods setting
40
	 * them in this class).
41
	 *
42
	 * @var DIWikiPage
43
	 */
44
	private $subject;
45
46
	/**
47
	 * Semantic data associated to subobjects of the subject of this
48
	 * SMWSemanticData.
49
	 * These key-value pairs of subObjectName (string) =>SMWSemanticData.
50
	 *
51
	 * @since 2.5
52
	 * @var SemanticData[]
53
	 */
54
	private $subSemanticData = array();
55
56
	/**
57
	 * Internal flag that indicates if this semantic data will accept
58
	 * subdata. Semantic data objects that are subdata already do not allow
59
	 * (second level) subdata to be added. This ensures that all data is
60
	 * collected on the top level, and in particular that there is only one
61
	 * way to represent the same data with subdata. This is also useful for
62
	 * diff computation.
63
	 *
64
	 * @var boolean
65
	 */
66
	private $subDataAllowed = true;
0 ignored issues
show
Unused Code introduced by
The property $subDataAllowed is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
67
68
	/**
69
	 * Maximum depth for an recursive sub data assignment
70
	 *
71
	 * @var integer
72
	 */
73
	private $subContainerMaxDepth = 3;
74
75
	/**
76
	 * @var integer
77
	 */
78
	private $subContainerDepthCounter = 0;
0 ignored issues
show
Unused Code introduced by
The property $subContainerDepthCounter is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
79
80
	/**
81
	 * Constructor.
82
	 *
83
	 * @param DIWikiPage $subject to which this data refers
84
	 * @param boolean $noDuplicates stating if duplicate data should be avoided
85
	 */
86
	public function __construct( DIWikiPage $subject, $noDuplicates = true ) {
87
		$this->clear();
88
		$this->subject = $subject;
89
		$this->noDuplicates = $noDuplicates;
90
	}
91
92
	/**
93
	 * This object is added to the parser output of MediaWiki, but it is
94
	 * not useful to have all its data as part of the parser cache since
95
	 * the data is already stored in more accessible format in SMW. Hence
96
	 * this implementation of __sleep() makes sure only the subject is
97
	 * serialised, yielding a minimal stub data container after
98
	 * unserialisation. This is a little safer than serialising nothing:
99
	 * if, for any reason, SMW should ever access an unserialised parser
100
	 * output, then the Semdata container will at least look as if properly
101
	 * initialised (though empty).
102
	 *
103
	 * @return array
104
	 */
105
	public function __sleep() {
106
		return array( 'subject', 'subSemanticData' );
107
	}
108
109
	/**
110
	 * Return subject to which the stored semantic annotations refer to.
111
	 *
112
	 * @return DIWikiPage subject
113
	 */
114
	public function getSubject() {
115
		return $this->subject;
116
	}
117
118
	/**
119
	 * Return the array of subSemanticData objects in form of
120
	 * subobjectName => ContainerSemanticData
121
	 *
122
	 * @since 2.5
123
	 *
124
	 * @return ContainerSemanticData[]
125
	 */
126
	public function getSubSemanticData() {
127
		return $this->subSemanticData;
128
	}
129
130
	/**
131
	 * @since 2.5
132
	 */
133
	public function clear() {
134
		$this->subSemanticData = array();
135
	}
136
137
	/**
138
	 * @since 2.5
139
	 *
140
	 * @param string $subobjectName|null
0 ignored issues
show
Documentation introduced by
There is no parameter named $subobjectName|null. Did you maybe mean $subobjectName?

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...
141
	 *
142
	 * @return boolean
143
	 */
144
	public function hasSubSemanticData( $subobjectName = null ) {
145
146
		if ( $this->subSemanticData === array() || $subobjectName === '' ) {
147
			return false;
148
		}
149
150
		return $subobjectName !== null ? isset( $this->subSemanticData[$subobjectName] ) : true;
151
	}
152
153
	/**
154
	 * Find a particular subobject container using its name as identifier
155
	 *
156
	 * @since 2.5
157
	 *
158
	 * @param string $subobjectName
159
	 *
160
	 * @return ContainerSemanticData|[]
0 ignored issues
show
Documentation introduced by
The doc-type ContainerSemanticData|[] could not be parsed: Unknown type name "" at position 22. [(view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
161
	 */
162
	public function findSubSemanticData( $subobjectName ) {
163
164
		if ( $this->hasSubSemanticData( $subobjectName ) && isset( $this->subSemanticData[$subobjectName] ) ) {
165
			return $this->subSemanticData[$subobjectName];
166
		}
167
168
		return array();
169
	}
170
171
	/**
172
	 * Add data about subobjects
173
	 *
174
	 * Will only work if the data that is added is about a subobject of
175
	 * this SMWSemanticData's subject. Otherwise an exception is thrown.
176
	 * The SMWSemanticData object that is given will belong to this object
177
	 * after the operation; it should not be modified further by the caller.
178
	 *
179
	 * @since 2.5
180
	 *
181
	 * @param SemanticData $semanticData
182
	 *
183
	 * @throws SubSemanticDataException if not adding data about a subobject of this data
184
	 */
185
	public function addSubSemanticData( SemanticData $semanticData ) {
186
187
	//	$semanticData->setLastModified( $this->getLastModified() );
0 ignored issues
show
Unused Code Comprehensibility introduced by
65% 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...
188
		$this->hash = null;
0 ignored issues
show
Bug introduced by
The property hash does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
189
190
		if ( $semanticData->subContainerDepthCounter > $this->subContainerMaxDepth ) {
191
			throw new SubSemanticDataException( "Cannot add further subdata with the depth of {$semanticData->subContainerDepthCounter}. You are trying to add data beyond the max depth of {$this->subContainerMaxDepth} to an SemanticData object." );
192
		}
193
194
		$subobjectName = $semanticData->getSubject()->getSubobjectName();
195
196
		if ( $subobjectName == '' ) {
197
			throw new SubSemanticDataException( "Cannot add data that is not about a subobject." );
198
		}
199
200
		if ( $semanticData->getSubject()->getDBkey() !== $this->getSubject()->getDBkey() ) {
201
			throw new SubSemanticDataException( "Data for a subobject of {$semanticData->getSubject()->getDBkey()} cannot be added to {$this->getSubject()->getDBkey()}." );
202
		}
203
204
		if ( $this->hasSubSemanticData( $subobjectName ) ) {
205
			$this->subSemanticData[$subobjectName]->importDataFrom( $semanticData );
206
207
			foreach ( $semanticData->getSubSemanticData() as $containerSemanticData ) {
208
				$this->addSubSemanticData( $containerSemanticData );
209
			}
210
		} else {
211
			$semanticData->subContainerDepthCounter++;
212
			foreach ( $semanticData->getSubSemanticData() as $containerSemanticData ) {
213
214
				// Skip container that are known to be registered (avoids recursive statement extension)
215
				if ( $this->hasSubSemanticData( $containerSemanticData->getSubject()->getSubobjectName() ) ) {
216
					continue;
217
				}
218
219
				$this->addSubSemanticData( $containerSemanticData );
220
			}
221
222
			$semanticData->clearSubSemanticData();
223
			$this->subSemanticData[$subobjectName] = $semanticData;
224
		}
225
	}
226
227
	/**
228
	* Remove data about a subobject
229
	*
230
	* If the removed data is not about a subobject of this object,
231
	* it will silently be ignored (nothing to remove). Likewise,
232
	* removing data that is not present does not change anything.
233
	*
234
	* @since 2.5
235
	*
236
	* @param SemanticData $semanticData
237
	*/
238
	public function removeSubSemanticData( SemanticData $semanticData ) {
239
240
		if ( $semanticData->getSubject()->getDBkey() !== $this->getSubject()->getDBkey() ) {
241
			return;
242
		}
243
244
		$subobjectName = $semanticData->getSubject()->getSubobjectName();
245
246
		if ( $this->hasSubSemanticData( $subobjectName ) ) {
247
			$this->subSemanticData[$subobjectName]->removeDataFrom( $semanticData );
248
249
			if ( $this->subSemanticData[$subobjectName]->isEmpty() ) {
250
				unset( $this->subSemanticData[$subobjectName] );
251
			}
252
		}
253
	}
254
255
}
256