annotate vendor/drupal/coder/coder_sniffer/DrupalPractice/Project.php @ 0:4c8ae668cc8c

Initial import (non-working)
author Chris Cannam
date Wed, 29 Nov 2017 16:09:58 +0000
parents
children 129ea1e6d783
rev   line source
Chris@0 1 <?php
Chris@0 2 /**
Chris@0 3 * DrupalPractice_Project
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@0 10 use Symfony\Component\Yaml\Yaml;
Chris@0 11
Chris@0 12 /**
Chris@0 13 * Helper class to retrieve project information like module/theme name for a file.
Chris@0 14 *
Chris@0 15 * @category PHP
Chris@0 16 * @package PHP_CodeSniffer
Chris@0 17 * @link http://pear.php.net/package/PHP_CodeSniffer
Chris@0 18 */
Chris@0 19 class DrupalPractice_Project
Chris@0 20 {
Chris@0 21
Chris@0 22
Chris@0 23 /**
Chris@0 24 * Determines the project short name a file might be associated with.
Chris@0 25 *
Chris@0 26 * @param PHP_CodeSniffer_File $phpcsFile The file being scanned.
Chris@0 27 *
Chris@0 28 * @return string|false Returns the project machine name or false if it could not
Chris@0 29 * be derived.
Chris@0 30 */
Chris@0 31 public static function getName(PHP_CodeSniffer_File $phpcsFile)
Chris@0 32 {
Chris@0 33 // Cache the project name per file as this might get called often.
Chris@0 34 static $cache;
Chris@0 35
Chris@0 36 if (isset($cache[$phpcsFile->getFilename()]) === true) {
Chris@0 37 return $cache[$phpcsFile->getFilename()];
Chris@0 38 }
Chris@0 39
Chris@0 40 $pathParts = pathinfo($phpcsFile->getFilename());
Chris@0 41 // Module and install files are easy: they contain the project name in the
Chris@0 42 // file name.
Chris@0 43 if (isset($pathParts['extension']) === true && ($pathParts['extension'] === 'module' || $pathParts['extension'] === 'install')) {
Chris@0 44 $cache[$phpcsFile->getFilename()] = $pathParts['filename'];
Chris@0 45 return $pathParts['filename'];
Chris@0 46 }
Chris@0 47
Chris@0 48 $infoFile = static::getInfoFile($phpcsFile);
Chris@0 49 if ($infoFile === false) {
Chris@0 50 return false;
Chris@0 51 }
Chris@0 52
Chris@0 53 $pathParts = pathinfo($infoFile);
Chris@0 54 $cache[$phpcsFile->getFilename()] = $pathParts['filename'];
Chris@0 55 return $pathParts['filename'];
Chris@0 56
Chris@0 57 }//end getName()
Chris@0 58
Chris@0 59
Chris@0 60 /**
Chris@0 61 * Determines the info file a file might be associated with.
Chris@0 62 *
Chris@0 63 * @param PHP_CodeSniffer_File $phpcsFile The file being scanned.
Chris@0 64 *
Chris@0 65 * @return string|false The project info file name or false if it could not
Chris@0 66 * be derived.
Chris@0 67 */
Chris@0 68 public static function getInfoFile(PHP_CodeSniffer_File $phpcsFile)
Chris@0 69 {
Chris@0 70 // Cache the project name per file as this might get called often.
Chris@0 71 static $cache;
Chris@0 72
Chris@0 73 if (isset($cache[$phpcsFile->getFilename()]) === true) {
Chris@0 74 return $cache[$phpcsFile->getFilename()];
Chris@0 75 }
Chris@0 76
Chris@0 77 $pathParts = pathinfo($phpcsFile->getFilename());
Chris@0 78
Chris@0 79 // Search for an info file.
Chris@0 80 $dir = $pathParts['dirname'];
Chris@0 81 do {
Chris@0 82 $infoFiles = glob("$dir/*.info.yml");
Chris@0 83 if (empty($infoFiles) === true) {
Chris@0 84 $infoFiles = glob("$dir/*.info");
Chris@0 85 }
Chris@0 86
Chris@0 87 // Go one directory up if we do not find an info file here.
Chris@0 88 $dir = dirname($dir);
Chris@0 89 } while (empty($infoFiles) === true && $dir !== dirname($dir));
Chris@0 90
Chris@0 91 // No info file found, so we give up.
Chris@0 92 if (empty($infoFiles) === true) {
Chris@0 93 $cache[$phpcsFile->getFilename()] = false;
Chris@0 94 return false;
Chris@0 95 }
Chris@0 96
Chris@0 97 // Sort the info file names and take the shortest info file.
Chris@0 98 usort($infoFiles, array('DrupalPractice_Project', 'compareLength'));
Chris@0 99 $infoFile = $infoFiles[0];
Chris@0 100 $cache[$phpcsFile->getFilename()] = $infoFile;
Chris@0 101 return $infoFile;
Chris@0 102
Chris@0 103 }//end getInfoFile()
Chris@0 104
Chris@0 105
Chris@0 106 /**
Chris@0 107 * Determines the *.services.yml file in a module.
Chris@0 108 *
Chris@0 109 * @param PHP_CodeSniffer_File $phpcsFile The file being scanned.
Chris@0 110 *
Chris@0 111 * @return string|false The Services YML file name or false if it could not
Chris@0 112 * be derived.
Chris@0 113 */
Chris@0 114 public static function getServicesYmlFile(PHP_CodeSniffer_File $phpcsFile)
Chris@0 115 {
Chris@0 116 // Cache the services file per file as this might get called often.
Chris@0 117 static $cache;
Chris@0 118
Chris@0 119 if (isset($cache[$phpcsFile->getFilename()]) === true) {
Chris@0 120 return $cache[$phpcsFile->getFilename()];
Chris@0 121 }
Chris@0 122
Chris@0 123 $pathParts = pathinfo($phpcsFile->getFilename());
Chris@0 124
Chris@0 125 // Search for an info file.
Chris@0 126 $dir = $pathParts['dirname'];
Chris@0 127 do {
Chris@0 128 $ymlFiles = glob("$dir/*.services.yml");
Chris@0 129
Chris@0 130 // Go one directory up if we do not find an info file here.
Chris@0 131 $dir = dirname($dir);
Chris@0 132 } while (empty($ymlFiles) === true && $dir !== dirname($dir));
Chris@0 133
Chris@0 134 // No YML file found, so we give up.
Chris@0 135 if (empty($ymlFiles) === true) {
Chris@0 136 $cache[$phpcsFile->getFilename()] = false;
Chris@0 137 return false;
Chris@0 138 }
Chris@0 139
Chris@0 140 // Sort the YML file names and take the shortest info file.
Chris@0 141 usort($ymlFiles, array('DrupalPractice_Project', 'compareLength'));
Chris@0 142 $ymlFile = $ymlFiles[0];
Chris@0 143 $cache[$phpcsFile->getFilename()] = $ymlFile;
Chris@0 144 return $ymlFile;
Chris@0 145
Chris@0 146 }//end getServicesYmlFile()
Chris@0 147
Chris@0 148
Chris@0 149 /**
Chris@0 150 * Return true if the given class is a Drupal service registered in *.services.yml.
Chris@0 151 *
Chris@0 152 * @param PHP_CodeSniffer_File $phpcsFile The file being scanned.
Chris@0 153 * @param int $classPtr The position of the class declaration
Chris@0 154 * in the token stack.
Chris@0 155 *
Chris@0 156 * @return bool
Chris@0 157 */
Chris@0 158 public static function isServiceClass(PHP_CodeSniffer_File $phpcsFile, $classPtr)
Chris@0 159 {
Chris@0 160 // Cache the information per file as this might get called often.
Chris@0 161 static $cache;
Chris@0 162
Chris@0 163 if (isset($cache[$phpcsFile->getFilename()]) === true) {
Chris@0 164 return $cache[$phpcsFile->getFilename()];
Chris@0 165 }
Chris@0 166
Chris@0 167 // Get the namespace of the class if there is one.
Chris@0 168 $namespacePtr = $phpcsFile->findPrevious(T_NAMESPACE, ($classPtr - 1));
Chris@0 169 if ($namespacePtr === false) {
Chris@0 170 $cache[$phpcsFile->getFilename()] = false;
Chris@0 171 return false;
Chris@0 172 }
Chris@0 173
Chris@0 174 $ymlFile = static::getServicesYmlFile($phpcsFile);
Chris@0 175 if ($ymlFile === false) {
Chris@0 176 $cache[$phpcsFile->getFilename()] = false;
Chris@0 177 return false;
Chris@0 178 }
Chris@0 179
Chris@0 180 $services = Yaml::parse(file_get_contents($ymlFile));
Chris@0 181 if (isset($services['services']) === false) {
Chris@0 182 $cache[$phpcsFile->getFilename()] = false;
Chris@0 183 return false;
Chris@0 184 }
Chris@0 185
Chris@0 186 $nsEnd = $phpcsFile->findNext(
Chris@0 187 [
Chris@0 188 T_NS_SEPARATOR,
Chris@0 189 T_STRING,
Chris@0 190 T_WHITESPACE,
Chris@0 191 ],
Chris@0 192 ($namespacePtr + 1),
Chris@0 193 null,
Chris@0 194 true
Chris@0 195 );
Chris@0 196 $namespace = trim($phpcsFile->getTokensAsString(($namespacePtr + 1), ($nsEnd - $namespacePtr - 1)));
Chris@0 197 $classNameSpaced = ltrim($namespace.'\\'.$phpcsFile->getDeclarationName($classPtr), '\\');
Chris@0 198
Chris@0 199 foreach ($services['services'] as $service) {
Chris@0 200 if (isset($service['class']) === true
Chris@0 201 && $classNameSpaced === ltrim($service['class'], '\\')
Chris@0 202 ) {
Chris@0 203 $cache[$phpcsFile->getFilename()] = true;
Chris@0 204 return true;
Chris@0 205 }
Chris@0 206 }
Chris@0 207
Chris@0 208 return false;
Chris@0 209
Chris@0 210 }//end isServiceClass()
Chris@0 211
Chris@0 212
Chris@0 213 /**
Chris@0 214 * Helper method to sort array values by string length with usort().
Chris@0 215 *
Chris@0 216 * @param string $a First string.
Chris@0 217 * @param string $b Second string.
Chris@0 218 *
Chris@0 219 * @return int
Chris@0 220 */
Chris@0 221 public static function compareLength($a, $b)
Chris@0 222 {
Chris@0 223 return (strlen($a) - strlen($b));
Chris@0 224
Chris@0 225 }//end compareLength()
Chris@0 226
Chris@0 227
Chris@0 228 /**
Chris@0 229 * Determines the Drupal core version a file might be associated with.
Chris@0 230 *
Chris@0 231 * @param PHP_CodeSniffer_File $phpcsFile The file being scanned.
Chris@0 232 *
Chris@0 233 * @return string|false The core version string or false if it could not
Chris@0 234 * be derived.
Chris@0 235 */
Chris@0 236 public static function getCoreVersion(PHP_CodeSniffer_File $phpcsFile)
Chris@0 237 {
Chris@0 238 $infoFile = static::getInfoFile($phpcsFile);
Chris@0 239 if ($infoFile === false) {
Chris@0 240 return false;
Chris@0 241 }
Chris@0 242
Chris@0 243 $pathParts = pathinfo($infoFile);
Chris@0 244
Chris@0 245 // Drupal 6 and 7 use the .info file extension.
Chris@0 246 if ($pathParts['extension'] === 'info') {
Chris@0 247 $info_settings = Drupal_Sniffs_InfoFiles_ClassFilesSniff::drupalParseInfoFormat(file_get_contents($infoFile));
Chris@0 248 if (isset($info_settings['core']) === true) {
Chris@0 249 return $info_settings['core'];
Chris@0 250 }
Chris@0 251 } else {
Chris@0 252 // Drupal 8 uses the .yml file extension.
Chris@0 253 // @todo Revisit for Drupal 9, but I don't want to do YAML parsing
Chris@0 254 // for now.
Chris@0 255 return '8.x';
Chris@0 256 }
Chris@0 257
Chris@0 258 }//end getCoreVersion()
Chris@0 259
Chris@0 260
Chris@0 261 }//end class