annotate vendor/drupal/coder/coder_sniffer/Drupal/Sniffs/InfoFiles/DuplicateEntrySniff.php @ 19:fa3358dc1485 tip

Add ndrum files
author Chris Cannam
date Wed, 28 Aug 2019 13:14:47 +0100
parents 129ea1e6d783
children
rev   line source
Chris@0 1 <?php
Chris@0 2 /**
Chris@17 3 * \Drupal\Sniffs\InfoFiles\DuplicateEntrySniff.
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 Drupal\Sniffs\InfoFiles;
Chris@17 11
Chris@17 12 use PHP_CodeSniffer\Files\File;
Chris@17 13 use PHP_CodeSniffer\Sniffs\Sniff;
Chris@17 14
Chris@0 15 /**
Chris@0 16 * Make sure that entries in info files are specified only once.
Chris@0 17 *
Chris@0 18 * @category PHP
Chris@0 19 * @package PHP_CodeSniffer
Chris@0 20 * @link http://pear.php.net/package/PHP_CodeSniffer
Chris@0 21 */
Chris@17 22 class DuplicateEntrySniff implements Sniff
Chris@0 23 {
Chris@0 24
Chris@0 25
Chris@0 26 /**
Chris@0 27 * Returns an array of tokens this test wants to listen for.
Chris@0 28 *
Chris@0 29 * @return array
Chris@0 30 */
Chris@0 31 public function register()
Chris@0 32 {
Chris@0 33 return array(T_INLINE_HTML);
Chris@0 34
Chris@0 35 }//end register()
Chris@0 36
Chris@0 37
Chris@0 38 /**
Chris@0 39 * Processes this test, when one of its tokens is encountered.
Chris@0 40 *
Chris@17 41 * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned.
Chris@17 42 * @param int $stackPtr The position of the current token in the
Chris@17 43 * stack passed in $tokens.
Chris@0 44 *
Chris@0 45 * @return int
Chris@0 46 */
Chris@17 47 public function process(File $phpcsFile, $stackPtr)
Chris@0 48 {
Chris@0 49 // Only run this sniff once per info file.
Chris@0 50 $fileExtension = strtolower(substr($phpcsFile->getFilename(), -4));
Chris@0 51 if ($fileExtension !== 'info') {
Chris@0 52 return ($phpcsFile->numTokens + 1);
Chris@0 53 }
Chris@0 54
Chris@0 55 $contents = file_get_contents($phpcsFile->getFilename());
Chris@0 56 $duplicates = $this->findDuplicateInfoFileEntries($contents);
Chris@0 57 if (empty($duplicates) === false) {
Chris@0 58 foreach ($duplicates as $duplicate) {
Chris@0 59 $error = 'Duplicate entry for "%s" in info file';
Chris@0 60 $phpcsFile->addError($error, $stackPtr, 'DuplicateEntry', array($duplicate));
Chris@0 61 }
Chris@0 62 }
Chris@0 63
Chris@0 64 return ($phpcsFile->numTokens + 1);
Chris@0 65
Chris@0 66 }//end process()
Chris@0 67
Chris@0 68
Chris@0 69 /**
Chris@0 70 * Parses a Drupal info file and checsk if a key apperas more than once.
Chris@0 71 *
Chris@0 72 * @param string $data The contents of the info file to parse
Chris@0 73 *
Chris@0 74 * @return array A list of configuration keys that appear more than once.
Chris@0 75 */
Chris@0 76 protected function findDuplicateInfoFileEntries($data)
Chris@0 77 {
Chris@0 78 $info = array();
Chris@0 79 $duplicates = array();
Chris@0 80 $constants = get_defined_constants();
Chris@0 81
Chris@0 82 if (preg_match_all(
Chris@0 83 '
Chris@0 84 @^\s* # Start at the beginning of a line, ignoring leading whitespace
Chris@0 85 ((?:
Chris@0 86 [^=;\[\]]| # Key names cannot contain equal signs, semi-colons or square brackets,
Chris@0 87 \[[^\[\]]*\] # unless they are balanced and not nested
Chris@0 88 )+?)
Chris@0 89 \s*=\s* # Key/value pairs are separated by equal signs (ignoring white-space)
Chris@0 90 (?:
Chris@0 91 ("(?:[^"]|(?<=\\\\)")*")| # Double-quoted string, which may contain slash-escaped quotes/slashes
Chris@0 92 (\'(?:[^\']|(?<=\\\\)\')*\')| # Single-quoted string, which may contain slash-escaped quotes/slashes
Chris@0 93 ([^\r\n]*?) # Non-quoted string
Chris@0 94 )\s*$ # Stop at the next end of a line, ignoring trailing whitespace
Chris@0 95 @msx',
Chris@0 96 $data,
Chris@0 97 $matches,
Chris@0 98 PREG_SET_ORDER
Chris@0 99 ) !== false
Chris@0 100 ) {
Chris@0 101 foreach ($matches as $match) {
Chris@0 102 // Fetch the key and value string.
Chris@0 103 $i = 0;
Chris@0 104 foreach (array('key', 'value1', 'value2', 'value3') as $var) {
Chris@0 105 if (isset($match[++$i]) === true) {
Chris@0 106 $$var = $match[$i];
Chris@0 107 } else {
Chris@0 108 $$var = '';
Chris@0 109 }
Chris@0 110 }
Chris@0 111
Chris@0 112 $value = stripslashes(substr($value1, 1, -1)).stripslashes(substr($value2, 1, -1)).$value3;
Chris@0 113
Chris@0 114 // Parse array syntax.
Chris@0 115 $keys = preg_split('/\]?\[/', rtrim($key, ']'));
Chris@0 116 $last = array_pop($keys);
Chris@0 117 $parent = &$info;
Chris@0 118
Chris@0 119 // Create nested arrays.
Chris@0 120 foreach ($keys as $key) {
Chris@0 121 if ($key === '') {
Chris@0 122 $key = count($parent);
Chris@0 123 }
Chris@0 124
Chris@0 125 if (isset($parent[$key]) === false || is_array($parent[$key]) === false) {
Chris@0 126 $parent[$key] = array();
Chris@0 127 }
Chris@0 128
Chris@0 129 $parent = &$parent[$key];
Chris@0 130 }
Chris@0 131
Chris@0 132 // Handle PHP constants.
Chris@0 133 if (isset($constants[$value]) === true) {
Chris@0 134 $value = $constants[$value];
Chris@0 135 }
Chris@0 136
Chris@0 137 // Insert actual value.
Chris@0 138 if ($last === '') {
Chris@0 139 $last = count($parent);
Chris@0 140 }
Chris@0 141
Chris@0 142 if (array_key_exists($last, $parent) === true) {
Chris@0 143 $duplicates[] = $last;
Chris@0 144 }
Chris@0 145
Chris@0 146 $parent[$last] = $value;
Chris@0 147 }//end foreach
Chris@0 148 }//end if
Chris@0 149
Chris@0 150 return $duplicates;
Chris@0 151
Chris@0 152 }//end findDuplicateInfoFileEntries()
Chris@0 153
Chris@0 154
Chris@0 155 }//end class