These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | |||
3 | namespace SMW\DataValues; |
||
4 | |||
5 | use SMW\ApplicationFactory; |
||
6 | use SMW\DataValueFactory; |
||
7 | use SMW\DataValues\ValueFormatters\DataValueFormatter; |
||
8 | use SMW\DataValues\ValueParsers\MonolingualTextValueParser; |
||
9 | use SMW\DIProperty; |
||
10 | use SMW\DIWikiPage; |
||
11 | use SMW\Localizer; |
||
12 | use SMWContainerSemanticData as ContainerSemanticData; |
||
13 | use SMWDataItem as DataItem; |
||
14 | use SMWDataValue as DataValue; |
||
15 | use SMWDIContainer as DIContainer; |
||
16 | |||
17 | /** |
||
18 | * MonolingualTextValue requires two components, a language code and a |
||
19 | * text. |
||
20 | * |
||
21 | * A text `foo@en` is expected to be invoked with a BCP47 language |
||
22 | * code tag and a language dependent text component. |
||
23 | * |
||
24 | * Internally, the value is stored as container object that represents |
||
25 | * the language code and text as separate entities in order to be queried |
||
26 | * individually. |
||
27 | * |
||
28 | * External output representation depends on the context (wiki, html) |
||
29 | * whether the language code is omitted or not. |
||
30 | * |
||
31 | * @license GNU GPL v2+ |
||
32 | * @since 2.4 |
||
33 | * |
||
34 | * @author mwjames |
||
35 | */ |
||
36 | class MonolingualTextValue extends AbstractMultiValue { |
||
37 | |||
38 | /** |
||
39 | * @var DIProperty[]|null |
||
40 | */ |
||
41 | private static $properties = null; |
||
42 | |||
43 | /** |
||
44 | * @var MonolingualTextValueParser |
||
45 | */ |
||
46 | private $monolingualTextValueParser = null; |
||
47 | |||
48 | /** |
||
49 | * @param string $typeid |
||
50 | */ |
||
51 | 19 | public function __construct( $typeid = '' ) { |
|
52 | 19 | parent::__construct( '_mlt_rec' ); |
|
53 | 19 | } |
|
54 | |||
55 | /** |
||
56 | * @see AbstractMultiValue::setFieldProperties |
||
57 | * |
||
58 | * @param DIProperty[] $properties |
||
59 | */ |
||
60 | public function setFieldProperties( array $properties ) { |
||
61 | // Keep the interface while the properties for this type |
||
62 | // are fixed. |
||
63 | } |
||
64 | |||
65 | /** |
||
66 | * @see AbstractMultiValue::getProperties |
||
67 | * |
||
68 | * @param DIProperty[] $properties |
||
0 ignored issues
–
show
|
|||
69 | */ |
||
70 | public function getProperties() { |
||
71 | self::$properties; |
||
72 | } |
||
73 | |||
74 | /** |
||
75 | * @see DataValue::parseUserValue |
||
76 | * @note called by DataValue::setUserValue |
||
77 | * |
||
78 | * @param string $userValue |
||
79 | */ |
||
80 | 17 | protected function parseUserValue( $userValue ) { |
|
81 | |||
82 | 17 | list( $text, $languageCode ) = $this->getValuesFromString( $userValue ); |
|
83 | |||
84 | 17 | $languageCodeValue = $this->newLanguageCodeValue( $languageCode ); |
|
85 | |||
86 | if ( |
||
87 | 17 | ( $languageCode !== '' && $languageCodeValue->getErrors() !== array() ) || |
|
88 | 17 | ( $languageCode === '' && $this->isEnabledFeature( SMW_DV_MLTV_LCODE ) ) ) { |
|
89 | 3 | $this->addError( $languageCodeValue->getErrors() ); |
|
90 | 3 | return; |
|
91 | } |
||
92 | |||
93 | 14 | $dataValues = array(); |
|
94 | |||
95 | 14 | foreach ( $this->getPropertyDataItems() as $property ) { |
|
96 | |||
97 | if ( |
||
98 | 14 | ( $languageCode === '' && $property->getKey() === '_LCODE' ) || |
|
99 | 14 | ( $text === '' && $property->getKey() === '_TEXT' ) ) { |
|
100 | 1 | continue; |
|
101 | } |
||
102 | |||
103 | 14 | $value = $text; |
|
104 | |||
105 | 14 | if ( $property->getKey() === '_LCODE' ) { |
|
106 | 13 | $value = $languageCode; |
|
107 | } |
||
108 | |||
109 | 14 | $dataValue = DataValueFactory::getInstance()->newDataValueByProperty( |
|
110 | $property, |
||
111 | $value, |
||
112 | 14 | false, |
|
113 | 14 | $this->m_contextPage |
|
114 | ); |
||
115 | |||
116 | 14 | $dataValues[] = $dataValue; |
|
117 | } |
||
118 | |||
119 | // Generate a hash from the normalized representation so that foo@en being |
||
120 | // the same as foo@EN independent of a user input |
||
121 | 14 | $containerSemanticData = $this->newContainerSemanticData( $text . '@' . $languageCode ); |
|
122 | |||
123 | 14 | foreach ( $dataValues as $dataValue ) { |
|
124 | 14 | $containerSemanticData->addDataValue( $dataValue ); |
|
125 | } |
||
126 | |||
127 | 14 | $this->m_dataitem = new DIContainer( $containerSemanticData ); |
|
128 | 14 | } |
|
129 | |||
130 | /** |
||
131 | * @note called by MonolingualTextValueDescriptionDeserializer::deserialize |
||
132 | * and MonolingualTextValue::parseUserValue |
||
133 | * |
||
134 | * No explicit check is made on the validity of a language code and is |
||
135 | * expected to be done before calling this method. |
||
136 | * |
||
137 | * @since 2.4 |
||
138 | * |
||
139 | * @param string $userValue |
||
140 | * |
||
141 | * @return array |
||
142 | */ |
||
143 | 17 | public function getValuesFromString( $userValue ) { |
|
144 | 17 | return $this->getValueParser()->parse( $userValue ); |
|
145 | } |
||
146 | |||
147 | /** |
||
148 | * @see DataValue::loadDataItem |
||
149 | * |
||
150 | * @param DataItem $dataItem |
||
151 | * |
||
152 | * @return boolean |
||
153 | */ |
||
154 | 6 | protected function loadDataItem( DataItem $dataItem ) { |
|
155 | |||
156 | 6 | if ( $dataItem->getDIType() === DataItem::TYPE_CONTAINER ) { |
|
157 | $this->m_dataitem = $dataItem; |
||
158 | return true; |
||
159 | 6 | } elseif ( $dataItem->getDIType() === DataItem::TYPE_WIKIPAGE ) { |
|
160 | 6 | $semanticData = new ContainerSemanticData( $dataItem ); |
|
161 | 6 | $semanticData->copyDataFrom( ApplicationFactory::getInstance()->getStore()->getSemanticData( $dataItem ) ); |
|
162 | 6 | $this->m_dataitem = new DIContainer( $semanticData ); |
|
163 | 6 | return true; |
|
164 | } |
||
165 | |||
166 | 2 | return false; |
|
167 | } |
||
168 | |||
169 | /** |
||
170 | * @see DataValue::getShortWikiText |
||
171 | */ |
||
172 | 10 | public function getShortWikiText( $linker = null ) { |
|
173 | 10 | return $this->getDataValueFormatter()->format( DataValueFormatter::WIKI_SHORT, $linker ); |
|
174 | } |
||
175 | |||
176 | /** |
||
177 | * @see DataValue::getShortHTMLText |
||
178 | */ |
||
179 | public function getShortHTMLText( $linker = null ) { |
||
180 | return $this->getDataValueFormatter()->format( DataValueFormatter::HTML_SHORT, $linker ); |
||
181 | } |
||
182 | |||
183 | /** |
||
184 | * @see DataValue::getLongWikiText |
||
185 | */ |
||
186 | public function getLongWikiText( $linker = null ) { |
||
187 | return $this->getDataValueFormatter()->format( DataValueFormatter::WIKI_LONG, $linker ); |
||
188 | } |
||
189 | |||
190 | /** |
||
191 | * @see DataValue::getLongHTMLText |
||
192 | */ |
||
193 | public function getLongHTMLText( $linker = null ) { |
||
194 | return $this->getDataValueFormatter()->format( DataValueFormatter::HTML_LONG, $linker ); |
||
195 | } |
||
196 | |||
197 | /** |
||
198 | * @see DataValue::getWikiValue |
||
199 | */ |
||
200 | 5 | public function getWikiValue() { |
|
201 | 5 | return $this->getDataValueFormatter()->format( DataValueFormatter::VALUE ); |
|
202 | } |
||
203 | |||
204 | /** |
||
205 | * @since 2.4 |
||
206 | * @note called by AbstractRecordValue::getPropertyDataItems |
||
207 | * |
||
208 | * @return DIProperty[] |
||
209 | */ |
||
210 | 15 | public function getPropertyDataItems() { |
|
211 | |||
212 | 15 | if ( self::$properties !== null && self::$properties !== array() ) { |
|
213 | 14 | return self::$properties; |
|
0 ignored issues
–
show
The return type of
return self::$properties; (SMW\DIProperty[] ) is incompatible with the return type declared by the abstract method SMW\DataValues\AbstractM...e::getPropertyDataItems of type SMW\DataValues\DIProperty[]|null .
If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design. Let’s take a look at an example: class Author {
private $name;
public function __construct($name) {
$this->name = $name;
}
public function getName() {
return $this->name;
}
}
abstract class Post {
public function getAuthor() {
return 'Johannes';
}
}
class BlogPost extends Post {
public function getAuthor() {
return new Author('Johannes');
}
}
class ForumPost extends Post { /* ... */ }
function my_function(Post $post) {
echo strtoupper($post->getAuthor());
}
Our function
Loading history...
|
|||
214 | } |
||
215 | |||
216 | 1 | foreach ( array( '_TEXT', '_LCODE' ) as $id ) { |
|
217 | 1 | self::$properties[] = new DIProperty( $id ); |
|
218 | } |
||
219 | |||
220 | 1 | return self::$properties; |
|
0 ignored issues
–
show
The expression
self::$properties; of type null|SMW\DIProperty[] adds the type SMW\DIProperty[] to the return on line 220 which is incompatible with the return type declared by the abstract method SMW\DataValues\AbstractM...e::getPropertyDataItems of type SMW\DataValues\DIProperty[]|null .
Loading history...
|
|||
221 | } |
||
222 | |||
223 | /** |
||
224 | * @since 2.4 |
||
225 | * @note called by AbstractRecordValue::getDataItems |
||
226 | * |
||
227 | * @return DataItem[] |
||
228 | */ |
||
229 | 2 | public function getDataItems() { |
|
230 | |||
231 | 2 | if ( !$this->isValid() ) { |
|
232 | return array(); |
||
0 ignored issues
–
show
The return type of
return array(); (array ) is incompatible with the return type declared by the abstract method SMW\DataValues\AbstractMultiValue::getDataItems of type SMW\DataValues\DataItem[]|null .
If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design. Let’s take a look at an example: class Author {
private $name;
public function __construct($name) {
$this->name = $name;
}
public function getName() {
return $this->name;
}
}
abstract class Post {
public function getAuthor() {
return 'Johannes';
}
}
class BlogPost extends Post {
public function getAuthor() {
return new Author('Johannes');
}
}
class ForumPost extends Post { /* ... */ }
function my_function(Post $post) {
echo strtoupper($post->getAuthor());
}
Our function
Loading history...
|
|||
233 | } |
||
234 | |||
235 | 2 | $result = array(); |
|
236 | 2 | $index = 0; |
|
237 | |||
238 | 2 | foreach ( $this->getPropertyDataItems() as $diProperty ) { |
|
239 | 2 | $values = $this->getDataItem()->getSemanticData()->getPropertyValues( $diProperty ); |
|
240 | 2 | if ( count( $values ) > 0 ) { |
|
241 | 2 | $result[$index] = reset( $values ); |
|
242 | } else { |
||
243 | $result[$index] = null; |
||
244 | } |
||
245 | 2 | $index += 1; |
|
246 | } |
||
247 | |||
248 | 2 | return $result; |
|
0 ignored issues
–
show
The return type of
return $result; (array ) is incompatible with the return type declared by the abstract method SMW\DataValues\AbstractMultiValue::getDataItems of type SMW\DataValues\DataItem[]|null .
If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design. Let’s take a look at an example: class Author {
private $name;
public function __construct($name) {
$this->name = $name;
}
public function getName() {
return $this->name;
}
}
abstract class Post {
public function getAuthor() {
return 'Johannes';
}
}
class BlogPost extends Post {
public function getAuthor() {
return new Author('Johannes');
}
}
class ForumPost extends Post { /* ... */ }
function my_function(Post $post) {
echo strtoupper($post->getAuthor());
}
Our function
Loading history...
|
|||
249 | } |
||
250 | |||
251 | /** |
||
252 | * @since 2.4 |
||
253 | * |
||
254 | * @return DataValue|null |
||
255 | */ |
||
256 | 5 | public function getTextValueByLanguage( $languageCode ) { |
|
257 | |||
258 | 5 | if ( !$this->isValid() || $this->getDataItem() === array() ) { |
|
259 | return null; |
||
260 | } |
||
261 | |||
262 | 5 | $semanticData = $this->getDataItem()->getSemanticData(); |
|
263 | |||
264 | 5 | $dataItems = $semanticData->getPropertyValues( new DIProperty( '_LCODE' ) ); |
|
265 | 5 | $dataItem = reset( $dataItems ); |
|
266 | |||
267 | 5 | if ( $dataItem === false || ( $dataItem->getString() !== Localizer::asBCP47FormattedLanguageCode( $languageCode ) ) ) { |
|
268 | 1 | return null; |
|
269 | } |
||
270 | |||
271 | 4 | $dataItems = $semanticData->getPropertyValues( new DIProperty( '_TEXT' ) ); |
|
272 | 4 | $dataItem = reset( $dataItems ); |
|
273 | |||
274 | 4 | if ( $dataItem === false ) { |
|
275 | return null; |
||
276 | } |
||
277 | |||
278 | 4 | $dataValue = DataValueFactory::getInstance()->newDataValueByItem( |
|
279 | $dataItem, |
||
280 | 4 | new DIProperty( '_TEXT' ) |
|
281 | ); |
||
282 | |||
283 | 4 | return $dataValue; |
|
284 | } |
||
285 | |||
286 | 14 | private function newContainerSemanticData( $value ) { |
|
287 | |||
288 | 14 | if ( $this->m_contextPage === null ) { |
|
289 | 4 | $containerSemanticData = ContainerSemanticData::makeAnonymousContainer(); |
|
290 | 4 | $containerSemanticData->skipAnonymousCheck(); |
|
291 | } else { |
||
292 | 10 | $subobjectName = '_ML' . md5( $value ); |
|
293 | |||
294 | 10 | $subject = new DIWikiPage( |
|
295 | 10 | $this->m_contextPage->getDBkey(), |
|
296 | 10 | $this->m_contextPage->getNamespace(), |
|
297 | 10 | $this->m_contextPage->getInterwiki(), |
|
298 | $subobjectName |
||
299 | ); |
||
300 | |||
301 | 10 | $containerSemanticData = new ContainerSemanticData( $subject ); |
|
302 | } |
||
303 | |||
304 | 14 | return $containerSemanticData; |
|
305 | } |
||
306 | |||
307 | 17 | private function newLanguageCodeValue( $languageCode ) { |
|
308 | |||
309 | 17 | $languageCodeValue = new LanguageCodeValue(); |
|
310 | |||
311 | 17 | if ( $this->m_property !== null ) { |
|
312 | 10 | $languageCodeValue->setProperty( $this->m_property ); |
|
313 | } |
||
314 | |||
315 | 17 | $languageCodeValue->setUserValue( $languageCode ); |
|
316 | |||
317 | 17 | return $languageCodeValue; |
|
318 | } |
||
319 | |||
320 | 17 | private function getValueParser() { |
|
321 | |||
322 | 17 | if ( $this->monolingualTextValueParser === null ) { |
|
323 | 17 | $this->monolingualTextValueParser = ValueParserFactory::getInstance()->newMonolingualTextValueParser(); |
|
324 | } |
||
325 | |||
326 | 17 | return $this->monolingualTextValueParser; |
|
327 | } |
||
328 | |||
329 | } |
||
330 |
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 methodfinale(...)
.The most likely cause is that the parameter was removed, but the annotation was not.