FunctionNameContainsAndOrSniff   A
last analyzed

Complexity

Total Complexity 14

Size/Duplication

Total Lines 104
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 14
eloc 26
c 1
b 0
f 0
dl 0
loc 104
rs 10

6 Methods

Rating   Name   Duplication   Size   Complexity  
A ensuingDelimiter() 0 19 5
A register() 0 3 1
A containsKeywords() 0 8 3
A getErrorMessage() 0 3 1
A contains() 0 3 1
A process() 0 15 3
1
<?php declare(strict_types = 1);
2
3
namespace Codor\Sniffs\Files;
4
5
use PHP_CodeSniffer\Sniffs\Sniff as PHP_CodeSniffer_Sniff;
6
use PHP_CodeSniffer\Files\File as PHP_CodeSniffer_File;
7
8
class FunctionNameContainsAndOrSniff implements PHP_CodeSniffer_Sniff
9
{
10
11
    /**
12
     * The forbidden strings this sniff looks for.
13
     * @var array
14
     */
15
    protected $keywords = ['And', '_and', 'Or', '_or'];
16
17
    /**
18
     * Returns the token types that this sniff is interested in.
19
     * @return array
20
     */
21
    public function register(): array
22
    {
23
        return [T_FUNCTION];
24
    }
25
26
    /**
27
     * Processes the tokens that this sniff is interested in.
28
     *
29
     * @param PHP_CodeSniffer_File $phpcsFile The file where the token was found.
30
     * @param integer              $stackPtr  The position in the stack where
31
     *                                    the token was found.
32
     * @return void
33
     */
34
    public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr)
35
    {
36
        $tokens = $phpcsFile->getTokens();
37
        $functionNameToken = $tokens[$stackPtr + 2];
38
        $functionName = $functionNameToken['content'];
39
40
        if (! $this->containsKeywords($functionName)) {
41
            return;
42
        }
43
44
        if (! $this->ensuingDelimiter($functionName)) {
45
            return;
46
        }
47
48
        $phpcsFile->addError($this->getErrorMessage(), $stackPtr, __CLASS__);
49
    }
50
51
    /**
52
     * Determines if the provided $string contains any of the
53
     * strings in the $this->keywords property.
54
     * @param  string $string The string to check.
55
     * @return boolean
56
     */
57
    protected function containsKeywords(string $string): bool
58
    {
59
        $contains = false;
60
        foreach ($this->keywords as $keyword) {
61
            $this->contains($keyword, $string) ? $contains = true : null;
62
        }
63
64
        return $contains;
65
    }
66
67
    /**
68
     * Determines if the matched keyword has an ensuing
69
     * CamelCased or snake_cased delimiter.
70
     * @param string $string The string to check.
71
     * @return boolean
72
     */
73
    protected function ensuingDelimiter(string $string): bool
74
    {
75
        foreach ($this->keywords as $keyword) {
76
            if (! $this->contains($keyword, $string)) {
77
                continue;
78
            }
79
80
            $remaining = substr(strstr($string, $keyword), strlen($keyword));
81
            $leadChar = substr($remaining, 0, 1);
82
83
            // Base case
84
            if (ctype_upper($leadChar) || $leadChar == '_') {
85
                return true;
86
            }
87
88
            return $this->ensuingDelimiter($remaining);
89
        }
90
91
        return false;
92
    }
93
94
    /**
95
     * Checks if the $haystack contains the $needle.
96
     * @param  string $needle   Needle string.
97
     * @param  string $haystack Haystack string.
98
     * @return boolean
99
     */
100
    protected function contains(string $needle, string $haystack): bool
101
    {
102
        return strpos($haystack, $needle) !== false;
103
    }
104
105
    /**
106
     * Gets the error message for this sniff.
107
     * @return string
108
     */
109
    protected function getErrorMessage(): string
110
    {
111
        return "Your function contains 'and' or 'or' which indicates it might be doing more than one thing.";
112
    }
113
}
114