Completed
Push — master ( 9cb597...d2d2ad )
by mw
13s
created

ReferenceValueFormatter::findValueOutputFor()   C

Complexity

Conditions 13
Paths 13

Size

Total Lines 29
Code Lines 19

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 18
CRAP Score 13.0245

Importance

Changes 0
Metric Value
cc 13
eloc 19
nc 13
nop 4
dl 0
loc 29
ccs 18
cts 19
cp 0.9474
crap 13.0245
rs 5.1234
c 0
b 0
f 0

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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 129
	public function isFormatterFor( DataValue $dataValue ) {
30 129
		return $dataValue instanceof ReferenceValue;
31
	}
32
33
	/**
34
	 * @since 2.5
35
	 *
36
	 * {@inheritDoc}
37
	 */
38 9
	public function format( $type, $linker = null ) {
39
40 9
		if ( !$this->dataValue instanceof ReferenceValue ) {
41 1
			throw new RuntimeException( "The formatter is missing a valid ReferenceValue object" );
42
		}
43
44 8
		if ( $this->dataValue->getCaption() !== false &&
45 8
			( $type === self::WIKI_SHORT || $type === self::HTML_SHORT ) ) {
46 1
			return $this->dataValue->getCaption();
47
		}
48
49 7
		return $this->getOutputText( $type, $linker );
50
	}
51
52 7
	protected function getOutputText( $type, $linker = null ) {
53
54 7
		if ( !$this->dataValue->isValid() ) {
55
			return ( ( $type == self::WIKI_SHORT ) || ( $type == self::HTML_SHORT ) ) ? '' : $this->dataValue->getErrorText();
56
		}
57
58 7
		return $this->createOutput( $type, $linker );
59
	}
60
61 7
	private function createOutput( $type, $linker ) {
62
63 7
		$results = $this->getListOfFormattedPropertyDataItems(
64
			$type,
65
			$linker,
66 7
			$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 7
		if ( $type == self::VALUE ) {
70 2
			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 7
	private function getListOfFormattedPropertyDataItems( $type, $linker, $propertyDataItems ) {
98
99 7
		$results = array();
100
101 7
		foreach ( $propertyDataItems as $propertyDataItem ) {
102
103 7
			$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 7
			$dataItem = reset( $propertyValues );
105
106
			// By definition the first element in the list is the VALUE other
107
			// members are referencing to
108 7
			$isValue = $results === array();
109
110 7
			if ( $dataItem !== false ) {
111 7
				$dataValue = DataValueFactory::getInstance()->newDataValueByItem( $dataItem, $propertyDataItem );
112 7
				$output = $this->findValueOutputFor( $isValue, $type, $dataValue, $linker );
113
			} else {
114 4
				$output = '?';
115
			}
116
117 7
			$dataValue = DataValueFactory::getInstance()->newDataValueByItem(
118
				$propertyDataItem
119
			);
120
121
			// Tooltip in tooltip isn't expected to work therefore avoid them
122
			// when generating property labels in a reference output
123 7
			$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...
124
125 7
			if ( !$isValue && $type !== self::VALUE ) {
126 6
				$output = Message::get(
127
					array(
128 6
						'smw-datavalue-reference-outputformat',
129 6
						$dataValue->getShortHTMLText( smwfGetLinker() ),
130 6
						$output
131
					),
132 6
					Message::TEXT
133
				);
134
			}
135
136 7
			$results[] = $output;
137
		}
138
139 7
		return $results;
140
	}
141
142 7
	private function findValueOutputFor( $isValue, $type, $dataValue, $linker ) {
143
144 7
		$dataItem = $dataValue->getDataItem();
145
146
		// Turn Uri/Page links into a href representation when not used as value
147 7
		if ( !$isValue &&
148 7
			( $dataItem instanceof DIUri || $dataItem instanceof DIWikiPage ) &&
149 7
			$type !== self::VALUE ) {
150 2
			return $dataValue->getShortHTMLText( smwfGetLinker() );
151
		}
152
153
		// Dates and times are to be displayed in a localized format
154 7
		if ( !$isValue && $dataItem instanceof DITime && $type !== self::VALUE ) {
155 2
			$dataValue->setOutputFormat( 'LOCL' );
156
		}
157
158
		switch ( $type ) {
159 7
			case self::VALUE:
160 2
				return $dataValue->getWikiValue();
161 6
			case self::WIKI_SHORT:
162 3
				return $dataValue->getShortWikiText( $linker );
163 3
			case self::HTML_SHORT:
164 1
				return $dataValue->getShortHTMLText( $linker );
165 2
			case self::WIKI_LONG:
166 1
				return $dataValue->getShortWikiText( $linker );
167 1
			case self::HTML_LONG:
168 1
				return $dataValue->getShortHTMLText( $linker );
169
		}
170
	}
171
172
}
173