/src/Sniffs/Files/ClosingLocationCommentSniff.php

https://github.com/p4ul/CodeIgniter-for-PHP_CodeSniffer · PHP · 181 lines · 81 code · 14 blank · 86 comment · 19 complexity · c294509732939ae922b7d78d059b477b MD5 · raw file

  1. <?php
  2. /**
  3. * CodeIgniter_Sniffs_Files_ClosingLocationCommentSniff.
  4. *
  5. * PHP version 5
  6. *
  7. * @category PHP
  8. * @package PHP_CodeSniffer
  9. * @author Thomas Ernest <thomas.ernest@baobaz.com>
  10. * @copyright 2006 Thomas Ernest
  11. * @license http://thomas.ernest.fr/developement/php_cs/licence GNU General Public License
  12. * @link http://pear.php.net/package/PHP_CodeSniffer
  13. */
  14. if (class_exists('CodeIgniter_Sniffs_Files_AbstractClosingCommentSniff', true) === false) {
  15. $error = 'Class CodeIgniter_Sniffs_Files_AbstractClosingCommentSniff not found';
  16. throw new PHP_CodeSniffer_Exception($error);
  17. }
  18. /**
  19. * CodeIgniter_Sniffs_Files_ClosingLocationCommentSniff.
  20. *
  21. * Ensures that a comment containing the file location exists at the end of file.
  22. * Only other comments and whitespaces are allowed between this comment and
  23. * the end of file.
  24. *
  25. * It may be all kind of comment like multi-line and inline C-style comments as
  26. * well as PERL-style comments. Any number of white may separate comment delimiters
  27. * from comment content. However, content has to be equal to template
  28. * "Location: <file_path_relative_to_application_root>".
  29. * Comparison between content and template is case-sensitive.
  30. *
  31. * There are several ways to configure the application root. In order of priority :
  32. * - Configuration variable ci_application_root.
  33. * - Rule property applicationRoot.
  34. * - Default value '/application/'
  35. *
  36. * @category PHP
  37. * @package PHP_CodeSniffer
  38. * @author Thomas Ernest <thomas.ernest@baobaz.com>
  39. * @copyright 2006 Thomas Ernest
  40. * @license http://thomas.ernest.fr/developement/php_cs/licence GNU General Public License
  41. * @link http://pear.php.net/package/PHP_CodeSniffer
  42. */
  43. class CodeIgniter_Sniffs_Files_ClosingLocationCommentSniff extends CodeIgniter_Sniffs_Files_AbstractClosingCommentSniff
  44. {
  45. public $applicationRoot = '/application/';
  46. /**
  47. * Returns an array of tokens this test wants to listen for.
  48. *
  49. * @return array
  50. */
  51. public function register()
  52. {
  53. return array(
  54. T_OPEN_TAG
  55. );
  56. }//end register()
  57. /**
  58. * Processes this test, when one of its tokens is encountered.
  59. *
  60. * @param PHP_CodeSniffer_File $phpcsFile The current file being scanned.
  61. * @param int $stackPtr The position of the current token
  62. * in the stack passed in $tokens.
  63. *
  64. * @return void
  65. */
  66. public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr)
  67. {
  68. // We are only interested if this is the first open tag.
  69. if ($stackPtr !== 0) {
  70. if ($phpcsFile->findPrevious(T_OPEN_TAG, ($stackPtr - 1)) !== false) {
  71. return;
  72. }
  73. }
  74. $filePath = $phpcsFile->getFilename();
  75. $tokens = $phpcsFile->getTokens();
  76. // removes the application root from the beginning of the file path
  77. $locationPath = self::_getLocationPath($filePath, $this->_getAppRoot());
  78. // add an error, if application root doesn't exist in current file path
  79. if (false === $locationPath) {
  80. $error = 'Unable to find "' . $this->_getAppRoot() . '" in file path "' . $filePath . '". Please set your project\'s application root.';
  81. $phpcsFile->addError($error, count($tokens) - 1);
  82. return;
  83. }
  84. // generates the expected comment
  85. $commentTemplate = "Location: $locationPath";
  86. $currentToken = count($tokens) - 1;
  87. $hasClosingLocationComment = false;
  88. $isNotAWhitespaceOrAComment = false;
  89. while ($currentToken >= 0
  90. && ! $isNotAWhitespaceOrAComment
  91. && ! $hasClosingLocationComment
  92. ) {
  93. $token = $tokens[$currentToken];
  94. $tokenCode = $token['code'];
  95. if (T_COMMENT === $tokenCode) {
  96. $commentString = self::_getCommentContent($token['content']);
  97. if (0 === strcmp($commentString, $commentTemplate)) {
  98. $hasClosingLocationComment = true;
  99. }
  100. } else if (T_WHITESPACE === $tokenCode) {
  101. // Whitespaces are allowed between the closing file comment,
  102. //other comments and end of file
  103. } else {
  104. $isNotAWhitespaceOrAComment = true;
  105. }
  106. $currentToken--;
  107. }
  108. if ( ! $hasClosingLocationComment) {
  109. $error = 'No comment block marks the end of file instead of the closing PHP tag. Please add a comment block containing only "' . $commentTemplate . '".';
  110. $phpcsFile->addError($error, $currentToken);
  111. }
  112. }//end process()
  113. /**
  114. * Returns the relative path from $appRoot to $filePath, or false if
  115. * $appRoot cannot be found in $filePath, because $appRoot is not a parent
  116. * of $filePath.
  117. *
  118. * @param string $filePath Full path to the file being proceed.
  119. * @param string $appRoot Partial or full path to the CodeIgniter
  120. * application root of the file being proceed. It must not contain the
  121. * full path to the application root, but at least the name of the
  122. * application root. Parent directory of the application root are allowed
  123. * but not mandatory.
  124. *
  125. * @return string|bool The relative path from $appRoot to $filePath, or
  126. * false if $appRoot cannot be found in $filePath.
  127. */
  128. private static function _getLocationPath ($filePath, $appRoot)
  129. {
  130. // removes the path to application root
  131. // from the beginning of the file path
  132. $appRootAt = strpos($filePath, $appRoot);
  133. if (false === $appRootAt) {
  134. return false;
  135. }
  136. $localPath = substr($filePath, $appRootAt + strlen($appRoot));
  137. // ensures the location path to be a relative path starting with "./".
  138. if ( ! self::_stringStartsWith($localPath, './')) {
  139. $localPath = './' . $localPath;
  140. } else if ( ! self::_stringStartsWith($localPath, '.')
  141. && self::_stringStartsWith($localPath, '/')
  142. ) {
  143. $localPath = '.' . $localPath;
  144. }
  145. return $localPath;
  146. }//end _getLocationPath()
  147. /**
  148. * Returns the application root that should be used first.
  149. *
  150. * There are several ways to configure the application root.
  151. * In order of priority :
  152. * - Configuration variable ci_application_root.
  153. * - Rule property applicationRoot.
  154. * - Default value '/application/'
  155. *
  156. * @return string Path to your project application root.
  157. */
  158. private function _getAppRoot()
  159. {
  160. $appRoot = PHP_CodeSniffer::getConfigData('ci_application_root');
  161. if (null === $appRoot) {
  162. $appRoot = $this->applicationRoot;
  163. }
  164. return $appRoot;
  165. }//end _getAppRoot()
  166. }//end class
  167. ?>