Completed
Push — master ( 3abc67...80e892 )
by mw
207:38 queued 172:37
created

EditProtectedPropertyAnnotator.php (4 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
namespace SMW\PropertyAnnotators;
4
5
use SMW\PropertyAnnotator;
6
use ParserOutput;
7
use SMW\Message;
8
use Title;
9
use Html;
10
11
/**
12
 * @license GNU GPL v2+
13
 * @since 2.5
14
 *
15
 * @author mwjames
16
 */
17
class EditProtectedPropertyAnnotator extends PropertyAnnotatorDecorator {
18
19
	/**
20
	 * Indicates whether the annotation was maintained by
21
	 * the system or not.
22
	 */
23
	const SYSTEM_ANNOTATION = 'editprotectedpropertyannotator.system.annotation';
24
25
	/**
26
	 * @var Title
27
	 */
28
	private $title;
29
30
	/**
31
	 * @var boolean
32
	 */
33
	private $editProtectionRight = false;
34
35
	/**
36
	 * @since 1.9
37
	 *
38
	 * @param PropertyAnnotator $propertyAnnotator
39
	 * @param Title $title
40
	 */
41
	public function __construct( PropertyAnnotator $propertyAnnotator, Title $title ) {
42
		parent::__construct( $propertyAnnotator );
43
		$this->title = $title;
44
	}
45
46
	/**
47
	 * @since 2.5
48
	 *
49
	 * @param string|boolean $editProtectionRight
50
	 */
51
	public function setEditProtectionRight( $editProtectionRight ) {
52
		$this->editProtectionRight = $editProtectionRight;
0 ignored issues
show
Documentation Bug introduced by
It seems like $editProtectionRight can also be of type string. However, the property $editProtectionRight is declared as type boolean. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
53
	}
54
55
	/**
56
	 * @since 2.5
57
	 *
58
	 * @param ParserOutput
59
	 */
60
	public function addTopIndicatorTo( ParserOutput $parserOutput ) {
61
62
		if ( $this->editProtectionRight === false ) {
63
			return false;
64
		}
65
66
		// FIXME 3.0; Only MW 1.25+ (ParserOutput::setIndicator)
67
		if ( !method_exists( $parserOutput, 'setIndicator' ) ) {
68
			return false;
69
		}
70
71
		$property = $this->dataItemFactory->newDIProperty( '_EDIP' );
72
73
		if ( !$this->isEnabledProtection( $property ) && !$this->hasEditProtection() ) {
74
			return;
75
		}
76
77
		$html = Html::rawElement(
78
			'div',
79
			array(
80
				'class' => 'smw-edit-protection',
81
				'title' => Message::get( 'smw-edit-protection-enabled' )
82
			), ''
83
		);
84
85
		$parserOutput->setIndicator(
86
			'smw-protection-indicator',
87
			Html::rawElement( 'div', array( 'class' => 'smw-protection-indicator' ), $html )
88
		);
89
	}
90
91
	/**
92
	 * @see PropertyAnnotatorDecorator::addPropertyValues
93
	 */
94
	protected function addPropertyValues() {
95
96
		if ( $this->editProtectionRight === false ) {
97
			return false;
98
		}
99
100
		$property = $this->dataItemFactory->newDIProperty( '_EDIP' );
101
102
		if ( $this->getSemanticData()->hasProperty( $property ) || !$this->hasEditProtection() ) {
103
			return;
104
		}
105
106
		// Notify preceding processes that this property is set as part of the
107
		// protection restriction detection in order to decide whether this
108
		// property was added manually or by the system
109
		$dataItem = $this->dataItemFactory->newDIBoolean( true );
110
		$dataItem->setOption( self::SYSTEM_ANNOTATION, true );
0 ignored issues
show
true is of type boolean, but the function expects a string.

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...
111
112
		// Since edit protection is active, add the property as indicator this is
113
		// especially to retain the status when purging a page
114
		$this->getSemanticData()->addPropertyObjectValue(
115
			$property,
116
			$dataItem
117
		);
118
	}
119
120
	private function hasEditProtection() {
121
122
		//$this->title->flushRestrictions();
0 ignored issues
show
Unused Code Comprehensibility introduced by
75% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
123
124
		if ( !$this->title->isProtected( 'edit' ) ) {
125
			return false;
126
		}
127
128
		$restrictions = array_flip( $this->title->getRestrictions( 'edit' ) );
129
130
		// There could by any edit protections but the `Is edit protected` is
131
		// bound to the `smwgEditProtectionRight` setting
132
		return isset( $restrictions[$this->editProtectionRight] );
133
	}
134
135
	private function isEnabledProtection( $property ) {
136
137
		if ( !$this->getSemanticData()->hasProperty( $property ) ) {
138
			return false;
139
		}
140
141
		$semanticData = $this->getSemanticData();
142
143
		$dataItems = $semanticData->getPropertyValues( $property );
144
		$isEnabledProtection = false;
145
146
		// In case of two competing values, true always wins
147
		foreach ( $dataItems as $dataItem ) {
0 ignored issues
show
The expression $dataItems of type array|object<SMWDataItem> is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
148
149
			$isEnabledProtection = $dataItem->getBoolean();
150
151
			if ( $isEnabledProtection ) {
152
				break;
153
			}
154
		}
155
156
		return $isEnabledProtection;
157
	}
158
159
}
160