Completed
Push — master ( b9b0af...b944a3 )
by mw
279:13 queued 244:18
created

ValueFormatter::getFormattedValue()   D

Complexity

Conditions 9
Paths 8

Size

Total Lines 36
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 9
eloc 20
nc 8
nop 3
dl 0
loc 36
rs 4.909
c 0
b 0
f 0
1
<?php
2
3
namespace SMW\MediaWiki\Specials\Browse;
4
5
use SMW\Message;
6
use SMW\ApplicationFactory;
7
use SMWDataValue as DataValue;
8
use SMWDataItem as DataItem;
9
use SMWPropertyValue as PropertyValue;
10
use SMWInfolink as Infolink;
11
use SMW\DIProperty;
12
use SMW\Localizer;
13
14
/**
15
 * @private
16
 *
17
 * This class should eventually be injected instead of relying on static methods,
18
 * for now this is the easiest way to unclutter the mammoth Browse class and
19
 * splitting up responsibilities.
20
 *
21
 * @license GNU GPL v2+
22
 * @since   2.5
23
 *
24
 * @author mwjames
25
 */
26
class ValueFormatter {
27
28
	/**
29
	 * Displays a value, including all relevant links (browse and search by property)
30
	 *
31
	 * @param DataValue $value
0 ignored issues
show
Bug introduced by
There is no parameter named $value. Was it maybe removed?

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 method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
32
	 * @param PropertyValue $property
0 ignored issues
show
Documentation introduced by
There is no parameter named $property. Did you maybe mean $propertyValue?

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...
33
	 * @param boolean $incoming
34
	 *
35
	 * @return string
36
	 */
37
	public static function getFormattedValue( DataValue $dataValue, PropertyValue $propertyValue, $incoming = false ) {
38
39
		$linker = smwfGetLinker();
40
		$dataItem = $dataValue->getContextPage();
41
42
		// Allow the DV formatter to access a specific language code
43
		$dataValue->setOption(
44
			DataValue::OPT_CONTENT_LANGUAGE,
45
			Localizer::getInstance()->getPreferredContentLanguage( $dataItem )->getCode()
46
		);
47
48
		$dataValue->setOption(
49
			DataValue::OPT_USER_LANGUAGE,
50
			Localizer::getInstance()->getUserLanguage()->getCode()
51
		);
52
53
		// Use LOCL formatting where appropriate (date)
54
		$dataValue->setOutputFormat( 'LOCL' );
55
56
		// For a redirect, disable the DisplayTitle to show the original (aka source) page
57
		if ( $propertyValue->isValid() && $propertyValue->getDataItem()->getKey() == '_REDI' ) {
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 getKey() does only exist in the following sub-classes of SMWDataItem: SMWDIProperty, SMW\DIProperty. 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...
58
			$dataValue->setOption( 'smwgDVFeatures', ( $dataValue->getOption( 'smwgDVFeatures' ) & ~SMW_DV_WPV_DTITLE ) );
59
		}
60
61
		$html = $dataValue->getLongHTMLText( $linker );
62
63
		if ( $dataValue->getTypeID() === '_wpg' || $dataValue->getTypeID() === '__sob' ) {
64
			$html .= "&#160;" . Infolink::newBrowsingLink( '+', $dataValue->getLongWikiText() )->getHTML( $linker );
65
		} elseif ( $incoming && $propertyValue->isVisible() ) {
66
			$html .= "&#160;" . Infolink::newInversePropertySearchLink( '+', $dataValue->getTitle(), $propertyValue->getDataItem()->getLabel(), 'smwsearch' )->getHTML( $linker );
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class SMWDataValue as the method getTitle() does only exist in the following sub-classes of SMWDataValue: SMWWikiPageValue. 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...
Bug introduced by
It seems like you code against a specific sub-type and not the parent class SMWDataItem as the method getLabel() does only exist in the following sub-classes of SMWDataItem: SMWDIProperty, SMW\DIProperty. 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...
67
		} elseif ( $dataValue->getProperty() instanceof DIProperty && $dataValue->getProperty()->getKey() !== '_INST' ) {
68
			$html .= $dataValue->getInfolinkText( SMW_OUTPUT_HTML, $linker );
69
		}
70
71
		return $html;
72
	}
73
74
	/**
75
	 * Figures out the label of the property to be used. For outgoing ones it is just
76
	 * the text, for incoming ones we try to figure out the inverse one if needed,
77
	 * either by looking for an explicitly stated one or by creating a default one.
78
	 *
79
	 * @param PropertyValue $property
0 ignored issues
show
Documentation introduced by
There is no parameter named $property. Did you maybe mean $propertyValue?

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...
80
	 * @param boolean $incoming
81
	 * @param boolean $showInverse
82
	 *
83
	 * @return string
84
	 */
85
	public static function getPropertyLabel( PropertyValue $propertyValue, $incoming = false, $showInverse = false ) {
86
87
		$proptext = null;
88
89
		$linker = smwfGetLinker();
90
		$property = $propertyValue->getDataItem();
91
92
		if ( $propertyValue->isVisible() ) {
93
			$propertyValue->setCaption( self::findPropertyLabel( $propertyValue, $incoming, $showInverse ) );
94
			$proptext = $propertyValue->getShortHTMLText( $linker ) . "\n";
95
		} elseif ( $property->getKey() == '_INST' ) {
96
			$proptext = $linker->specialLink( 'Categories' );
97
		} elseif ( $property->getKey() == '_REDI' ) {
98
			$proptext = $linker->specialLink( 'Listredirects', 'isredirect' );
99
		}
100
101
		return $proptext;
102
	}
103
104
	private static function findPropertyLabel( PropertyValue $propertyValue, $incoming = false, $showInverse = false ) {
105
106
		if ( !$incoming || !$showInverse ) {
107
			return self::addNonBreakingSpace( $propertyValue->getWikiValue() );
108
		}
109
110
		$inverseProperty = PropertyValue::makeUserProperty( wfMessage( 'smw_inverse_label_property' )->text() );
111
		$property = $propertyValue->getDataItem();
112
113
		$dataItems = ApplicationFactory::getInstance()->getStore()->getPropertyValues(
114
			$property->getDiWikiPage(),
115
			$inverseProperty->getDataItem()
0 ignored issues
show
Compatibility introduced by
$inverseProperty->getDataItem() of type object<SMWDataItem> is not a sub-type of object<SMW\DIProperty>. It seems like you assume a child class of the class SMWDataItem to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
116
		);
117
118
		if ( $dataItems !== array() ) {
119
			$text = str_replace( '_', ' ', end( $dataItems )->getDBKey() );
120
		} else {
121
			$text = wfMessage( 'smw_inverse_label_default', $propertyValue->getWikiValue() )->text();
122
		}
123
124
		return self::addNonBreakingSpace( $text );
125
	}
126
127
	/**
128
	 * Replace the last two space characters with unbreakable spaces for beautification.
129
	 *
130
	 * @since 2.5
131
	 *
132
	 * @param string $text
133
	 *
134
	 * @return string
135
	 */
136
	public static function addNonBreakingSpace( $text ) {
137
138
		$nonBreakingSpace = html_entity_decode( '&#160;', ENT_NOQUOTES, 'UTF-8' );
139
		$text = preg_replace( '/[\s]/u', $nonBreakingSpace, $text, - 1, $count );
140
141
		if ( $count > 2) {
142
			return preg_replace( '/($nonBreakingSpace)/u', ' ', $text, max( 0, $count - 2 ) );
143
		}
144
145
		return  $text;
146
	}
147
148
}
149