PageRenderTime 114ms CodeModel.GetById 40ms app.highlight 47ms RepoModel.GetById 23ms app.codeStats 1ms

/.dev/code-sniffs/XLite/Sniffs/PHP/Commenting/ClassCommentSniff.php

https://github.com/istran/core
PHP | 292 lines | 200 code | 30 blank | 62 comment | 21 complexity | 939b6103c4270ee9692dbbc073de6e54 MD5 | raw file
  1<?php
  2/**
  3 * Parses and verifies the doc comments for classes.
  4 *
  5 * PHP version 5
  6 *
  7 * @category  PHP
  8 * @package   PHP_CodeSniffer
  9 * @author    Greg Sherwood <gsherwood@squiz.net>
 10 * @author    Marc McIntyre <mmcintyre@squiz.net>
 11 * @copyright 2006 Squiz Pty Ltd (ABN 77 084 670 600)
 12 * @license   http://matrix.squiz.net/developer/tools/php_cs/licence BSD Licence
 13 * @version   CVS: $Id: 6660e122e7822915b6358742729c7c2e3e4ac1b4 $
 14 * @link      http://pear.php.net/package/PHP_CodeSniffer
 15 */
 16
 17if (class_exists('PHP_CodeSniffer_CommentParser_ClassCommentParser', true) === false) {
 18    $error = 'Class PHP_CodeSniffer_CommentParser_ClassCommentParser not found';
 19    throw new PHP_CodeSniffer_Exception($error);
 20}
 21
 22if (class_exists('XLite_Sniffs_PHP_Commenting_FileCommentSniff', true) === false) {
 23    $error = 'Class XLite_Sniffs_PHP_Commenting_FileCommentSniff not found';
 24    throw new PHP_CodeSniffer_Exception($error);
 25}
 26
 27/**
 28 * Parses and verifies the doc comments for classes.
 29 *
 30 * Verifies that :
 31 * <ul>
 32 *  <li>A doc comment exists.</li>
 33 *  <li>There is a blank newline after the short description.</li>
 34 *  <li>There is a blank newline between the long and short description.</li>
 35 *  <li>There is a blank newline between the long description and tags.</li>
 36 *  <li>Check the order of the tags.</li>
 37 *  <li>Check the indentation of each tag.</li>
 38 *  <li>Check required and optional tags and the format of their content.</li>
 39 * </ul>
 40 *
 41 * @category  PHP
 42 * @package   PHP_CodeSniffer
 43 * @author    Greg Sherwood <gsherwood@squiz.net>
 44 * @author    Marc McIntyre <mmcintyre@squiz.net>
 45 * @copyright 2006 Squiz Pty Ltd (ABN 77 084 670 600)
 46 * @license   http://matrix.squiz.net/developer/tools/php_cs/licence BSD Licence
 47 * @version   Release: 1.2.0RC1
 48 * @link      http://pear.php.net/package/PHP_CodeSniffer
 49 */
 50class XLite_Sniffs_PHP_Commenting_ClassCommentSniff extends XLite_Sniffs_PHP_Commenting_FileCommentSniff
 51{
 52
 53    protected $tags = array(
 54    	'package'    => array(
 55        	'required'       => true,
 56            'allow_multiple' => false,
 57            'order_text'     => 'precedes @subpackage',
 58        ),
 59        'subpackage' => array(
 60        	'required'       => false,
 61            'allow_multiple' => false,
 62            'order_text'     => 'follows @package',
 63		),
 64		'see'        => array(
 65        	'required'       => false,
 66            'allow_multiple' => false,
 67            'order_text'     => 'follows @link',
 68        ),
 69        'since'      => array(
 70            'required'       => false,
 71            'allow_multiple' => false,
 72            'order_text'     => 'follows @see (if used) or @link',
 73        ),
 74        'deprecated' => array(
 75            'required'       => false,
 76            'allow_multiple' => false,
 77            'order_text'     => 'follows @since (if used) or @see (if used) or @link',
 78        ),
 79        'Entity' => array(
 80            'required'       => false,
 81            'allow_multiple' => false,
 82            'order_text'     => 'follows @since (if used) or @see (if used) or @link or @deprecated (if used)',
 83        ),
 84        'Table' => array(
 85            'required'       => false,
 86            'allow_multiple' => false,
 87            'order_text'     => 'follows @Entity',
 88        ),
 89        'Index'      => array(
 90            'required'       => false,
 91            'allow_multiple' => false,
 92            'order_text'     => 'follows @Table',
 93		),
 94        'UniqueConstraint'      => array(
 95            'required'       => false,
 96            'allow_multiple' => false,
 97            'order_text'     => 'follows @Table',
 98        ),
 99        'HasLifecycleCallbacks' => array(
100            'required'       => false,
101            'allow_multiple' => false,
102            'order_text'     => 'follows @Table',
103        ),
104        'InheritanceType' => array(
105            'required'       => false,
106            'allow_multiple' => false,
107            'order_text'     => 'follows @Table',
108        ),
109        'DiscriminatorColumn' => array(
110            'required'       => false,
111            'allow_multiple' => false,
112            'order_text'     => 'follows @Table',
113        ),
114        'DiscriminatorMap' => array(
115            'required'       => false,
116            'allow_multiple' => false,
117            'order_text'     => 'follows @Table',
118        ),
119        'MappedSuperclass' => array(
120            'required'       => false,
121            'allow_multiple' => false,
122            'order_text'     => 'follows @Table',
123        ),
124        'ListChild' => array(
125            'required'       => false,
126            'allow_multiple' => true,
127            'order_text'     => 'any place',
128        ),
129	);
130
131    protected $reqCodeRequire = 'REQ.PHP.4.4.3';
132    protected $reqCodePHPVersion = false;
133    protected $reqCodeForbidden = 'REQ.PHP.4.4.7';
134    protected $reqCodeOnlyOne = 'REQ.PHP.4.4.6';
135
136    protected $docBlock = 'class';
137
138
139    /**
140     * Returns an array of tokens this test wants to listen for.
141     *
142     * @return array
143     */
144    public function register()
145    {
146        return array(
147                T_CLASS,
148                T_INTERFACE,
149               );
150
151    }//end register()
152
153
154    /**
155     * Processes this test, when one of its tokens is encountered.
156     *
157     * @param PHP_CodeSniffer_File $phpcsFile The file being scanned.
158     * @param int                  $stackPtr  The position of the current token
159     *                                        in the stack passed in $tokens.
160     *
161     * @return void
162     */
163    public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr)
164    {
165        $this->currentFile = $phpcsFile;
166
167        $tokens = $phpcsFile->getTokens();
168        $type   = strtolower($tokens[$stackPtr]['content']);
169        $find   = array(
170                   T_ABSTRACT,
171                   T_WHITESPACE,
172                   T_FINAL,
173                  );
174
175        // Extract the class comment docblock.
176        $commentEnd = $phpcsFile->findPrevious($find, ($stackPtr - 1), null, true);
177
178        if ($commentEnd !== false && $tokens[$commentEnd]['code'] === T_COMMENT) {
179            $error = "You must use \"/**\" style comments for a $type comment";
180            $phpcsFile->addError($this->getReqPrefix('REQ.PHP.4.4.5') . $error, $stackPtr);
181            return;
182        } else if ($commentEnd === false
183            || $tokens[$commentEnd]['code'] !== T_DOC_COMMENT
184        ) {
185            $phpcsFile->addError($this->getReqPrefix('REQ.PHP.4.4.1') . "Missing $type doc comment", $stackPtr);
186            return;
187        }
188
189        $commentStart = ($phpcsFile->findPrevious(T_DOC_COMMENT, ($commentEnd - 1), null, true) + 1);
190        $commentNext  = $phpcsFile->findPrevious(T_WHITESPACE, ($commentEnd + 1), $stackPtr, false, $phpcsFile->eolChar);
191
192        // Distinguish file and class comment.
193        $prevClassToken = $phpcsFile->findPrevious(T_CLASS, ($stackPtr - 1));
194        if ($prevClassToken === false) {
195            // This is the first class token in this file, need extra checks.
196            $prevNonComment = $phpcsFile->findPrevious(T_DOC_COMMENT, ($commentStart - 1), null, true);
197            if ($prevNonComment !== false) {
198                $prevComment = $phpcsFile->findPrevious(T_DOC_COMMENT, ($prevNonComment - 1));
199                if ($prevComment === false) {
200                    // There is only 1 doc comment between open tag and class token.
201                    $newlineToken = $phpcsFile->findNext(T_WHITESPACE, ($commentEnd + 1), $stackPtr, false, $phpcsFile->eolChar);
202                    if ($newlineToken !== false) {
203                        $newlineToken = $phpcsFile->findNext(
204                            T_WHITESPACE,
205                            ($newlineToken + 1),
206                            $stackPtr,
207                            false,
208                            $phpcsFile->eolChar
209                        );
210
211                        if ($newlineToken !== false) {
212                            // Blank line between the class and the doc block.
213                            // The doc block is most likely a file comment.
214                            $error = "Missing $type doc comment";
215                            $phpcsFile->addError($this->getReqPrefix('REQ.PHP.4.1.6') . $error, ($stackPtr + 1));
216                            return;
217                        }
218                    }//end if
219                }//end if
220            }//end if
221        }//end if
222
223        $comment = $phpcsFile->getTokensAsString(
224            $commentStart,
225            ($commentEnd - $commentStart + 1)
226        );
227
228        // Parse the class comment.docblock.
229        try {
230            $this->commentParser = new PHP_CodeSniffer_CommentParser_ClassCommentParser($comment, $phpcsFile);
231            $this->commentParser->parse();
232        } catch (PHP_CodeSniffer_CommentParser_ParserException $e) {
233            $line = ($e->getLineWithinComment() + $commentStart);
234            $phpcsFile->addError($this->getReqPrefix('REQ.PHP.4.1.1') . $e->getMessage(), $line);
235            return;
236        }
237
238        $comment = $this->commentParser->getComment();
239        if (is_null($comment) === true) {
240            $error = ucfirst($type).' doc comment is empty';
241            $phpcsFile->addError($this->getReqPrefix('REQ.PHP.4.4.2') . $error, $commentStart);
242            return;
243        }
244
245        // No extra newline before short description.
246        $short        = $comment->getShortComment();
247        $newlineCount = 0;
248        $newlineSpan  = strspn($short, $phpcsFile->eolChar);
249        if ($short !== '' && $newlineSpan > 0) {
250            $line  = ($newlineSpan > 1) ? 'newlines' : 'newline';
251            $error = "Extra $line found before $type comment short description";
252            $phpcsFile->addError($this->getReqPrefix('REQ.PHP.4.1.7') . $error, ($commentStart + 1));
253        }
254
255        $newlineCount = (substr_count($short, $phpcsFile->eolChar) + 1);
256
257        // Exactly one blank line between short and long description.
258        $long = $comment->getLongComment();
259        if (empty($long) === false) {
260            $between        = $comment->getWhiteSpaceBetween();
261            $newlineBetween = substr_count($between, $phpcsFile->eolChar);
262            if ($newlineBetween !== 2) {
263                $error = "There must be exactly one blank line between descriptions in $type comments";
264                $phpcsFile->addError($this->getReqPrefix('REQ.PHP.4.1.18') . $error, ($commentStart + $newlineCount + 1));
265            }
266
267            $newlineCount += $newlineBetween;
268        }
269
270        // Exactly one blank line before tags.
271        $tags = $this->commentParser->getTagOrders();
272        if (count($tags) > 1) {
273            $newlineSpan = $comment->getNewlineAfter();
274            if ($newlineSpan !== 2) {
275                $error = "There must be exactly one blank line before the tags in $type comments";
276                if ($long !== '') {
277                    $newlineCount += (substr_count($long, $phpcsFile->eolChar) - $newlineSpan + 1);
278                }
279
280                $phpcsFile->addError($this->getReqPrefix('REQ.PHP.4.1.18') . $error, ($commentStart + $newlineCount));
281                $short = rtrim($short, $phpcsFile->eolChar.' ');
282            }
283        }
284
285        // Check each tag.
286        $this->processTags($commentStart, $commentEnd);
287
288    }//end process()
289
290}//end class
291
292?>