Passed
Push — master ( 29f8e6...e59da1 )
by Björn
02:58
created

AbstractDisallowedTagsSniff::tearDown()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 6
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace BestIt\Sniffs\DocTags;
6
7
use BestIt\CodeSniffer\Helper\DocTagHelper;
8
use BestIt\Sniffs\AbstractSniff;
9
use BestIt\Sniffs\DocPosProviderTrait;
10
use function in_array;
11
use function substr;
12
13
/**
14
 * Sniff to disallow the given tags.
15
 *
16
 * @author blange <[email protected]>
17
 * @package BestIt\Sniffs\DocTags
18
 */
19
abstract class AbstractDisallowedTagsSniff extends AbstractSniff
20
{
21
    use DocPosProviderTrait;
22
23
    /**
24
     * Code that comment tag is not allowed.
25
     *
26
     * @var string
27
     */
28
    public const CODE_TAG_NOT_ALLOWED = 'TagNotAllowed';
29
30
    /**
31
     * Message that comment tag is not allowed.
32
     *
33
     * @var string
34
     */
35
    private const MESSAGE_TAG_NOT_ALLOWED = 'The comment tag "%s" is not allowed.';
36
37
    /**
38
     * This tags are disallowed and could be injected from the outside.
39
     *
40
     * @var array
41
     */
42
    public $disallowedTags = [];
43
44
    /**
45
     * The possible tags of this php structure.
46
     *
47
     * @var array|null Tag tokens.
48
     */
49
    private $tags = null;
50
51
    /**
52
     * Returns true if the requirements for this sniff are met.
53
     *
54
     * @return bool Are the requirements met and the sniff should proceed?
55
     */
56
    protected function areRequirementsMet(): bool
57
    {
58
        return $this->getDocCommentPos() && $this->getAllTags();
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->getDocCommentPos() of type integer|null is loosely compared to true; this is ambiguous if the integer can be zero. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
59
    }
60
61
    /**
62
     * Checks and registers errors for the disallowed tags.
63
     *
64
     * @return void
65
     */
66
    private function checkAndRegisterDisallowedTagsError(): void
67
    {
68
        $disallowedTags = $this->getDisallowedTags();
69
        $tags = $this->getAllTags();
70
71
        foreach ($tags as $tagPos => $tag) {
72
            $tagContent = $tag['content'];
73
74
            if (in_array(substr($tagContent, 1), $disallowedTags)) {
75
                $this->file->addError(
76
                    self::MESSAGE_TAG_NOT_ALLOWED,
77
                    $tagPos,
78
                    self::CODE_TAG_NOT_ALLOWED,
79
                    [$tagContent]
80
                );
81
            }
82
        }
83
    }
84
85
    /**
86
     * Returns all tag tokens for this doc block.
87
     *
88
     * @return array
89
     */
90
    private function getAllTags(): array
91
    {
92
        if ($this->tags === null) {
93
            $this->tags = $this->loadAllTags();
94
        }
95
96
        return $this->tags;
97
    }
98
99
    /**
100
     * Type-safe getter for the disallowed tags.
101
     *
102
     * We need this because the ruleset user can "break" the api, if he does not provide an array with his config.
103
     *
104
     * @return array
105
     */
106
    private function getDisallowedTags(): array
107
    {
108
        return $this->disallowedTags;
109
    }
110
111
    /**
112
     * Loads all tags of the structures doc block.
113
     *
114
     * @return array
115
     */
116
    private function loadAllTags(): array
117
    {
118
        return (new DocTagHelper(
119
            $this->tokens[$this->getDocCommentPos()],
120
            $this->file,
0 ignored issues
show
Bug introduced by
It seems like $this->file can be null; however, __construct() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
121
            $this->stackPos
122
        )
123
        )->getCommentTagTokens();
124
    }
125
126
    /**
127
     * Processes the token.
128
     *
129
     * @return void
130
     */
131
    protected function processToken(): void
132
    {
133
        $this->checkAndRegisterDisallowedTagsError();
134
    }
135
136
    /**
137
     * Removes the cached data.
138
     *
139
     * @return void
140
     */
141
    protected function tearDown(): void
142
    {
143
        $this->resetDocCommentPos();
144
145
        $this->tags = null;
146
    }
147
}
148