SMWPageProperty::execute()   F
last analyzed

Complexity

Conditions 17
Paths 264

Size

Total Lines 130
Code Lines 86

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 306

Importance

Changes 0
Metric Value
cc 17
eloc 86
nc 264
nop 1
dl 0
loc 130
ccs 0
cts 79
cp 0
crap 306
rs 3.6909
c 0
b 0
f 0

How to fix   Long Method    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
 * @ingroup SMWSpecialPage
4
 * @ingroup SpecialPage
5
 *
6
 * Special page to show object relation pairs.
7
 *
8
 * @author Denny Vrandecic
9
 */
10
11
/**
12
 * This special page for Semantic MediaWiki implements a
13
 * view on a object-relation pair, i.e. a page that shows
14
 * all the fillers of a property for a certain page.
15
 * This is typically used for overflow results from other
16
 * dynamic output pages.
17
 *
18
 * @ingroup SMWSpecialPage
19
 * @ingroup SpecialPage
20
 */
21
class SMWPageProperty extends SpecialPage {
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class must be in a namespace of at least one level to avoid collisions.

You can fix this by adding a namespace to your class:

namespace YourVendor;

class YourClass { }

When choosing a vendor namespace, try to pick something that is not too generic to avoid conflicts with other libraries.

Loading history...
22
23
	/**
24
	 * Constructor
25
	 */
26
	public function __construct() {
27
		parent::__construct( 'PageProperty', '', false );
28
	}
29
30
	public function execute( $query ) {
31
		global $wgRequest, $wgOut;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
32
		$this->setHeaders();
33
34
		// Get parameters
35
		$pagename = $wgRequest->getVal( 'from' );
36
		$propname = $wgRequest->getVal( 'type' );
37
		$limit = $wgRequest->getVal( 'limit', 20 );
38
		$offset = $wgRequest->getVal( 'offset', 0 );
39
40
		if ( $propname == '' ) { // No GET parameters? Try the URL:
41
			$queryparts = explode( '::', $query );
42
			$propname = $query;
43
			if ( count( $queryparts ) > 1 ) {
44
				$pagename = $queryparts[0];
45
				$propname = implode( '::', array_slice( $queryparts, 1 ) );
46
			}
47
		}
48
49
		$subject = \SMW\DataValueFactory::getInstance()->newTypeIDValue( '_wpg', $pagename );
0 ignored issues
show
Deprecated Code introduced by
The method SMW\DataValueFactory::newTypeIdValue() has been deprecated with message: since 2.4, use DataValueFactory::newDataValueByType

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
50
		$pagename = $subject->isValid() ? $subject->getPrefixedText() : '';
51
		$property = SMWPropertyValue::makeUserProperty( $propname );
52
		$propname = $property->isValid() ? $property->getWikiValue() : '';
53
54
		// Produce output
55
		$html = '';
56
		if ( ( $propname === '' ) ) { // no property given, show a message
57
			$html .= wfMessage( 'smw_pp_docu' )->text() . "\n";
58
		} else { // property given, find and display results
59
			// @todo FIXME: very ugly, needs i18n
60
			$wgOut->setPagetitle( ( $pagename !== '' ? $pagename . ' ':'' ) . $property->getWikiValue() );
61
62
			// get results (get one more, to see if we have to add a link to more)
63
			$options = new SMWRequestOptions();
64
			$options->limit = $limit + 1;
65
			$options->offset = $offset;
66
			$options->sort = true;
67
			$results = \SMW\StoreFactory::getStore()->getPropertyValues( $pagename !== '' ? $subject->getDataItem() : null, $property->getDataItem(), $options );
0 ignored issues
show
Compatibility introduced by
$property->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...
68
69
			// prepare navigation bar if needed
70
			$navigation = '';
71
			if ( ( $offset > 0 ) || ( count( $results ) > $limit ) ) {
72
				if ( $offset > 0 ) {
73
					$navigation .= Html::element(
74
						'a',
75
						array(
76
							'href' => $this->getTitle()->getLocalURL( array(
77
								'offset' => max( 0, $offset - $limit ),
78
								'limit' => $limit,
79
								'type' => $propname,
80
								'from' => $pagename
81
							) )
82
						),
83
						wfMessage( 'smw_result_prev' )->text()
84
					);
85
				} else {
86
					$navigation = wfMessage( 'smw_result_prev' )->text();
87
				}
88
89
				// @todo FIXME: i18n patchwork.
90
				$navigation .=
91
					'&#160;&#160;&#160;&#160; <b>' .
92
						wfMessage( 'smw_result_results' )->text() . ' ' .
93
						( $offset + 1 ) . '– ' . ( $offset + min( count( $results ), $limit ) ) .
94
					'</b>&#160;&#160;&#160;&#160;';
95
96
				if ( count( $results ) == ( $limit + 1 ) ) {
97
					$navigation .= Html::element(
98
						'a',
99
						array(
100
							'href' => $this->getTitle()->getLocalURL( array(
101
								'offset' => ( $offset + $limit ),
102
								'limit' => $limit,
103
								'type' => $propname,
104
								'from' => $pagename
105
							) )
106
						),
107
						wfMessage( 'smw_result_next' )->text()
108
					);
109
				} else {
110
					$navigation .= wfMessage( 'smw_result_next' )->text();
111
				}
112
			}
113
114
			// display results
115
			$html .= '<br />' . $navigation;
116
			if ( count( $results ) == 0 ) {
117
				$html .= wfMessage( 'smw_result_noresults' )->text();
118
			} else {
119
				$linker = smwfGetLinker();
120
				$html .= "<ul>\n";
121
				$count = $limit + 1;
122
123
				foreach ( $results as $di ) {
124
					$count--;
125
					if ( $count < 1 ) {
126
						continue;
127
					}
128
129
					$dv = \SMW\DataValueFactory::getInstance()->newDataValueByItem( $di, $property->getDataItem() );
0 ignored issues
show
Documentation introduced by
$property->getDataItem() is of type object<SMWDataItem>, but the function expects a null|object<SMW\DIProperty>.

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
					$html .= '<li>' . $dv->getLongHTMLText( $linker ); // do not show infolinks, the magnifier "+" is ambiguous with the browsing '+' for '_wpg' (see below)
131
132
					if ( $property->getDataItem()->findPropertyTypeID() == '_wpg' ) {
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 findPropertyTypeID() 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...
133
						$browselink = SMWInfolink::newBrowsingLink( '+', $dv->getLongWikiText() );
134
						$html .= ' &#160;' . $browselink->getHTML( $linker );
135
					}
136
137
					$html .=  "</li> \n";
138
				}
139
140
				$html .= "</ul>\n";
141
			}
142
143
			$html .= $navigation;
144
		}
145
146
		// Deprecated: Use of SpecialPage::getTitle was deprecated in MediaWiki 1.23
147
		$spectitle = method_exists( $this, 'getPageTitle') ? $this->getPageTitle() : $this->getTitle();
148
149
		// Display query form
150
		$html .= '<p>&#160;</p>';
151
		$html .= '<form name="pageproperty" action="' . htmlspecialchars( $spectitle->getLocalURL() ) . '" method="get">' . "\n" .
152
		         '<input type="hidden" name="title" value="' . $spectitle->getPrefixedText() . '"/>';
153
		$html .= wfMessage( 'smw_pp_from' )->text() . ' <input type="text" name="from" value="' . htmlspecialchars( $pagename ) . '" />' . "&#160;&#160;&#160;\n";
154
		$html .= wfMessage( 'smw_pp_type' )->text() . ' <input type="text" name="type" value="' . htmlspecialchars( $propname ) . '" />' . "\n";
155
		$html .= '<input type="submit" value="' . wfMessage( 'smw_pp_submit' )->text() . "\"/>\n</form>\n";
156
157
		$wgOut->addHTML( $html );
158
		SMWOutputs::commitToOutputPage( $wgOut ); // make sure locally collected output data is pushed to the output!
159
	}
160
161
	protected function getGroupName() {
162
		return 'smw_group';
163
	}
164
}
165