Complex classes like SemanticData often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use SemanticData, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
32 | class SemanticData { |
||
33 | |||
34 | /** |
||
35 | * Returns the last modified timestamp the data were stored to the Store or |
||
36 | * have been fetched from cache. |
||
37 | */ |
||
38 | const OPT_LAST_MODIFIED = 'opt.last.modified'; |
||
39 | |||
40 | /** |
||
41 | * Cache for the localized version of the namespace prefix "Property:". |
||
42 | * |
||
43 | * @var string |
||
44 | */ |
||
45 | static protected $mPropertyPrefix = ''; |
||
46 | |||
47 | /** |
||
48 | * States whether this is a stub object. Stubbing might happen on |
||
49 | * serialisation to save DB space. |
||
50 | * |
||
51 | * @todo Check why this is public and document this here. Or fix it. |
||
52 | * |
||
53 | * @var boolean |
||
54 | */ |
||
55 | public $stubObject; |
||
56 | |||
57 | /** |
||
58 | * Array mapping property keys (string) to arrays of SMWDataItem |
||
59 | * objects. |
||
60 | * |
||
61 | * @var SMWDataItem[] |
||
62 | */ |
||
63 | protected $mPropVals = array(); |
||
64 | |||
65 | /** |
||
66 | * Array mapping property keys (string) to DIProperty objects. |
||
67 | * |
||
68 | * @var DIProperty[] |
||
69 | */ |
||
70 | protected $mProperties = array(); |
||
71 | |||
72 | /** |
||
73 | * States whether the container holds any normal properties. |
||
74 | * |
||
75 | * @var boolean |
||
76 | */ |
||
77 | protected $mHasVisibleProps = false; |
||
78 | |||
79 | /** |
||
80 | * States whether the container holds any displayable predefined |
||
81 | * $mProperties (as opposed to predefined properties without a display |
||
82 | * label). For some settings we need this to decide if a Factbox is |
||
83 | * displayed. |
||
84 | * |
||
85 | * @var boolean |
||
86 | */ |
||
87 | protected $mHasVisibleSpecs = false; |
||
88 | |||
89 | /** |
||
90 | * States whether repeated values should be avoided. Not needing |
||
91 | * duplicate elimination (e.g. when loading from store) can save some |
||
92 | * time, especially in subclasses like SMWSqlStubSemanticData, where |
||
93 | * the first access to a data item is more costy. |
||
94 | * |
||
95 | * @note This setting is merely for optimization. The SMW data model |
||
96 | * never cares about the multiplicity of identical data assignments. |
||
97 | * |
||
98 | * @var boolean |
||
99 | */ |
||
100 | protected $mNoDuplicates; |
||
101 | |||
102 | /** |
||
103 | * DIWikiPage object that is the subject of this container. |
||
104 | * Subjects can never be null (and this is ensured in all methods setting |
||
105 | * them in this class). |
||
106 | * |
||
107 | * @var DIWikiPage |
||
108 | */ |
||
109 | protected $mSubject; |
||
110 | |||
111 | /** |
||
112 | * Semantic data associated to subobjects of the subject of this |
||
113 | * SMWSemanticData. |
||
114 | * These key-value pairs of subObjectName (string) =>SMWSemanticData. |
||
115 | * |
||
116 | * @since 1.8 |
||
117 | * @var SubSemanticData |
||
118 | */ |
||
119 | protected $subSemanticData; |
||
120 | |||
121 | /** |
||
122 | * Internal flag that indicates if this semantic data will accept |
||
123 | * subdata. Semantic data objects that are subdata already do not allow |
||
124 | * (second level) subdata to be added. This ensures that all data is |
||
125 | * collected on the top level, and in particular that there is only one |
||
126 | * way to represent the same data with subdata. This is also useful for |
||
127 | * diff computation. |
||
128 | */ |
||
129 | protected $subDataAllowed = true; |
||
130 | |||
131 | /** |
||
132 | * @var array |
||
133 | */ |
||
134 | protected $errors = array(); |
||
135 | |||
136 | /** |
||
137 | * Cache the hash to ensure a minimal impact in case of repeated usage. Any |
||
138 | * removal or insert action will reset the hash to null to ensure it is |
||
139 | * recreated in corresponds to changed nature of the data. |
||
140 | * |
||
141 | * @var string|null |
||
142 | */ |
||
143 | private $hash = null; |
||
144 | |||
145 | /** |
||
146 | * @var Options |
||
147 | */ |
||
148 | private $options = null; |
||
149 | |||
150 | /** |
||
151 | * This is kept public to keep track of the depth during a recursive processing |
||
152 | * when accessed through the SubSemanticData instance. |
||
153 | * |
||
154 | * @var integer |
||
155 | */ |
||
156 | public $subContainerDepthCounter = 0; |
||
157 | |||
158 | /** |
||
159 | 326 | * Constructor. |
|
160 | 326 | * |
|
161 | 326 | * @param DIWikiPage $subject to which this data refers |
|
162 | 326 | * @param boolean $noDuplicates stating if duplicate data should be avoided |
|
163 | 326 | */ |
|
164 | 326 | public function __construct( DIWikiPage $subject, $noDuplicates = true ) { |
|
170 | |||
171 | /** |
||
172 | * This object is added to the parser output of MediaWiki, but it is |
||
173 | * not useful to have all its data as part of the parser cache since |
||
174 | * the data is already stored in more accessible format in SMW. Hence |
||
175 | * this implementation of __sleep() makes sure only the subject is |
||
176 | * serialised, yielding a minimal stub data container after |
||
177 | * unserialisation. This is a little safer than serialising nothing: |
||
178 | * if, for any reason, SMW should ever access an unserialised parser |
||
179 | 270 | * output, then the Semdata container will at least look as if properly |
|
180 | 270 | * initialised (though empty). |
|
181 | * |
||
182 | * @return array |
||
183 | */ |
||
184 | public function __sleep() { |
||
187 | |||
188 | 302 | /** |
|
189 | 302 | * Return subject to which the stored semantic annotations refer to. |
|
190 | * |
||
191 | * @return DIWikiPage subject |
||
192 | */ |
||
193 | public function getSubject() { |
||
196 | |||
197 | 300 | /** |
|
198 | 300 | * Get the array of all properties that have stored values. |
|
199 | 300 | * |
|
200 | * @return array of DIProperty objects |
||
201 | */ |
||
202 | public function getProperties() { |
||
206 | |||
207 | /** |
||
208 | * @since 2.4 |
||
209 | 268 | * |
|
210 | 268 | * @param DIProperty $property |
|
211 | * |
||
212 | * @return boolean |
||
213 | */ |
||
214 | public function hasProperty( DIProperty $property ) { |
||
217 | |||
218 | /** |
||
219 | 295 | * Get the array of all stored values for some property. |
|
220 | 295 | * |
|
221 | 1 | * @param DIProperty $property |
|
222 | * @return SMWDataItem[] |
||
223 | */ |
||
224 | 295 | public function getPropertyValues( DIProperty $property ) { |
|
235 | |||
236 | /** |
||
237 | * @since 2.5 |
||
238 | 89 | * |
|
239 | 89 | * @param string $key |
|
240 | * |
||
241 | * @return mixed |
||
242 | */ |
||
243 | public function getOption( $key ) { |
||
251 | 41 | ||
252 | /** |
||
253 | * @since 2.5 |
||
254 | * |
||
255 | * @param string $key |
||
256 | * @param string $value |
||
257 | */ |
||
258 | public function setOption( $key, $value ) { |
||
266 | 13 | ||
267 | /** |
||
268 | 13 | * Returns collected errors occurred during processing |
|
269 | * |
||
270 | * @since 1.9 |
||
271 | * |
||
272 | 13 | * @return array |
|
273 | */ |
||
274 | public function getErrors() { |
||
277 | |||
278 | /** |
||
279 | * Adds an error array |
||
280 | * |
||
281 | * @since 1.9 |
||
282 | 301 | * |
|
283 | * @return array|string |
||
284 | */ |
||
285 | 301 | public function addError( $error ) { |
|
288 | |||
289 | 301 | /** |
|
290 | * Generate a hash value to simplify the comparison of this data |
||
291 | * container with other containers. Subdata is taken into account. |
||
292 | * |
||
293 | * The hash uses PHP's md5 implementation, which is among the fastest |
||
294 | 301 | * hash algorithms that PHP offers. |
|
295 | * |
||
296 | * @note This function may be used to obtain keys for SemanticData |
||
297 | * objects or to do simple equality tests. Equal hashes with very |
||
298 | * high probability indicate equal data. |
||
299 | * |
||
300 | * @return string |
||
301 | */ |
||
302 | 326 | public function getHash() { |
|
310 | |||
311 | /** |
||
312 | * @see SubSemanticData::getSubSemanticData |
||
313 | * |
||
314 | * @since 1.8 |
||
315 | 26 | * |
|
316 | 26 | * @return ContainerSemanticData[] |
|
317 | */ |
||
318 | public function getSubSemanticData() { |
||
332 | |||
333 | /** |
||
334 | * @since 2.5 |
||
335 | */ |
||
336 | public function clearSubSemanticData() { |
||
344 | 293 | ||
345 | /** |
||
346 | 293 | * Return true if there are any visible properties. |
|
347 | * |
||
348 | 293 | * @note While called "visible" this check actually refers to the |
|
349 | 175 | * function DIProperty::isShown(). The name is kept for |
|
350 | 174 | * compatibility. |
|
351 | * |
||
352 | * @return boolean |
||
353 | 293 | */ |
|
354 | public function hasVisibleProperties() { |
||
357 | 293 | ||
358 | 293 | /** |
|
359 | 293 | * Return true if there are any special properties that can |
|
360 | * be displayed. |
||
361 | * |
||
362 | 293 | * @note While called "visible" this check actually refers to the |
|
363 | 293 | * function DIProperty::isShown(). The name is kept for |
|
364 | * compatibility. |
||
365 | * |
||
366 | * @return boolean |
||
367 | */ |
||
368 | 293 | public function hasVisibleSpecialProperties() { |
|
371 | 264 | ||
372 | /** |
||
373 | * Store a value for a property identified by its SMWDataItem object. |
||
374 | 245 | * |
|
375 | * @note There is no check whether the type of the given data item |
||
376 | * agrees with the type of the property. Since property types can |
||
377 | * change, all parts of SMW are prepared to handle mismatched data item |
||
378 | 293 | * types anyway. |
|
379 | 217 | * |
|
380 | 139 | * @param $property DIProperty |
|
381 | 139 | * @param $dataItem SMWDataItem |
|
382 | */ |
||
383 | public function addPropertyObjectValue( DIProperty $property, SMWDataItem $dataItem ) { |
||
429 | |||
430 | 34 | /** |
|
431 | * Store a value for a given property identified by its text label |
||
432 | 34 | * (without namespace prefix). |
|
433 | * |
||
434 | * @param $propertyName string |
||
435 | 34 | * @param $dataItem SMWDataItem |
|
436 | */ |
||
437 | public function addPropertyValue( $propertyName, SMWDataItem $dataItem ) { |
||
459 | |||
460 | /** |
||
461 | * @since 1.9 |
||
462 | * |
||
463 | * @param SMWDataValue $dataValue |
||
464 | */ |
||
465 | public function addDataValue( SMWDataValue $dataValue ) { |
||
486 | 7 | ||
487 | /** |
||
488 | * @since 2.1 |
||
489 | * |
||
490 | 7 | * @param Subobject $subobject |
|
491 | */ |
||
492 | 7 | public function addSubobject( Subobject $subobject ) { |
|
498 | |||
499 | /** |
||
500 | * Remove a value for a property identified by its SMWDataItem object. |
||
501 | * This method removes a property-value specified by the property and |
||
502 | 7 | * dataitem. If there are no more property-values for this property it |
|
503 | 7 | * also removes the property from the mProperties. |
|
504 | 7 | * |
|
505 | * @note There is no check whether the type of the given data item |
||
506 | 7 | * agrees with the type of the property. Since property types can |
|
507 | * change, all parts of SMW are prepared to handle mismatched data item |
||
508 | * types anyway. |
||
509 | * |
||
510 | * @param $property DIProperty |
||
511 | 326 | * @param $dataItem SMWDataItem |
|
512 | 326 | * |
|
513 | 326 | * @since 1.8 |
|
514 | 326 | */ |
|
515 | 326 | public function removePropertyObjectValue( DIProperty $property, SMWDataItem $dataItem ) { |
|
550 | |||
551 | 13 | /** |
|
552 | * Removes a property and all the values associated with this property. |
||
553 | * |
||
554 | * @since 2.5 |
||
555 | 13 | * |
|
556 | 13 | * @param $property DIProperty |
|
557 | 3 | */ |
|
558 | 3 | public function removeProperty( DIProperty $property ) { |
|
584 | |||
585 | /** |
||
586 | * Delete all data other than the subject. |
||
587 | */ |
||
588 | public function clear() { |
||
598 | 3 | ||
599 | 3 | /** |
|
600 | 3 | * Return true if this SemanticData is empty. |
|
601 | * This is the case when the subject has neither property values nor |
||
602 | * data for subobjects. |
||
603 | * |
||
604 | 3 | * @since 1.8 |
|
605 | * |
||
606 | * @return boolean |
||
607 | 3 | */ |
|
608 | public function isEmpty() { |
||
611 | |||
612 | /** |
||
613 | * Add all data from the given SMWSemanticData. |
||
614 | * Only works if the imported SMWSemanticData has the same subject as |
||
615 | * this SMWSemanticData; an exception is thrown otherwise. |
||
616 | * |
||
617 | 154 | * @since 1.7 |
|
618 | 154 | * |
|
619 | * @param SemanticData $semanticData object to copy from |
||
620 | * |
||
621 | * @throws SemanticDataImportException |
||
622 | */ |
||
623 | public function importDataFrom( SemanticData $semanticData ) { |
||
658 | |||
659 | /** |
||
660 | * Removes data from the given SMWSemanticData. |
||
661 | * If the subject of the data that is to be removed is not equal to the |
||
662 | * subject of this SMWSemanticData, it will just be ignored (nothing to |
||
663 | * remove). Likewise, removing data that is not present does not change |
||
664 | 256 | * anything. |
|
665 | * |
||
666 | 256 | * @since 1.8 |
|
667 | 204 | * |
|
668 | * @param SemanticData $semanticData |
||
669 | */ |
||
670 | 255 | public function removeDataFrom( SemanticData $semanticData ) { |
|
683 | |||
684 | /** |
||
685 | * @see SubSemanticData::hasSubSemanticData |
||
686 | 272 | * @since 1.9 |
|
687 | 272 | * |
|
688 | 272 | * @param string $subobjectName|null |
|
689 | * |
||
690 | * @return boolean |
||
691 | */ |
||
692 | public function hasSubSemanticData( $subobjectName = null ) { |
||
695 | |||
696 | /** |
||
697 | * @see SubSemanticData::findSubSemanticData |
||
698 | * @since 1.9 |
||
699 | * |
||
700 | * @param string $subobjectName |
||
701 | * |
||
702 | * @return SMWContainerSemanticData|null |
||
703 | */ |
||
704 | public function findSubSemanticData( $subobjectName ) { |
||
707 | |||
708 | /** |
||
709 | * @see SubSemanticData::addSubSemanticData |
||
710 | * @since 1.8 |
||
711 | * |
||
712 | * @param SemanticData $semanticData |
||
713 | * @throws SubSemanticDataException |
||
714 | */ |
||
715 | public function addSubSemanticData( SemanticData $semanticData ) { |
||
719 | |||
720 | /** |
||
721 | * @see SubSemanticData::removeSubSemanticData |
||
722 | * @since 1.8 |
||
723 | * |
||
724 | * @param SemanticData $semanticData |
||
725 | */ |
||
726 | public function removeSubSemanticData( SemanticData $semanticData ) { |
||
730 | |||
731 | } |
||
732 |
Instead of relying on
global
state, we recommend one of these alternatives:1. Pass all data via parameters
2. Create a class that maintains your state