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