Completed
Push — master ( a6cb7c...886dbb )
by mw
120:09 queued 91:42
created

getListOfFormattedPropertyDataItems()   C

Complexity

Conditions 7
Paths 7

Size

Total Lines 50
Code Lines 26

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 23
CRAP Score 7

Importance

Changes 0
Metric Value
cc 7
eloc 26
nc 7
nop 3
dl 0
loc 50
ccs 23
cts 23
cp 1
crap 7
rs 6.7272
c 0
b 0
f 0
1
<?php
2
3
namespace SMW\DataValues\ValueFormatters;
4
5
use RuntimeException;
6
use SMW\DataValueFactory;
7
use SMW\DataValues\ReferenceValue;
8
use SMW\DIProperty;
9
use SMW\DIWikiPage;
10
use SMW\Message;
11
use SMWDataValue as DataValue;
12
use SMWPropertyValue as PropertyValue;
13
use SMWDIUri as DIUri;
14
use SMWDITime as DITime;
15
16
/**
17
 * @license GNU GPL v2+
18
 * @since 2.5
19
 *
20
 * @author mwjames
21
 */
22
class ReferenceValueFormatter extends DataValueFormatter {
23
24
	/**
25
	 * @since 2.5
26
	 *
27
	 * {@inheritDoc}
28
	 */
29 157
	public function isFormatterFor( DataValue $dataValue ) {
30 157
		return $dataValue instanceof ReferenceValue;
31
	}
32
33
	/**
34
	 * @since 2.5
35
	 *
36
	 * {@inheritDoc}
37
	 */
38 15
	public function format( $type, $linker = null ) {
39
40 15
		if ( !$this->dataValue instanceof ReferenceValue ) {
41 1
			throw new RuntimeException( "The formatter is missing a valid ReferenceValue object" );
42
		}
43
44 14
		if ( $this->dataValue->getCaption() !== false &&
45 14
			( $type === self::WIKI_SHORT || $type === self::HTML_SHORT ) ) {
46 1
			return $this->dataValue->getCaption();
47
		}
48
49 13
		return $this->getOutputText( $type, $linker );
50
	}
51
52 13
	protected function getOutputText( $type, $linker = null ) {
53
54 13
		if ( !$this->dataValue->isValid() ) {
55
			return ( ( $type == self::WIKI_SHORT ) || ( $type == self::HTML_SHORT ) ) ? '' : $this->dataValue->getErrorText();
56
		}
57
58 13
		return $this->createOutput( $type, $linker );
59
	}
60
61 13
	private function createOutput( $type, $linker ) {
62
63 13
		$results = $this->getListOfFormattedPropertyDataItems(
64
			$type,
65
			$linker,
66 13
			$this->dataValue->getPropertyDataItems()
0 ignored issues
show
Bug introduced by
The method getPropertyDataItems() does not exist on SMWDataValue. Did you maybe mean getProperty()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
67
		);
68
69 13
		if ( $type == self::VALUE || $linker === null ) {
70 8
			return implode( ';', $results );
71
		}
72
73 6
		$result = array_shift( $results );
74 6
		$class = 'smw-reference-otiose';
75
76
		// "smw-highlighter smwttinline" signals to invoke the tooltip
77 6
		if ( count( $results ) > 0 ) {
78 6
			$class = 'smw-reference smw-reference-indicator smw-highlighter smwttinline';
79
		}
80
81
		// Add an extra "title" attribute to support nojs environments by allowing
82
		// it to display references even without JS, it will be removed when JS is available
83
		// to show the "normal" tooltip
84 6
		$result .= \Html::rawElement(
85 6
			'span',
86
			array(
87 6
				'class' => $class,
88 6
				'data-title'   =>  Message::get( 'smw-ui-tooltip-title-reference', Message::TEXT, Message::USER_LANGUAGE ),
89 6
				'data-content' => '<ul><li>' . implode( '</li><li>', $results ) . '</li></ul>',
90 6
				'title' => strip_tags( implode( ', ', $results ) )
91
			)
92
		);
93
94 6
		return $result;
95
	}
96
97 13
	private function getListOfFormattedPropertyDataItems( $type, $linker, $propertyDataItems ) {
98
99 13
		$results = array();
100
101 13
		foreach ( $propertyDataItems as $propertyDataItem ) {
102
103 13
			$propertyValues = $this->dataValue->getDataItem()->getSemanticData()->getPropertyValues( $propertyDataItem );
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class SMWDataItem as the method getSemanticData() does only exist in the following sub-classes of SMWDataItem: SMWDIContainer. 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...
104 13
			$dataItem = reset( $propertyValues );
105
106
			// By definition the first element in the list is the VALUE other
107
			// members are referencing to
108 13
			$isValue = $results === array();
109 13
			$dataValue = null;
110
111 13
			if ( $dataItem !== false ) {
112 13
				$dataValue = DataValueFactory::getInstance()->newDataValueByItem( $dataItem, $propertyDataItem );
113 13
				$output = $this->findValueOutputFor( $isValue, $type, $dataValue, $linker );
114
			} else {
115 6
				$output = '?';
116
			}
117
118
			// Return a plain value in case no linker object is available
119 13
			if ( $dataValue !== null && $linker === null ) {
120 7
				return array( $dataValue->getWikiValue() );
121
			}
122
123 8
			$dataValue = DataValueFactory::getInstance()->newDataValueByItem(
124
				$propertyDataItem
125
			);
126
127
			// Tooltip in tooltip isn't expected to work therefore avoid them
128
			// when generating property labels in a reference output
129 8
			$dataValue->setOption( PropertyValue::OPT_NO_HIGHLIGHT, true );
0 ignored issues
show
Documentation introduced by
true is of type boolean, but the function expects a object<mxied>.

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...
130
131 8
			if ( !$isValue && $type !== self::VALUE ) {
132 6
				$output = Message::get(
133
					array(
134 6
						'smw-datavalue-reference-outputformat',
135 6
						$dataValue->getShortHTMLText( smwfGetLinker() ),
136 6
						$output
137
					),
138 6
					Message::TEXT
139
				);
140
			}
141
142 8
			$results[] = $output;
143
		}
144
145 7
		return $results;
146
	}
147
148 13
	private function findValueOutputFor( $isValue, $type, $dataValue, $linker ) {
149
150 13
		$dataItem = $dataValue->getDataItem();
151
152
		// Turn Uri/Page links into a href representation when not used as value
153 13
		if ( !$isValue &&
154 13
			( $dataItem instanceof DIUri || $dataItem instanceof DIWikiPage ) &&
155 13
			$type !== self::VALUE ) {
156 2
			return $dataValue->getShortHTMLText( smwfGetLinker() );
157
		}
158
159
		// Dates and times are to be displayed in a localized format
160 13
		if ( !$isValue && $dataItem instanceof DITime && $type !== self::VALUE ) {
161 2
			$dataValue->setOutputFormat( 'LOCL' );
162
		}
163
164
		switch ( $type ) {
165 13
			case self::VALUE:
166 4
				return $dataValue->getWikiValue();
167 10
			case self::WIKI_SHORT:
168 4
				return $dataValue->getShortWikiText( $linker );
169 6
			case self::HTML_SHORT:
170 2
				return $dataValue->getShortHTMLText( $linker );
171 4
			case self::WIKI_LONG:
172 2
				return $dataValue->getShortWikiText( $linker );
173 2
			case self::HTML_LONG:
174 2
				return $dataValue->getShortHTMLText( $linker );
175
		}
176
	}
177
178
}
179