Chris@0
|
1 <?php
|
Chris@0
|
2 /**
|
Chris@17
|
3 * \DrupalPractice\Sniffs\Objects\GlobalFunctionSniff.
|
Chris@0
|
4 *
|
Chris@0
|
5 * @category PHP
|
Chris@0
|
6 * @package PHP_CodeSniffer
|
Chris@0
|
7 * @link http://pear.php.net/package/PHP_CodeSniffer
|
Chris@0
|
8 */
|
Chris@0
|
9
|
Chris@17
|
10 namespace DrupalPractice\Sniffs\Objects;
|
Chris@17
|
11
|
Chris@17
|
12 use PHP_CodeSniffer\Files\File;
|
Chris@17
|
13 use PHP_CodeSniffer\Sniffs\Sniff;
|
Chris@17
|
14 use DrupalPractice\Sniffs\Objects\GlobalDrupalSniff;
|
Chris@17
|
15 use DrupalPractice\Project;
|
Chris@17
|
16
|
Chris@0
|
17 /**
|
Chris@0
|
18 * Checks that global functions like t() are not used in forms or controllers.
|
Chris@0
|
19 *
|
Chris@0
|
20 * @category PHP
|
Chris@0
|
21 * @package PHP_CodeSniffer
|
Chris@0
|
22 * @link http://pear.php.net/package/PHP_CodeSniffer
|
Chris@0
|
23 */
|
Chris@17
|
24 class GlobalFunctionSniff implements Sniff
|
Chris@0
|
25 {
|
Chris@0
|
26
|
Chris@0
|
27 /**
|
Chris@0
|
28 * List of global functions that should not be called.
|
Chris@0
|
29 *
|
Chris@0
|
30 * @var string[]
|
Chris@0
|
31 */
|
Chris@0
|
32 protected $functions = array(
|
Chris@0
|
33 'drupal_get_destination' => 'the "redirect.destination" service',
|
Chris@0
|
34 'drupal_render' => 'the "renderer" service',
|
Chris@0
|
35 'entity_load' => 'the "entity_type.manager" service',
|
Chris@0
|
36 'file_load' => 'the "entity_type.manager" service',
|
Chris@0
|
37 'format_date' => 'the "date.formatter" service',
|
Chris@0
|
38 'node_load' => 'the "entity_type.manager" service',
|
Chris@17
|
39 'node_load_multiple' => 'the "entity_type.manager" service',
|
Chris@0
|
40 'node_type_load' => 'the "entity_type.manager" service',
|
Chris@0
|
41 't' => '$this->t()',
|
Chris@0
|
42 'taxonomy_term_load' => 'the "entity_type.manager" service',
|
Chris@0
|
43 'taxonomy_vocabulary_load' => 'the "entity_type.manager" service',
|
Chris@0
|
44 'user_load' => 'the "entity_type.manager" service',
|
Chris@0
|
45 'user_role_load' => 'the "entity_type.manager" service',
|
Chris@0
|
46 );
|
Chris@0
|
47
|
Chris@0
|
48
|
Chris@0
|
49 /**
|
Chris@0
|
50 * Returns an array of tokens this test wants to listen for.
|
Chris@0
|
51 *
|
Chris@0
|
52 * @return array
|
Chris@0
|
53 */
|
Chris@0
|
54 public function register()
|
Chris@0
|
55 {
|
Chris@0
|
56 return array(T_STRING);
|
Chris@0
|
57
|
Chris@0
|
58 }//end register()
|
Chris@0
|
59
|
Chris@0
|
60
|
Chris@0
|
61 /**
|
Chris@0
|
62 * Processes this test, when one of its tokens is encountered.
|
Chris@0
|
63 *
|
Chris@17
|
64 * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned.
|
Chris@17
|
65 * @param int $stackPtr The position of the current token
|
Chris@17
|
66 * in the stack passed in $tokens.
|
Chris@0
|
67 *
|
Chris@0
|
68 * @return void
|
Chris@0
|
69 */
|
Chris@17
|
70 public function process(File $phpcsFile, $stackPtr)
|
Chris@0
|
71 {
|
Chris@0
|
72 $tokens = $phpcsFile->getTokens();
|
Chris@0
|
73
|
Chris@0
|
74 // We are only interested in function calls, which are not in the global
|
Chris@0
|
75 // scope.
|
Chris@0
|
76 if (isset($this->functions[$tokens[$stackPtr]['content']]) === false
|
Chris@0
|
77 || isset($tokens[($stackPtr + 1)]) === false
|
Chris@0
|
78 || $tokens[($stackPtr + 1)]['code'] !== T_OPEN_PARENTHESIS
|
Chris@0
|
79 || empty($tokens[$stackPtr]['conditions']) === true
|
Chris@0
|
80 ) {
|
Chris@0
|
81 return;
|
Chris@0
|
82 }
|
Chris@0
|
83
|
Chris@0
|
84 // If there is an object operator before the call then this is a method
|
Chris@0
|
85 // invocation, not a function call.
|
Chris@0
|
86 $previous = $phpcsFile->findPrevious(T_WHITESPACE, ($stackPtr - 1), null, true);
|
Chris@0
|
87 if ($tokens[$previous]['code'] === T_OBJECT_OPERATOR) {
|
Chris@0
|
88 return;
|
Chris@0
|
89 }
|
Chris@0
|
90
|
Chris@0
|
91 // Check that this statement is not in a static function.
|
Chris@0
|
92 foreach ($tokens[$stackPtr]['conditions'] as $conditionPtr => $conditionCode) {
|
Chris@0
|
93 if ($conditionCode === T_FUNCTION && $phpcsFile->getMethodProperties($conditionPtr)['is_static'] === true) {
|
Chris@0
|
94 return;
|
Chris@0
|
95 }
|
Chris@0
|
96 }
|
Chris@0
|
97
|
Chris@0
|
98 // Check if the class extends another class and get the name of the class
|
Chris@0
|
99 // that is extended.
|
Chris@0
|
100 $classPtr = key($tokens[$stackPtr]['conditions']);
|
Chris@0
|
101 $extendsName = $phpcsFile->findExtendedClassName($classPtr);
|
Chris@0
|
102
|
Chris@0
|
103 if (($extendsName === false
|
Chris@17
|
104 || in_array($extendsName, GlobalDrupalSniff::$baseClasses) === false)
|
Chris@17
|
105 && Project::isServiceClass($phpcsFile, $classPtr) === false
|
Chris@0
|
106 ) {
|
Chris@0
|
107 return;
|
Chris@0
|
108 }
|
Chris@0
|
109
|
Chris@0
|
110 $warning = '%s() calls should be avoided in classes, use dependency injection and %s instead';
|
Chris@0
|
111 $data = array(
|
Chris@0
|
112 $tokens[$stackPtr]['content'],
|
Chris@0
|
113 $this->functions[$tokens[$stackPtr]['content']],
|
Chris@0
|
114 );
|
Chris@0
|
115 $phpcsFile->addWarning($warning, $stackPtr, 'GlobalFunction', $data);
|
Chris@0
|
116
|
Chris@0
|
117 }//end process()
|
Chris@0
|
118
|
Chris@0
|
119
|
Chris@0
|
120 }//end class
|