Completed
Push — master ( 30add5...f043e7 )
by mw
14s
created

ConceptPage::getFormattedColumns()   B

Complexity

Conditions 3
Paths 3

Size

Total Lines 24
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 24
ccs 0
cts 14
cp 0
rs 8.9713
cc 3
eloc 14
nc 3
nop 1
crap 12
1
<?php
2
3
namespace SMW;
4
5
use Html;
6
use SMW\Query\Language\ConceptDescription;
7
use SMW\MediaWiki\ByLanguageCollationMapper;
8
use SMWPageLister;
9
use SMWDataItem as DataItem;
10
11
/**
12
 * Special handling for relation/attribute description pages.
13
 * Some code based on CategoryPage.php
14
 *
15
 * Indicate class aliases in a way PHPStorm and Eclipse understand.
16
 * This is purely an IDE helper file, and is not loaded by the extension.
17
 *
18
 * @since 1.9
19
 *
20
 * @ingroup SMW
21
 *
22
 * @license GNU GPL v2+
23
 * @author: Markus Krötzsch
24
 * @author: mwjames
25
 */
26
27
/**
28
 * Implementation of MediaWiki's Article that shows additional information on
29
 * Concept: pages. Very similar to CategoryPage.
30
 * @ingroup SMW
31
 */
32
class ConceptPage extends \SMWOrderedListPage {
33
34
	/**
35
	 * Initialize parameters to use a higher limit. This operation is very
36
	 * similar to showing members of categories.
37
	 */
38
	protected function initParameters() {
39
		global $smwgConceptPagingLimit;
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...
40
		$this->limit = $smwgConceptPagingLimit;
41
		return true;
42
	}
43
44
	/**
45
	 * Returns the HTML which is added to $wgOut after the article text.
46
	 *
47
	 * @return string
48
	 */
49
	protected function getHtml() {
50
		global $smwgConceptPagingLimit, $wgRequest;
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...
51
52
		if ( $this->limit > 0 ) { // limit==0: configuration setting to disable this completely
53
			$description = new ConceptDescription( $this->getDataItem() );
54
			$query = SMWPageLister::getQuery( $description, $this->limit, $this->from, $this->until );
0 ignored issues
show
Documentation introduced by
$description is of type object<SMW\Query\Language\ConceptDescription>, but the function expects a object<SMWDescription>.

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...
55
56
			$query->setLimit( $wgRequest->getVal( 'limit', $smwgConceptPagingLimit ) );
57
			$query->setOffset( $wgRequest->getVal( 'offset', '0' ) );
58
59
			$queryResult = ApplicationFactory::getInstance()->getStore()->getQueryResult( $query );
60
61
			$diWikiPages = $queryResult->getResults();
62
			if ( $this->until !== '' ) {
63
				$diWikiPages = array_reverse( $diWikiPages );
64
			}
65
66
			$errors = $queryResult->getErrors();
67
		} else {
68
			$diWikiPages = array();
69
			$errors = array();
70
		}
71
72
		$pageLister = new SMWPageLister( $diWikiPages, null, $this->limit, $this->from, $this->until );
0 ignored issues
show
Unused Code introduced by
$pageLister is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
73
		$this->mTitle->setFragment( '#SMWResults' ); // Make navigation point to the result list.
74
75
		$titleText = htmlspecialchars( $this->mTitle->getText() );
76
77
		return Html::element( 'br', array( 'id' => 'smwfootbr' ) ) .
78
			Html::element( 'a', array( 'name' => 'SMWResults' ), null ) .
79
			Html::rawElement( 'div', array( 'id' => 'mw-pages'),
80
				$this->getCacheInformation() .
81
				Html::rawElement( 'h2', array(), $this->getContext()->msg( 'smw_concept_header', $titleText )->text() ) .
82
				$this->getNavigationLinks( 'smw_conceptarticlecount', $diWikiPages, $smwgConceptPagingLimit ) .
83
				smwfEncodeMessages( $errors ) . ' ' .
84
				$this->getFormattedColumns( $diWikiPages )
85
			);
86
	}
87
88
	private function getCacheInformation() {
89
90
		$concept = ApplicationFactory::getInstance()->getStore()->getConceptCacheStatus( $this->getDataItem() );
91
		$cacheInformation = wfMessage( 'smw-concept-no-cache' )->text();
92
93
		if ( $concept instanceof DIConcept && $concept->getCacheStatus() === 'full' ) {
0 ignored issues
show
Unused Code Bug introduced by
The strict comparison === seems to always evaluate to false as the types of $concept->getCacheStatus() (integer) and 'full' (string) can never be identical. Maybe you want to use a loose comparison == instead?
Loading history...
94
			$cacheInformation = wfMessage(
95
				'smw-concept-cache-count',
96
				$this->getContext()->getLanguage()->formatNum( $concept->getCacheCount() ),
97
				$this->getContext()->getLanguage()->timeanddate( $concept->getCacheDate() )
98
			)->parse();
99
		}
100
101
		return Html::rawElement(
102
			'h2',
103
			array(),
104
			$this->getContext()->msg( 'smw-concept-cache-header' )->text()
105
		) . $cacheInformation;
106
	}
107
108
	private function getFormattedColumns( array $diWikiPages ) {
109
110
		if ( $diWikiPages === array() ) {
111
			return '';
112
		}
113
114
		$mwCollaboratorFactory = ApplicationFactory::getInstance()->newMwCollaboratorFactory();
115
		$htmlColumnListRenderer = $mwCollaboratorFactory->newHtmlColumnListRenderer();
116
117
		foreach ( $diWikiPages as $value ) {
118
			$dv = DataValueFactory::getInstance()->newDataItemValue( $value );
119
			$contentsByIndex[$this->getFirstLetterForCategory( $value )][] = $dv->getLongHTMLText( smwfGetLinker() );
0 ignored issues
show
Coding Style Comprehensibility introduced by
$contentsByIndex was never initialized. Although not strictly required by PHP, it is generally a good practice to add $contentsByIndex = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
120
		}
121
122
		$htmlColumnListRenderer->setColumnRTLDirectionalityState(
123
			$this->getContext()->getLanguage()->isRTL()
124
		);
125
126
		$htmlColumnListRenderer->setColumnClass( 'smw-column-responsive' );
127
		$htmlColumnListRenderer->setNumberOfColumns( 1 );
128
		$htmlColumnListRenderer->addContentsByIndex( $contentsByIndex );
0 ignored issues
show
Bug introduced by
The variable $contentsByIndex does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
129
130
		return $htmlColumnListRenderer->getHtml();
131
	}
132
133
	private function getFirstLetterForCategory( DataItem $dataItem ) {
134
135
		$sortKey = $dataItem->getSortKey();
136
137
		if ( $dataItem->getDIType() == DataItem::TYPE_WIKIPAGE ) {
138
			$sortKey = ApplicationFactory::getInstance()->getStore()->getWikiPageSortKey( $dataItem );
139
140
		}
141
142
		return ByLanguageCollationMapper::getInstance()->findFirstLetterForCategory( $sortKey );
143
	}
144
145
}
146