├── .gitignore ├── TESTING.md ├── .travis.yml ├── Symfony3Custom ├── Tests │ ├── Commenting │ │ ├── FunctionCommentUnitTest.inc │ │ └── FunctionCommentUnitTest.php │ ├── Objects │ │ ├── ObjectInstantiationUnitTest.inc │ │ └── ObjectInstantiationUnitTest.php │ ├── Formatting │ │ ├── BlankLineBeforeReturnUnitTest.inc │ │ └── BlankLineBeforeReturnUnitTest.php │ └── Arrays │ │ ├── MultiLineArrayCommaUnitTest.inc │ │ └── MultiLineArrayCommaUnitTest.php ├── Sniffs │ ├── WhiteSpace │ │ ├── CommaSpacingSniff.php │ │ ├── BinaryOperatorSpacingSniff.php │ │ ├── AssignmentSpacingSniff.php │ │ ├── DiscourageFitzinatorSniff.php │ │ └── FunctionClosingBraceSpaceSniff.php │ ├── Scope │ │ └── MethodScopeSniff.php │ ├── Classes │ │ ├── MultipleClassesOneFileSniff.php │ │ └── PropertyDeclarationSniff.php │ ├── Objects │ │ └── ObjectInstantiationSniff.php │ ├── Arrays │ │ └── MultiLineArrayCommaSniff.php │ ├── Formatting │ │ └── BlankLineBeforeReturnSniff.php │ ├── Functions │ │ └── ScopeOrderSniff.php │ ├── Commenting │ │ ├── ClassCommentSniff.php │ │ └── FunctionCommentSniff.php │ └── NamingConventions │ │ └── ValidClassNameSniff.php └── ruleset.xml ├── CONTRIBUTING.md ├── composer.json └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | cache.properties 2 | phpunit.xml 3 | composer.lock 4 | composer.phar 5 | vendor/ 6 | build/ 7 | -------------------------------------------------------------------------------- /TESTING.md: -------------------------------------------------------------------------------- 1 | Testing 2 | ======= 3 | 4 | Contributions to this repository will only be accepted if all tests pass successfully: 5 | 6 | * PHP syntax/lint checks 7 | * Unit tests: [PHPUnit](https://phpunit.de/) 8 | * Coding standard-checks: [PHP_CodeSniffer](https://github.com/squizlabs/PHP_CodeSniffer/wiki) 9 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: php 2 | 3 | php: 4 | - 5.3 5 | - 5.4 6 | - 5.5 7 | - 5.6 8 | - 7.0 9 | - hhvm 10 | 11 | script: 12 | - ant travis 13 | 14 | branches: 15 | except: 16 | - jenkins 17 | 18 | notifications: 19 | email: 20 | - dev@escapestudios.com 21 | -------------------------------------------------------------------------------- /Symfony3Custom/Tests/Commenting/FunctionCommentUnitTest.inc: -------------------------------------------------------------------------------- 1 | foo); 17 | new Foo\Bar(); 18 | new Foo\Bar(true); 19 | new Foo\Bar($this->foo); 20 | new \Foo\Bar(); 21 | new \Foo\Bar(true); 22 | new \Foo\Bar($this->foo); 23 | new $foo(); 24 | new $foo(true); 25 | new $foo($this->foo); 26 | new static(); 27 | new static(true); 28 | new static($this->foo); 29 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | Contributing 2 | ============ 3 | 4 | 1. Fork it 5 | 2. Create your feature branch (`git checkout -b my-new-feature`) 6 | 3. Commit your changes (`git commit -am 'Add some feature'`) 7 | 4. [Add tests for your changes](https://github.com/escapestudios/Symfony2-coding-standard/blob/master/TESTING.md) 8 | 4. Push your changes to your feature branch (`git push origin my-new-feature`) 9 | 5. Create a new Pull Request (PR) 10 | 11 | ## Testing 12 | Contributions will only be accepted if they are fully tested as specified in [TESTING.md](https://github.com/escapestudios/Symfony2-coding-standard/blob/master/TESTING.md). 13 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "endouble/symfony3-custom-coding-standard", 3 | "type": "coding-standard", 4 | "description": "Customized CodeSniffer ruleset for the Symfony3 projects", 5 | "keywords": ["Symfony3", "coding standard", "phpcs"], 6 | "homepage": "https://github.com/Endouble/Symfony3-coding-standard", 7 | "license": "MIT", 8 | "authors": [ 9 | { 10 | "name": "David Joos", 11 | "email": "david.joos@escapestudios.com" 12 | } 13 | ], 14 | "extra": { 15 | "branch-alias": { 16 | "dev-master": "2.x-dev" 17 | } 18 | }, 19 | "minimum-stability": "dev", 20 | "require": { 21 | "squizlabs/php_codesniffer": "~2.0" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Symfony3Custom/Tests/Formatting/BlankLineBeforeReturnUnitTest.inc: -------------------------------------------------------------------------------- 1 | 11 | * @license http://spdx.org/licenses/MIT MIT License 12 | * @link https://github.com/escapestudios/Symfony3Custom-coding-standard 13 | */ 14 | 15 | /** 16 | * Unit test class for the FunctionComment sniff. 17 | * 18 | * A sniff unit test checks a .inc file for expected violations of a single 19 | * coding standard. Expected errors and warnings are stored in this class. 20 | * 21 | * PHP version 5 22 | * 23 | * @category PHP 24 | * @package Symfony3Custom-coding-standard 25 | * @author Authors 26 | * @license http://spdx.org/licenses/MIT MIT License 27 | * @link https://github.com/escapestudios/Symfony3Custom-coding-standard 28 | */ 29 | class Symfony3Custom_Tests_Commenting_FunctionCommentUnitTest 30 | extends AbstractSniffUnitTest 31 | { 32 | /** 33 | * Returns the lines where errors should occur. 34 | * 35 | * The key of the array should represent the line number and the value 36 | * should represent the number of errors that should occur on that line. 37 | * 38 | * @return array 39 | */ 40 | public function getErrorList() 41 | { 42 | return array( 43 | 5 => 1, 44 | ); 45 | } 46 | 47 | /** 48 | * Returns the lines where warnings should occur. 49 | * 50 | * The key of the array should represent the line number and the value 51 | * should represent the number of warnings that should occur on that line. 52 | * 53 | * @return array(int => int) 54 | */ 55 | protected function getWarningList() 56 | { 57 | return array(); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /Symfony3Custom/Tests/Formatting/BlankLineBeforeReturnUnitTest.php: -------------------------------------------------------------------------------- 1 | 11 | * @license http://spdx.org/licenses/MIT MIT License 12 | * @link https://github.com/escapestudios/Symfony3Custom-coding-standard 13 | */ 14 | 15 | /** 16 | * Unit test class for the BlankLineBeforeReturn sniff. 17 | * 18 | * A sniff unit test checks a .inc file for expected violations of a single 19 | * coding standard. Expected errors and warnings are stored in this class. 20 | * 21 | * PHP version 5 22 | * 23 | * @category PHP 24 | * @package Symfony3Custom-coding-standard 25 | * @author Authors 26 | * @license http://spdx.org/licenses/MIT MIT License 27 | * @link https://github.com/escapestudios/Symfony3Custom-coding-standard 28 | */ 29 | class Symfony3Custom_Tests_Formatting_BlankLineBeforeReturnUnitTest 30 | extends AbstractSniffUnitTest 31 | { 32 | /** 33 | * Returns the lines where errors should occur. 34 | * 35 | * The key of the array should represent the line number and the value 36 | * should represent the number of errors that should occur on that line. 37 | * 38 | * @return array(int => int) 39 | */ 40 | public function getErrorList() 41 | { 42 | return array( 43 | 37 => 1 44 | ); 45 | } 46 | 47 | /** 48 | * Returns the lines where warnings should occur. 49 | * 50 | * The key of the array should represent the line number and the value 51 | * should represent the number of errors that should occur on that line. 52 | * 53 | * @return array(int => int) 54 | */ 55 | public function getWarningList() 56 | { 57 | return array(); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /Symfony3Custom/Tests/Arrays/MultiLineArrayCommaUnitTest.php: -------------------------------------------------------------------------------- 1 | 11 | * @license http://spdx.org/licenses/MIT MIT License 12 | * @link https://github.com/escapestudios/Symfony3Custom-coding-standard 13 | */ 14 | 15 | /** 16 | * Unit test class for the MultiLineArrayComma sniff. 17 | * 18 | * A sniff unit test checks a .inc file for expected violations of a single 19 | * coding standard. Expected errors and warnings are stored in this class. 20 | * 21 | * PHP version 5 22 | * 23 | * @category PHP 24 | * @package Symfony3Custom-coding-standard 25 | * @author Authors 26 | * @license http://spdx.org/licenses/MIT MIT License 27 | * @link https://github.com/escapestudios/Symfony3Custom-coding-standard 28 | */ 29 | class Symfony3Custom_Tests_Arrays_MultiLineArrayCommaUnitTest 30 | extends AbstractSniffUnitTest 31 | { 32 | /** 33 | * Returns the lines where errors should occur. 34 | * 35 | * The key of the array should represent the line number and the value 36 | * should represent the number of errors that should occur on that line. 37 | * 38 | * @return array 39 | */ 40 | public function getErrorList() 41 | { 42 | return array( 43 | 11 => 1, 44 | 24 => 1, 45 | 37 => 1, 46 | 47 => 1, 47 | 60 => 1, 48 | 70 => 1, 49 | ); 50 | } 51 | 52 | /** 53 | * Returns the lines where warnings should occur. 54 | * 55 | * The key of the array should represent the line number and the value 56 | * should represent the number of errors that should occur on that line. 57 | * 58 | * @return array(int => int) 59 | */ 60 | public function getWarningList() 61 | { 62 | return array(); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /Symfony3Custom/Tests/Objects/ObjectInstantiationUnitTest.php: -------------------------------------------------------------------------------- 1 | 11 | * @license http://spdx.org/licenses/MIT MIT License 12 | * @link https://github.com/escapestudios/Symfony3Custom-coding-standard 13 | */ 14 | 15 | /** 16 | * Unit test class for the ObjectInstantiation sniff. 17 | * 18 | * A sniff unit test checks a .inc file for expected violations of a single 19 | * coding standard. Expected errors and warnings are stored in this class. 20 | * 21 | * PHP version 5 22 | * 23 | * @category PHP 24 | * @package Symfony3Custom-coding-standard 25 | * @author Authors 26 | * @license http://spdx.org/licenses/MIT MIT License 27 | * @link https://github.com/escapestudios/Symfony3Custom-coding-standard 28 | */ 29 | class Symfony3Custom_Tests_Objects_ObjectInstantiationUnitTest 30 | extends AbstractSniffUnitTest 31 | { 32 | /** 33 | * Returns the lines where errors should occur. 34 | * 35 | * The key of the array should represent the line number and the value 36 | * should represent the number of errors that should occur on that line. 37 | * 38 | * @return array 39 | */ 40 | public function getErrorList() 41 | { 42 | return array( 43 | 4 => 1, 44 | 5 => 1, 45 | 6 => 1, 46 | 7 => 1, 47 | 8 => 1, 48 | 9 => 1, 49 | 10 => 1, 50 | ); 51 | } 52 | 53 | /** 54 | * Returns the lines where warnings should occur. 55 | * 56 | * The key of the array should represent the line number and the value 57 | * should represent the number of errors that should occur on that line. 58 | * 59 | * @return array(int => int) 60 | */ 61 | public function getWarningList() 62 | { 63 | return array(); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /Symfony3Custom/Sniffs/WhiteSpace/CommaSpacingSniff.php: -------------------------------------------------------------------------------- 1 | 11 | * @license http://spdx.org/licenses/MIT MIT License 12 | * @link https://github.com/escapestudios/Symfony3Custom-coding-standard 13 | */ 14 | 15 | /** 16 | * Symfony3Custom_Sniffs_WhiteSpace_CommaSpacingSniff. 17 | * 18 | * Throws warnings if comma isn't followed by a whitespace. 19 | * 20 | * PHP version 5 21 | * 22 | * @category PHP 23 | * @package Symfony3Custom-coding-standard 24 | * @author Authors 25 | * @license http://spdx.org/licenses/MIT MIT License 26 | * @link https://github.com/escapestudios/Symfony3Custom-coding-standard 27 | */ 28 | class Symfony3Custom_Sniffs_WhiteSpace_CommaSpacingSniff 29 | implements PHP_CodeSniffer_Sniff 30 | { 31 | /** 32 | * A list of tokenizers this sniff supports. 33 | * 34 | * @var array 35 | */ 36 | public $supportedTokenizers = array( 37 | 'PHP', 38 | ); 39 | 40 | /** 41 | * Returns an array of tokens this test wants to listen for. 42 | * 43 | * @return array 44 | */ 45 | public function register() 46 | { 47 | return array( 48 | T_COMMA, 49 | ); 50 | 51 | } 52 | 53 | /** 54 | * Processes this test, when one of its tokens is encountered. 55 | * 56 | * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. 57 | * @param int $stackPtr The position of the current token 58 | * in the stack passed in $tokens. 59 | * 60 | * @return void 61 | */ 62 | public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) 63 | { 64 | $tokens = $phpcsFile->getTokens(); 65 | $line = $tokens[$stackPtr]['line']; 66 | 67 | if ($tokens[$stackPtr + 1]['line'] === $line 68 | && $tokens[$stackPtr + 1]['code'] !== T_WHITESPACE 69 | ) { 70 | $phpcsFile->addError( 71 | 'Add a single space after each comma delimiter', 72 | $stackPtr, 73 | 'Invalid' 74 | ); 75 | } 76 | 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /Symfony3Custom/Sniffs/WhiteSpace/BinaryOperatorSpacingSniff.php: -------------------------------------------------------------------------------- 1 | 11 | * @license http://spdx.org/licenses/MIT MIT License 12 | * @link https://github.com/escapestudios/Symfony3Custom-coding-standard 13 | */ 14 | 15 | /** 16 | * Symfony3Custom_Sniffs_WhiteSpace_BinaryOperatorSpacingSniff. 17 | * 18 | * Throws warnings if a binary operator isn't surrounded with whitespace. 19 | * 20 | * PHP version 5 21 | * 22 | * @category PHP 23 | * @package Symfony3Custom-coding-standard 24 | * @author Authors 25 | * @license http://spdx.org/licenses/MIT MIT License 26 | * @link https://github.com/escapestudios/Symfony3Custom-coding-standard 27 | */ 28 | class Symfony3Custom_Sniffs_WhiteSpace_BinaryOperatorSpacingSniff 29 | implements PHP_CodeSniffer_Sniff 30 | { 31 | /** 32 | * A list of tokenizers this sniff supports. 33 | * 34 | * @var array 35 | */ 36 | public $supportedTokenizers = array( 37 | 'PHP', 38 | ); 39 | 40 | /** 41 | * Returns an array of tokens this test wants to listen for. 42 | * 43 | * @return array 44 | */ 45 | public function register() 46 | { 47 | return PHP_CodeSniffer_Tokens::$comparisonTokens; 48 | 49 | } 50 | 51 | /** 52 | * Processes this test, when one of its tokens is encountered. 53 | * 54 | * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. 55 | * @param int $stackPtr The position of the current token 56 | * in the stack passed in $tokens. 57 | * 58 | * @return void 59 | */ 60 | public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) 61 | { 62 | $tokens = $phpcsFile->getTokens(); 63 | 64 | if ($tokens[$stackPtr -1]['code'] !== T_WHITESPACE 65 | || $tokens[$stackPtr +1]['code'] !== T_WHITESPACE 66 | ) { 67 | $phpcsFile->addError( 68 | 'Add a single space around binary operators', 69 | $stackPtr, 70 | 'Invalid' 71 | ); 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /Symfony3Custom/Sniffs/WhiteSpace/AssignmentSpacingSniff.php: -------------------------------------------------------------------------------- 1 | 11 | * @license http://spdx.org/licenses/MIT MIT License 12 | * @link https://github.com/escapestudios/Symfony3Custom-coding-standard 13 | */ 14 | 15 | /** 16 | * Symfony3Custom_Sniffs_WhiteSpace_AssignmentSpacingSniff. 17 | * 18 | * Throws warnings if an assignment operator isn't surrounded with whitespace. 19 | * 20 | * PHP version 5 21 | * 22 | * @category PHP 23 | * @package Symfony3Custom-coding-standard 24 | * @author Authors 25 | * @license http://spdx.org/licenses/MIT MIT License 26 | * @link https://github.com/escapestudios/Symfony3Custom-coding-standard 27 | */ 28 | class Symfony3Custom_Sniffs_WhiteSpace_AssignmentSpacingSniff 29 | implements PHP_CodeSniffer_Sniff 30 | { 31 | /** 32 | * A list of tokenizers this sniff supports. 33 | * 34 | * @var array 35 | */ 36 | public $supportedTokenizers = array( 37 | 'PHP', 38 | ); 39 | 40 | /** 41 | * Returns an array of tokens this test wants to listen for. 42 | * 43 | * @return array 44 | */ 45 | public function register() 46 | { 47 | return PHP_CodeSniffer_Tokens::$assignmentTokens; 48 | 49 | } 50 | 51 | /** 52 | * Processes this test, when one of its tokens is encountered. 53 | * 54 | * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. 55 | * @param int $stackPtr The position of the current token 56 | * in the stack passed in $tokens. 57 | * 58 | * @return void 59 | */ 60 | public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) 61 | { 62 | $tokens = $phpcsFile->getTokens(); 63 | 64 | if (($tokens[$stackPtr - 1]['code'] !== T_WHITESPACE 65 | || $tokens[$stackPtr + 1]['code'] !== T_WHITESPACE) 66 | && $tokens[$stackPtr - 1]['content'] !== 'strict_types' 67 | ) { 68 | $phpcsFile->addError( 69 | 'Add a single space around assignment operators', 70 | $stackPtr, 71 | 'Invalid' 72 | ); 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /Symfony3Custom/Sniffs/Scope/MethodScopeSniff.php: -------------------------------------------------------------------------------- 1 | 11 | * @license http://spdx.org/licenses/MIT MIT License 12 | * @link https://github.com/escapestudios/Symfony3Custom-coding-standard 13 | */ 14 | 15 | if (class_exists('PHP_CodeSniffer_Standards_AbstractScopeSniff', true) === false) { 16 | throw new PHP_CodeSniffer_Exception( 17 | 'Class PHP_CodeSniffer_Standards_AbstractScopeSniff not found' 18 | ); 19 | } 20 | 21 | /** 22 | * Verifies that class members have scope modifiers. 23 | * 24 | * PHP version 5 25 | * 26 | * @category PHP 27 | * @package Symfony3Custom-coding-standard 28 | * @author Authors 29 | * @license http://spdx.org/licenses/MIT MIT License 30 | * @link http://pear.php.net/package/PHP_CodeSniffer 31 | */ 32 | class Symfony3Custom_Sniffs_Scope_MethodScopeSniff 33 | extends PHP_CodeSniffer_Standards_AbstractScopeSniff 34 | { 35 | /** 36 | * Constructs a Symfony3Custom_Sniffs_Scope_MethodScopeSniff. 37 | */ 38 | public function __construct() 39 | { 40 | parent::__construct(array(T_CLASS), array(T_FUNCTION)); 41 | 42 | } 43 | 44 | /** 45 | * Processes the function tokens within the class. 46 | * 47 | * @param PHP_CodeSniffer_File $phpcsFile The file where this token was found. 48 | * @param int $stackPtr The position where the token was found. 49 | * @param int $currScope The current scope opener token. 50 | * 51 | * @return void 52 | */ 53 | protected function processTokenWithinScope( 54 | PHP_CodeSniffer_File $phpcsFile, 55 | $stackPtr, 56 | $currScope 57 | ) { 58 | $tokens = $phpcsFile->getTokens(); 59 | 60 | $methodName = $phpcsFile->getDeclarationName($stackPtr); 61 | if ($methodName === null) { 62 | // Ignore closures. 63 | return; 64 | } 65 | 66 | $modifier = $phpcsFile->findPrevious( 67 | PHP_CodeSniffer_Tokens::$scopeModifiers, 68 | $stackPtr 69 | ); 70 | 71 | if (($modifier === false) 72 | || ($tokens[$modifier]['line'] !== $tokens[$stackPtr]['line']) 73 | ) { 74 | $error = 'No scope modifier specified for function "%s"'; 75 | $data = array($methodName); 76 | $phpcsFile->addError($error, $stackPtr, 'Missing', $data); 77 | } 78 | 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /Symfony3Custom/Sniffs/WhiteSpace/DiscourageFitzinatorSniff.php: -------------------------------------------------------------------------------- 1 | 11 | * @license http://spdx.org/licenses/MIT MIT License 12 | * @link https://github.com/escapestudios/Symfony3Custom-coding-standard 13 | */ 14 | 15 | /** 16 | * Symfony3Custom_Sniffs_WhiteSpace_DiscourageFitzinatorSniff. 17 | * 18 | * Throws warnings if a file contains trailing whitespace. 19 | * 20 | * PHP version 5 21 | * 22 | * @category PHP 23 | * @package Symfony3Custom-coding-standard 24 | * @author Authors 25 | * @license http://spdx.org/licenses/MIT MIT License 26 | * @link https://github.com/escapestudios/Symfony3Custom-coding-standard 27 | */ 28 | class Symfony3Custom_Sniffs_WhiteSpace_DiscourageFitzinatorSniff 29 | implements PHP_CodeSniffer_Sniff 30 | { 31 | /** 32 | * A list of tokenizers this sniff supports. 33 | * 34 | * @var array 35 | */ 36 | public $supportedTokenizers = array( 37 | 'PHP', 38 | 'JS', 39 | 'CSS', 40 | ); 41 | 42 | 43 | /** 44 | * Returns an array of tokens this test wants to listen for. 45 | * 46 | * @return array 47 | */ 48 | public function register() 49 | { 50 | return array(T_WHITESPACE); 51 | 52 | } 53 | 54 | /** 55 | * Processes this test, when one of its tokens is encountered. 56 | * 57 | * @param PHP_CodeSniffer_File $phpcsFile All the tokens found in the document. 58 | * @param int $stackPtr The position of the current token in 59 | * the stack passed in $tokens. 60 | * 61 | * @return void 62 | */ 63 | public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) 64 | { 65 | $tokens = $phpcsFile->getTokens(); 66 | 67 | // Make sure this is trailing whitespace. 68 | $line = $tokens[$stackPtr]['line']; 69 | if (($stackPtr < count($tokens) - 1) 70 | && $tokens[($stackPtr + 1)]['line'] === $line 71 | ) { 72 | return; 73 | } 74 | 75 | if (strpos($tokens[$stackPtr]['content'], "\n") > 0 76 | || strpos($tokens[$stackPtr]['content'], "\r") > 0 77 | ) { 78 | $warning = 'Please trim any trailing whitespace'; 79 | $phpcsFile->addWarning($warning, $stackPtr); 80 | } 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /Symfony3Custom/Sniffs/Classes/MultipleClassesOneFileSniff.php: -------------------------------------------------------------------------------- 1 | 11 | * @license http://spdx.org/licenses/MIT MIT License 12 | * @link https://github.com/escapestudios/Symfony3Custom-coding-standard 13 | */ 14 | 15 | /** 16 | * Throws errors if multiple classes are defined in a single file. 17 | * 18 | * PHP version 5 19 | * 20 | * Symfony coding standard specifies: "Define one class per file;" 21 | * 22 | * @category PHP 23 | * @package Symfony3Custom-coding-standard 24 | * @author Authors 25 | * @license http://spdx.org/licenses/MIT MIT License 26 | * @link https://github.com/escapestudios/Symfony3Custom-coding-standard 27 | */ 28 | class Symfony3Custom_Sniffs_Classes_MultipleClassesOneFileSniff 29 | implements PHP_CodeSniffer_Sniff 30 | { 31 | /** 32 | * The number of times the T_CLASS token is encountered in the file. 33 | * 34 | * @var int 35 | */ 36 | protected $classCount = 0; 37 | 38 | /** 39 | * The current file this class is operating on. 40 | * 41 | * @var string 42 | */ 43 | protected $currentFile; 44 | 45 | /** 46 | * A list of tokenizers this sniff supports. 47 | * 48 | * @var array 49 | */ 50 | public $supportedTokenizers = array( 51 | 'PHP', 52 | ); 53 | 54 | /** 55 | * Returns an array of tokens this test wants to listen for. 56 | * 57 | * @return array 58 | */ 59 | public function register() 60 | { 61 | return array(T_CLASS); 62 | } 63 | 64 | /** 65 | * Processes this test, when one of its tokens is encountered. 66 | * 67 | * @param PHP_CodeSniffer_File $phpcsFile All the tokens found in the document. 68 | * @param int $stackPtr The position of the current token in 69 | * the stack passed in $tokens. 70 | * 71 | * @return void 72 | */ 73 | public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) 74 | { 75 | if ($this->currentFile !== $phpcsFile->getFilename()) { 76 | $this->classCount = 0; 77 | $this->currentFile = $phpcsFile->getFilename(); 78 | } 79 | 80 | $this->classCount++; 81 | 82 | if ($this->classCount > 1) { 83 | $phpcsFile->addError( 84 | 'Multiple classes defined in a single file', 85 | $stackPtr 86 | ); 87 | } 88 | 89 | return; 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Symfony3 Custom PHP CodeSniffer Coding Standard 2 | 3 | This is a fork of https://github.com/djoos/Symfony2-coding-standard 4 | These are the Symfony2 standards, but tweaked to meet some needs we have in our CSB project, for example to comply with 5 | [PSR-12](https://github.com/php-fig/fig-standards/blob/master/proposed/extended-coding-style-guide.md) for PHP 7 6 | 7 | ## Installation 8 | 9 | ### Composer 10 | 11 | This standard can be installed with the [Composer](https://getcomposer.org/) dependency manager. 12 | 13 | 1. Add the repository to your composer.json: 14 | ```json 15 | "repositories": [ 16 | { 17 | "type": "vcs", 18 | "url": "git@github.com:Endouble/Symfony3-custom-coding-standard" 19 | } 20 | ``` 21 | 22 | 2. Add the coding standard as a dependency of your project 23 | 24 | ```json 25 | "require-dev": { 26 | "endouble/symfony3-custom-coding-standard": "^2.10" 27 | }, 28 | ``` 29 | 30 | 3. Add the coding standard to the PHP_CodeSniffer install path 31 | 32 | The path is relative to the php_codesniffer install path. This is important to make it work both in your vagrant, local machine and PHPStorm 33 | 34 | bin/phpcs --config-set installed_paths ../../endouble/symfony3-custom-coding-standard 35 | 36 | 4. Check the installed coding standards for "Symfony2" 37 | 38 | bin/phpcs -i 39 | 40 | 5. Done! 41 | 42 | bin/phpcs --standard=Symfony3Custom /path/to/code 43 | 44 | 6. (optional) Set up PHPStorm 45 | 46 | - configure code sniffer under Languages & Frameworks -> PHP -> Code Sniffer 47 | - Go to Editor -> Inspections -> PHP Code sniffer, refresh the standards and select Symfony3Custom 48 | 49 | ## Customizations 50 | 51 | The following adjustments have been made to the original standard: 52 | 53 | In Sniff/WhiteSpace/AssignmentSpacingSniff: 54 | - Added an exception for ```declare(strict_types=1);``` to comply with [PSR-12](https://github.com/php-fig/fig-standards/blob/master/proposed/extended-coding-style-guide.md#3-declare-statements-namespace-and-use-declarations) 55 | 56 | In Sniff/WhiteSpace/FunctionalClosingBraceSniff: 57 | - copied from Squiz and adapted to have no blank line at the end of a function 58 | 59 | In Sniff/Commenting/FunctionCommentSniff: 60 | - check for 1 blank line above a docblock 61 | - don't check docblocks for test and setUp methods (PHPunit, would be blank) 62 | - do check protected and private methods for docblocks 63 | 64 | In Sniff/NamingConventions/ValidClassNameSniff 65 | - remove the abstract class name rule 66 | 67 | In ruleset.xml 68 | - Disabled the class comment rule 69 | - Changed the concatenation spacing rule, for readability, to require 1 space around concatenation dot, instead of no spaces as the [Symfony](https://symfony.com/doc/current/contributing/code/standards.html#structure) standard requires. 70 | - Re-enabled the blank line check from superfluousWhitespace (disabled in PSR-2) 71 | 72 | -------------------------------------------------------------------------------- /Symfony3Custom/Sniffs/Objects/ObjectInstantiationSniff.php: -------------------------------------------------------------------------------- 1 | 11 | * @license http://spdx.org/licenses/MIT MIT License 12 | * @link https://github.com/escapestudios/Symfony3Custom-coding-standard 13 | */ 14 | 15 | /** 16 | * Symfony3Custom_Sniffs_Objects_ObjectInstantiationSniff. 17 | * 18 | * Throws a warning if an object isn't instantiated using parenthesis. 19 | * 20 | * PHP version 5 21 | * 22 | * @category PHP 23 | * @package Symfony3Custom-coding-standard 24 | * @author Authors 25 | * @license http://spdx.org/licenses/MIT MIT License 26 | * @link https://github.com/escapestudios/Symfony3Custom-coding-standard 27 | */ 28 | class Symfony3Custom_Sniffs_Objects_ObjectInstantiationSniff 29 | implements PHP_CodeSniffer_Sniff 30 | { 31 | /** 32 | * A list of tokenizers this sniff supports. 33 | * 34 | * @var array 35 | */ 36 | public $supportedTokenizers = array( 37 | 'PHP', 38 | ); 39 | 40 | 41 | /** 42 | * Returns an array of tokens this test wants to listen for. 43 | * 44 | * @return array 45 | */ 46 | public function register() 47 | { 48 | return array( 49 | T_NEW, 50 | ); 51 | } 52 | 53 | /** 54 | * Processes this test, when one of its tokens is encountered. 55 | * 56 | * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. 57 | * @param int $stackPtr The position of the current token 58 | * in the stack passed in $tokens. 59 | * 60 | * @return void 61 | */ 62 | public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) 63 | { 64 | $tokens = $phpcsFile->getTokens(); 65 | $allowed = array( 66 | T_STRING, 67 | T_NS_SEPARATOR, 68 | T_VARIABLE, 69 | T_STATIC, 70 | ); 71 | 72 | $object = $stackPtr; 73 | $line = $tokens[$object]['line']; 74 | 75 | while ($object && $tokens[$object]['line'] === $line) { 76 | $object = $phpcsFile->findNext($allowed, $object + 1); 77 | 78 | if ($tokens[$object]['line'] === $line 79 | && !in_array($tokens[$object + 1]['code'], $allowed) 80 | ) { 81 | if ($tokens[$object + 1]['code'] !== T_OPEN_PARENTHESIS) { 82 | $phpcsFile->addError( 83 | 'Use parentheses when instantiating classes', 84 | $stackPtr, 85 | 'Invalid' 86 | ); 87 | } 88 | 89 | break; 90 | } 91 | } 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /Symfony3Custom/Sniffs/Arrays/MultiLineArrayCommaSniff.php: -------------------------------------------------------------------------------- 1 | 10 | * @license http://spdx.org/licenses/MIT MIT License 11 | * @version GIT: master 12 | * @link https://github.com/escapestudios/Symfony3Custom-coding-standard 13 | */ 14 | 15 | /** 16 | * Symfony3Custom_Sniffs_WhiteSpace_MultiLineArrayCommaSniff. 17 | * 18 | * Throws warnings if the last item in a multi line array does not have a 19 | * trailing comma 20 | * 21 | * @category PHP 22 | * @package PHP_CodeSniffer-Symfony3Custom 23 | * @author wicliff wolda 24 | * @license http://spdx.org/licenses/MIT MIT License 25 | * @link https://github.com/escapestudios/Symfony3Custom-coding-standard 26 | */ 27 | class Symfony3Custom_Sniffs_Arrays_MultiLineArrayCommaSniff 28 | implements PHP_CodeSniffer_Sniff 29 | { 30 | /** 31 | * A list of tokenizers this sniff supports. 32 | * 33 | * @var array 34 | */ 35 | public $supportedTokenizers = array( 36 | 'PHP', 37 | ); 38 | 39 | /** 40 | * Returns an array of tokens this test wants to listen for. 41 | * 42 | * @return array 43 | */ 44 | public function register() 45 | { 46 | return array( 47 | T_ARRAY, 48 | T_OPEN_SHORT_ARRAY, 49 | ); 50 | 51 | } 52 | 53 | /** 54 | * Processes this test, when one of its tokens is encountered. 55 | * 56 | * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. 57 | * @param int $stackPtr The position of the current token 58 | * in the stack passed in $tokens. 59 | * 60 | * @return void 61 | */ 62 | public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) 63 | { 64 | $tokens = $phpcsFile->getTokens(); 65 | $open = $tokens[$stackPtr]; 66 | 67 | if ($open['code'] === T_ARRAY) { 68 | $closePtr = $open['parenthesis_closer']; 69 | } else { 70 | $closePtr = $open['bracket_closer']; 71 | } 72 | 73 | if ($open['line'] <> $tokens[$closePtr]['line']) { 74 | $lastComma = $phpcsFile->findPrevious(T_COMMA, $closePtr); 75 | 76 | while ($lastComma < $closePtr -1) { 77 | $lastComma++; 78 | 79 | if ($tokens[$lastComma]['code'] !== T_WHITESPACE 80 | && $tokens[$lastComma]['code'] !== T_COMMENT 81 | ) { 82 | $phpcsFile->addError( 83 | 'Add a comma after each item in a multi-line array', 84 | $stackPtr, 85 | 'Invalid' 86 | ); 87 | break; 88 | } 89 | } 90 | } 91 | 92 | } 93 | 94 | } 95 | -------------------------------------------------------------------------------- /Symfony3Custom/Sniffs/Classes/PropertyDeclarationSniff.php: -------------------------------------------------------------------------------- 1 | 11 | * @license http://spdx.org/licenses/MIT MIT License 12 | * @link https://github.com/escapestudios/Symfony3Custom-coding-standard 13 | */ 14 | 15 | /** 16 | * Symfony3Custom_Sniffs_Classes_PropertyDeclarationSniff. 17 | * 18 | * Throws warnings if properties are declared after methods 19 | * 20 | * PHP version 5 21 | * 22 | * @category PHP 23 | * @package Symfony3Custom-coding-standard 24 | * @author Authors 25 | * @license http://spdx.org/licenses/MIT MIT License 26 | * @link https://github.com/escapestudios/Symfony3Custom-coding-standard 27 | */ 28 | class Symfony3Custom_Sniffs_Classes_PropertyDeclarationSniff 29 | implements PHP_CodeSniffer_Sniff 30 | { 31 | 32 | /** 33 | * A list of tokenizers this sniff supports. 34 | * 35 | * @var array 36 | */ 37 | public $supportedTokenizers = array( 38 | 'PHP', 39 | ); 40 | 41 | /** 42 | * Returns an array of tokens this test wants to listen for. 43 | * 44 | * @return array 45 | */ 46 | public function register() 47 | { 48 | return array( 49 | T_CLASS, 50 | ); 51 | } 52 | 53 | /** 54 | * Processes this test, when one of its tokens is encountered. 55 | * 56 | * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. 57 | * @param int $stackPtr The position of the current token 58 | * in the stack passed in $tokens. 59 | * 60 | * @return void 61 | */ 62 | public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) 63 | { 64 | $tokens = $phpcsFile->getTokens(); 65 | 66 | $end = null; 67 | if (isset($tokens[$stackPtr]['scope_closer'])) { 68 | $end = $tokens[$stackPtr]['scope_closer']; 69 | } 70 | 71 | $scope = $phpcsFile->findNext( 72 | T_FUNCTION, 73 | $stackPtr, 74 | $end 75 | ); 76 | 77 | $wantedTokens = array( 78 | T_PUBLIC, 79 | T_PROTECTED, 80 | T_PRIVATE 81 | ); 82 | 83 | while ($scope) { 84 | $scope = $phpcsFile->findNext( 85 | $wantedTokens, 86 | $scope + 1, 87 | $end 88 | ); 89 | 90 | if ($scope && $tokens[$scope + 2]['code'] === T_VARIABLE) { 91 | $phpcsFile->addError( 92 | 'Declare class properties before methods', 93 | $scope, 94 | 'Invalid' 95 | ); 96 | } 97 | } 98 | } 99 | 100 | } 101 | -------------------------------------------------------------------------------- /Symfony3Custom/Sniffs/Formatting/BlankLineBeforeReturnSniff.php: -------------------------------------------------------------------------------- 1 | 11 | * @license http://spdx.org/licenses/MIT MIT License 12 | * @link https://github.com/escapestudios/Symfony3Custom-coding-standard 13 | */ 14 | 15 | /** 16 | * Throws errors if there's no blank line before return statements. 17 | * Symfony coding standard specifies: "Add a blank line before return statements, 18 | * unless the return is alone inside a statement-group (like an if statement);" 19 | * 20 | * PHP version 5 21 | * 22 | * @category PHP 23 | * @package Symfony3Custom-coding-standard 24 | * @author Authors 25 | * @license http://spdx.org/licenses/MIT MIT License 26 | * @link https://github.com/escapestudios/Symfony3Custom-coding-standard 27 | */ 28 | class Symfony3Custom_Sniffs_Formatting_BlankLineBeforeReturnSniff 29 | implements PHP_CodeSniffer_Sniff 30 | { 31 | /** 32 | * A list of tokenizers this sniff supports. 33 | * 34 | * @var array 35 | */ 36 | public $supportedTokenizers = array( 37 | 'PHP', 38 | 'JS', 39 | ); 40 | 41 | /** 42 | * Returns an array of tokens this test wants to listen for. 43 | * 44 | * @return array 45 | */ 46 | public function register() 47 | { 48 | return array(T_RETURN); 49 | } 50 | 51 | /** 52 | * Processes this test, when one of its tokens is encountered. 53 | * 54 | * @param PHP_CodeSniffer_File $phpcsFile All the tokens found in the document. 55 | * @param int $stackPtr The position of the current token in 56 | * the stack passed in $tokens. 57 | * 58 | * @return void 59 | */ 60 | public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) 61 | { 62 | $tokens = $phpcsFile->getTokens(); 63 | $current = $stackPtr; 64 | $previousLine = $tokens[$stackPtr]['line'] - 1; 65 | $prevLineTokens = array(); 66 | 67 | while ($current >= 0 && $tokens[$current]['line'] >= $previousLine) { 68 | if ($tokens[$current]['line'] == $previousLine 69 | && $tokens[$current]['type'] !== 'T_WHITESPACE' 70 | && $tokens[$current]['type'] !== 'T_COMMENT' 71 | && $tokens[$current]['type'] !== 'T_DOC_COMMENT_CLOSE_TAG' 72 | && $tokens[$current]['type'] !== 'T_DOC_COMMENT_WHITESPACE' 73 | ) { 74 | $prevLineTokens[] = $tokens[$current]['type']; 75 | } 76 | $current--; 77 | } 78 | 79 | if (isset($prevLineTokens[0]) 80 | && ($prevLineTokens[0] === 'T_OPEN_CURLY_BRACKET' 81 | || $prevLineTokens[0] === 'T_COLON') 82 | ) { 83 | return; 84 | } else if (count($prevLineTokens) > 0) { 85 | $phpcsFile->addError( 86 | 'Missing blank line before return statement', 87 | $stackPtr 88 | ); 89 | } 90 | 91 | return; 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /Symfony3Custom/Sniffs/Functions/ScopeOrderSniff.php: -------------------------------------------------------------------------------- 1 | 11 | * @license http://spdx.org/licenses/MIT MIT License 12 | * @link https://github.com/escapestudios/Symfony3Custom-coding-standard 13 | */ 14 | 15 | /** 16 | * Symfony3Custom_Sniffs_Functions_ScopeOrderSniff. 17 | * 18 | * Throws warnings if properties are declared after methods 19 | * 20 | * PHP version 5 21 | * 22 | * @category PHP 23 | * @package Symfony3Custom-coding-standard 24 | * @author Authors 25 | * @license http://spdx.org/licenses/MIT MIT License 26 | * @link https://github.com/escapestudios/Symfony3Custom-coding-standard 27 | */ 28 | class Symfony3Custom_Sniffs_Functions_ScopeOrderSniff 29 | implements PHP_CodeSniffer_Sniff 30 | { 31 | 32 | /** 33 | * A list of tokenizers this sniff supports. 34 | * 35 | * @var array 36 | */ 37 | public $supportedTokenizers = array( 38 | 'PHP', 39 | ); 40 | 41 | /** 42 | * Returns an array of tokens this test wants to listen for. 43 | * 44 | * @return array 45 | */ 46 | public function register() 47 | { 48 | return array( 49 | T_CLASS, 50 | T_INTERFACE, 51 | ); 52 | } 53 | 54 | /** 55 | * Processes this test, when one of its tokens is encountered. 56 | * 57 | * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. 58 | * @param int $stackPtr The position of the current token 59 | * in the stack passed in $tokens. 60 | * 61 | * @return void 62 | */ 63 | public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) 64 | { 65 | $tokens = $phpcsFile->getTokens(); 66 | $function = $stackPtr; 67 | 68 | $scopes = array( 69 | 0 => T_PUBLIC, 70 | 1 => T_PROTECTED, 71 | 2 => T_PRIVATE, 72 | ); 73 | 74 | $whitelisted = array( 75 | '__construct', 76 | 'setUp', 77 | 'tearDown', 78 | ); 79 | 80 | while ($function) { 81 | $end = null; 82 | 83 | if (isset($tokens[$stackPtr]['scope_closer'])) { 84 | $end = $tokens[$stackPtr]['scope_closer']; 85 | } 86 | 87 | $function = $phpcsFile->findNext( 88 | T_FUNCTION, 89 | $function + 1, 90 | $end 91 | ); 92 | 93 | if (isset($tokens[$function]['parenthesis_opener'])) { 94 | $scope = $phpcsFile->findPrevious($scopes, $function -1, $stackPtr); 95 | $name = $phpcsFile->findNext( 96 | T_STRING, 97 | $function + 1, 98 | $tokens[$function]['parenthesis_opener'] 99 | ); 100 | 101 | if ($scope 102 | && $name 103 | && !in_array( 104 | $tokens[$name]['content'], 105 | $whitelisted 106 | ) 107 | ) { 108 | $current = array_keys($scopes, $tokens[$scope]['code']); 109 | $current = $current[0]; 110 | 111 | $error = 'Declare public methods first,' 112 | .'then protected ones and finally private ones'; 113 | 114 | if (isset($previous) && $current < $previous) { 115 | $phpcsFile->addError( 116 | $error, 117 | $scope, 118 | 'Invalid' 119 | ); 120 | } 121 | 122 | $previous = $current; 123 | } 124 | } 125 | } 126 | } 127 | 128 | } 129 | -------------------------------------------------------------------------------- /Symfony3Custom/Sniffs/Commenting/ClassCommentSniff.php: -------------------------------------------------------------------------------- 1 | 11 | * @license http://spdx.org/licenses/MIT MIT License 12 | * @link https://github.com/escapestudios/Symfony3Custom-coding-standard 13 | */ 14 | 15 | if (class_exists('PHP_CodeSniffer_Tokenizers_Comment', true) === false) { 16 | $error = 'Class PHP_CodeSniffer_Tokenizers_Comment not found'; 17 | throw new PHP_CodeSniffer_Exception($error); 18 | } 19 | 20 | if (class_exists('PEAR_Sniffs_Commenting_ClassCommentSniff', true) === false) { 21 | $error = 'Class PEAR_Sniffs_Commenting_ClassCommentSniff not found'; 22 | throw new PHP_CodeSniffer_Exception($error); 23 | } 24 | 25 | /** 26 | * Parses and verifies the doc comments for classes. 27 | * 28 | * Verifies that : 29 | *
    30 | *
  • A doc comment exists.
  • 31 | *
  • There is a blank newline after the short description.
  • 32 | *
  • There is a blank newline between the long and short description.
  • 33 | *
  • There is a blank newline between the long description and tags.
  • 34 | *
  • Check the order of the tags.
  • 35 | *
  • Check the indentation of each tag.
  • 36 | *
  • Check required and optional tags and the format of their content.
  • 37 | *
38 | * 39 | * PHP version 5 40 | * 41 | * @category PHP 42 | * @package Symfony3Custom-coding-standard 43 | * @author Authors 44 | * @license http://spdx.org/licenses/MIT MIT License 45 | * @link http://pear.php.net/package/PHP_CodeSniffer 46 | */ 47 | class Symfony3Custom_Sniffs_Commenting_ClassCommentSniff 48 | extends PEAR_Sniffs_Commenting_ClassCommentSniff 49 | { 50 | /** 51 | * Tags in correct order and related info. 52 | * 53 | * @var array 54 | */ 55 | protected $tags = array( 56 | 'category' => array( 57 | 'required' => false, 58 | 'allow_multiple' => false, 59 | 'order_text' => 'precedes @package', 60 | ), 61 | 'package' => array( 62 | 'required' => false, 63 | 'allow_multiple' => false, 64 | 'order_text' => 'follows @category', 65 | ), 66 | 'subpackage' => array( 67 | 'required' => false, 68 | 'allow_multiple' => false, 69 | 'order_text' => 'follows @package', 70 | ), 71 | 'author' => array( 72 | 'required' => false, 73 | 'allow_multiple' => true, 74 | 'order_text' => 'follows @subpackage (if used) or @package', 75 | ), 76 | 'copyright' => array( 77 | 'required' => false, 78 | 'allow_multiple' => true, 79 | 'order_text' => 'follows @author', 80 | ), 81 | 'license' => array( 82 | 'required' => false, 83 | 'allow_multiple' => false, 84 | 'order_text' => 'follows @copyright (if used) or @author', 85 | ), 86 | 'version' => array( 87 | 'required' => false, 88 | 'allow_multiple' => false, 89 | 'order_text' => 'follows @license', 90 | ), 91 | 'link' => array( 92 | 'required' => false, 93 | 'allow_multiple' => true, 94 | 'order_text' => 'follows @version', 95 | ), 96 | 'see' => array( 97 | 'required' => false, 98 | 'allow_multiple' => true, 99 | 'order_text' => 'follows @link', 100 | ), 101 | 'since' => array( 102 | 'required' => false, 103 | 'allow_multiple' => false, 104 | 'order_text' => 'follows @see (if used) or @link', 105 | ), 106 | 'deprecated' => array( 107 | 'required' => false, 108 | 'allow_multiple' => false, 109 | 'order_text' => 'follows @since (if used) or @see (if used) or @link', 110 | ), 111 | ); 112 | } 113 | -------------------------------------------------------------------------------- /Symfony3Custom/Sniffs/NamingConventions/ValidClassNameSniff.php: -------------------------------------------------------------------------------- 1 | 11 | * @license http://spdx.org/licenses/MIT MIT License 12 | * @link https://github.com/escapestudios/Symfony3Custom-coding-standard 13 | */ 14 | 15 | /** 16 | * Symfony3Custom_Sniffs_NamingConventions_ValidClassNameSniff. 17 | * 18 | * Throws errors if symfony's naming conventions are not met. 19 | * 20 | * PHP version 5 21 | * 22 | * @category PHP 23 | * @package Symfony3Custom-coding-standard 24 | * @author Authors 25 | * @license http://spdx.org/licenses/MIT MIT License 26 | * @link https://github.com/escapestudios/Symfony3Custom-coding-standard 27 | */ 28 | class Symfony3Custom_Sniffs_NamingConventions_ValidClassNameSniff 29 | implements PHP_CodeSniffer_Sniff 30 | { 31 | /** 32 | * A list of tokenizers this sniff supports. 33 | * 34 | * @var array 35 | */ 36 | public $supportedTokenizers = array( 37 | 'PHP', 38 | ); 39 | 40 | /** 41 | * Returns an array of tokens this test wants to listen for. 42 | * 43 | * @return array 44 | */ 45 | public function register() 46 | { 47 | return array( 48 | T_INTERFACE, 49 | T_TRAIT, 50 | T_EXTENDS, 51 | T_ABSTRACT 52 | ); 53 | } 54 | 55 | /** 56 | * Processes this test, when one of its tokens is encountered. 57 | * 58 | * @param PHP_CodeSniffer_File $phpcsFile All the tokens found in the document. 59 | * @param int $stackPtr The position of the current token in 60 | * the stack passed in $tokens. 61 | * 62 | * @return void 63 | */ 64 | public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) 65 | { 66 | $tokens = $phpcsFile->getTokens(); 67 | $line = $tokens[$stackPtr]['line']; 68 | 69 | while ($tokens[$stackPtr]['line'] == $line) { 70 | 71 | /* 72 | * Suffix interfaces with Interface; 73 | */ 74 | if ('T_INTERFACE' == $tokens[$stackPtr]['type']) { 75 | $name = $phpcsFile->findNext(T_STRING, $stackPtr); 76 | 77 | if ($name && substr($tokens[$name]['content'], -9) != 'Interface') { 78 | $phpcsFile->addError( 79 | 'Interface name is not suffixed with "Interface"', 80 | $stackPtr, 81 | 'InvalidInterfaceName' 82 | ); 83 | } 84 | break; 85 | } 86 | 87 | /* 88 | * Suffix traits with Trait; 89 | */ 90 | if ('T_TRAIT' == $tokens[$stackPtr]['type']) { 91 | $name = $phpcsFile->findNext(T_STRING, $stackPtr); 92 | 93 | if ($name && substr($tokens[$name]['content'], -5) != 'Trait') { 94 | $phpcsFile->addError( 95 | 'Trait name is not suffixed with "Trait"', 96 | $stackPtr, 97 | 'InvalidTraitName' 98 | ); 99 | } 100 | break; 101 | } 102 | 103 | /* 104 | * Suffix exceptions with Exception; 105 | */ 106 | if ('T_EXTENDS' == $tokens[$stackPtr]['type']) { 107 | $extend = $phpcsFile->findNext(T_STRING, $stackPtr); 108 | 109 | if ($extend 110 | && substr($tokens[$extend]['content'], -9) == 'Exception' 111 | ) { 112 | $class = $phpcsFile->findPrevious(T_CLASS, $stackPtr); 113 | $name = $phpcsFile->findNext(T_STRING, $class); 114 | 115 | if ($name 116 | && substr($tokens[$name]['content'], -9) != 'Exception' 117 | ) { 118 | $phpcsFile->addError( 119 | 'Exception name is not suffixed with "Exception"', 120 | $stackPtr, 121 | 'InvalidExceptionName' 122 | ); 123 | } 124 | } 125 | break; 126 | } 127 | 128 | $stackPtr++; 129 | } 130 | 131 | return; 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /Symfony3Custom/ruleset.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | The Symfony3Custom coding standard. 4 | 5 | 6 | */Resources/* 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 0 65 | 66 | 67 | 68 | 69 | 0 70 | 71 | 72 | 73 | 74 | 0 75 | 76 | 77 | 0 78 | 79 | 80 | 0 81 | 82 | 83 | 84 | 0 85 | 86 | 87 | 88 | 0 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 5 116 | 117 | 118 | -------------------------------------------------------------------------------- /Symfony3Custom/Sniffs/WhiteSpace/FunctionClosingBraceSpaceSniff.php: -------------------------------------------------------------------------------- 1 | 10 | * @author Marc McIntyre 11 | * @copyright 2006-2014 Squiz Pty Ltd (ABN 77 084 670 600) 12 | * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence 13 | * @link http://pear.php.net/package/PHP_CodeSniffer 14 | */ 15 | 16 | /** 17 | * Symfony3Custom_Sniffs_WhiteSpace_FunctionClosingBraceSpaceSniff. 18 | * 19 | * Checks that there is no empty line before the closing brace of a function. 20 | * 21 | * @category PHP 22 | * @package PHP_CodeSniffer 23 | * @author Greg Sherwood 24 | * @author Marc McIntyre 25 | * @copyright 2006-2014 Squiz Pty Ltd (ABN 77 084 670 600) 26 | * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence 27 | * @version Release: @package_version@ 28 | * @link http://pear.php.net/package/PHP_CodeSniffer 29 | */ 30 | class Symfony3Custom_Sniffs_WhiteSpace_FunctionClosingBraceSpaceSniff implements PHP_CodeSniffer_Sniff 31 | { 32 | 33 | /** 34 | * A list of tokenizers this sniff supports. 35 | * 36 | * @var array 37 | */ 38 | public $supportedTokenizers = array( 39 | 'PHP', 40 | 'JS', 41 | ); 42 | 43 | 44 | /** 45 | * Returns an array of tokens this test wants to listen for. 46 | * 47 | * @return array 48 | */ 49 | public function register() 50 | { 51 | return array( 52 | T_FUNCTION, 53 | T_CLOSURE, 54 | ); 55 | 56 | }//end register() 57 | 58 | 59 | /** 60 | * Processes this test, when one of its tokens is encountered. 61 | * 62 | * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. 63 | * @param int $stackPtr The position of the current token 64 | * in the stack passed in $tokens. 65 | * 66 | * @return void 67 | */ 68 | public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) 69 | { 70 | $tokens = $phpcsFile->getTokens(); 71 | 72 | if (isset($tokens[$stackPtr]['scope_closer']) === false) { 73 | // Probably an interface method. 74 | return; 75 | } 76 | 77 | $closeBrace = $tokens[$stackPtr]['scope_closer']; 78 | $prevContent = $phpcsFile->findPrevious(T_WHITESPACE, ($closeBrace - 1), null, true); 79 | 80 | // Special case for empty JS functions. 81 | if ($phpcsFile->tokenizerType === 'JS' && $prevContent === $tokens[$stackPtr]['scope_opener']) { 82 | // In this case, the opening and closing brace must be 83 | // right next to each other. 84 | if ($tokens[$stackPtr]['scope_closer'] !== ($tokens[$stackPtr]['scope_opener'] + 1)) { 85 | $error = 'The opening and closing braces of empty functions must be directly next to each other; e.g., function () {}'; 86 | $fix = $phpcsFile->addFixableError($error, $closeBrace, 'SpacingBetween'); 87 | if ($fix === true) { 88 | $phpcsFile->fixer->beginChangeset(); 89 | for ($i = ($tokens[$stackPtr]['scope_opener'] + 1); $i < $closeBrace; $i++) { 90 | $phpcsFile->fixer->replaceToken($i, ''); 91 | } 92 | 93 | $phpcsFile->fixer->endChangeset(); 94 | } 95 | } 96 | 97 | return; 98 | } 99 | 100 | $braceLine = $tokens[$closeBrace]['line']; 101 | $prevLine = $tokens[$prevContent]['line']; 102 | $found = ($braceLine - $prevLine - 1); 103 | 104 | if ($found < 0) { 105 | $error = 'Closing brace of nested function must be on a new line'; 106 | $fix = $phpcsFile->addFixableError($error, $closeBrace, 'ContentBeforeClose'); 107 | if ($fix === true) { 108 | $phpcsFile->fixer->addNewlineBefore($closeBrace); 109 | } 110 | } else { 111 | if ($found > 0) { 112 | $error = 'Expected 0 blank lines before closing brace of function; %s found'; 113 | $data = array($found); 114 | $fix = $phpcsFile->addFixableError($error, $closeBrace, 'SpacingBeforeNestedClose', $data); 115 | 116 | if ($fix === true) { 117 | $phpcsFile->fixer->beginChangeset(); 118 | $changeMade = false; 119 | for ($i = ($prevContent + 1); $i < $closeBrace; $i++) { 120 | // Try and maintain indentation. 121 | if ($tokens[$i]['line'] === ($braceLine - 1)) { 122 | break; 123 | } 124 | 125 | $phpcsFile->fixer->replaceToken($i, ''); 126 | $changeMade = true; 127 | } 128 | 129 | // Special case for when the last content contains the newline 130 | // token as well, like with a comment. 131 | if ($changeMade === false) { 132 | $phpcsFile->fixer->replaceToken(($prevContent + 1), ''); 133 | } 134 | 135 | $phpcsFile->fixer->endChangeset(); 136 | }//end if 137 | } 138 | }//end if 139 | 140 | 141 | }//end process() 142 | 143 | 144 | }//end class 145 | -------------------------------------------------------------------------------- /Symfony3Custom/Sniffs/Commenting/FunctionCommentSniff.php: -------------------------------------------------------------------------------- 1 | 11 | * @license http://spdx.org/licenses/MIT MIT License 12 | * @link https://github.com/escapestudios/Symfony3Custom-coding-standard 13 | */ 14 | 15 | if (class_exists('PEAR_Sniffs_Commenting_FunctionCommentSniff', true) === false) { 16 | $error = 'Class PEAR_Sniffs_Commenting_FunctionCommentSniff not found'; 17 | throw new PHP_CodeSniffer_Exception($error); 18 | } 19 | 20 | /** 21 | * Symfony3Custom standard customization to PEARs FunctionCommentSniff. 22 | * 23 | * Verifies that : 24 | *
    25 | *
  • 26 | * There is a @return tag if a return statement exists inside the method 27 | *
  • 28 | *
29 | * 30 | * PHP version 5 31 | * 32 | * @category PHP 33 | * @package Symfony3Custom-coding-standard 34 | * @author Authors 35 | * @license http://spdx.org/licenses/MIT MIT License 36 | * @link http://pear.php.net/package/PHP_CodeSniffer 37 | */ 38 | class Symfony3Custom_Sniffs_Commenting_FunctionCommentSniff 39 | extends PEAR_Sniffs_Commenting_FunctionCommentSniff 40 | { 41 | /** 42 | * Processes this test, when one of its tokens is encountered. 43 | * 44 | * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. 45 | * @param int $stackPtr The position of the current token 46 | * in the stack passed in $tokens. 47 | * 48 | * @return void 49 | */ 50 | public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) 51 | { 52 | if (false === $commentEnd = $phpcsFile->findPrevious( 53 | array( 54 | T_COMMENT, 55 | T_DOC_COMMENT, 56 | T_CLASS, 57 | T_FUNCTION, 58 | T_OPEN_TAG, 59 | ), 60 | ($stackPtr - 1) 61 | )) { 62 | return; 63 | } 64 | 65 | $tokens = $phpcsFile->getTokens(); 66 | $code = $tokens[$commentEnd]['code']; 67 | 68 | $name = $phpcsFile->getDeclarationName($stackPtr); 69 | 70 | $commentRequired = strpos($name, 'test') !== 0 && $name !== 'setUp'; 71 | 72 | if (($code === T_COMMENT && !$commentRequired) 73 | || ($code !== T_DOC_COMMENT && !$commentRequired) 74 | ) { 75 | return; 76 | } 77 | 78 | parent::process($phpcsFile, $stackPtr); 79 | } 80 | 81 | /** 82 | * Process the return comment of this function comment. 83 | * 84 | * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. 85 | * @param int $stackPtr The position of the current token 86 | * in the stack passed in $tokens. 87 | * @param int $commentStart The position in the stack 88 | * where the comment started. 89 | * 90 | * @return void 91 | */ 92 | protected function processReturn( 93 | PHP_CodeSniffer_File $phpcsFile, 94 | $stackPtr, 95 | $commentStart 96 | ) { 97 | 98 | if ($this->isInheritDoc($phpcsFile, $stackPtr)) { 99 | return; 100 | } 101 | 102 | $tokens = $phpcsFile->getTokens(); 103 | 104 | // Only check for a return comment if a non-void return statement exists 105 | if (isset($tokens[$stackPtr]['scope_opener'])) { 106 | // Start inside the function 107 | $start = $phpcsFile->findNext( 108 | T_OPEN_CURLY_BRACKET, 109 | $stackPtr, 110 | $tokens[$stackPtr]['scope_closer'] 111 | ); 112 | for ($i = $start; $i < $tokens[$stackPtr]['scope_closer']; ++$i) { 113 | // Skip closures 114 | if ($tokens[$i]['code'] === T_CLOSURE) { 115 | $i = $tokens[$i]['scope_closer']; 116 | continue; 117 | } 118 | 119 | // Found a return not in a closure statement 120 | // Run the check on the first which is not only 'return;' 121 | if ($tokens[$i]['code'] === T_RETURN 122 | && $this->isMatchingReturn($tokens, $i) 123 | ) { 124 | parent::processReturn($phpcsFile, $stackPtr, $commentStart); 125 | break; 126 | } 127 | } 128 | } 129 | } 130 | 131 | /** 132 | * @param PHP_CodeSniffer_File $phpcsFile 133 | * @param int $stackPtr 134 | * @param int $commentStart 135 | */ 136 | protected function processWhitespace(PHP_CodeSniffer_File $phpcsFile, int $stackPtr, int $commentStart) 137 | { 138 | $tokens = $phpcsFile->getTokens(); 139 | $before = $phpcsFile->findPrevious(T_WHITESPACE, ($commentStart - 1), null, true); 140 | 141 | $startLine = $tokens[$commentStart]['line']; 142 | $prevLine = $tokens[$before]['line']; 143 | 144 | $found = $startLine - $prevLine - 1; 145 | 146 | // Skip for class opening 147 | if ($found !== 1 && !($found === 0 && $tokens[$before]['type'] === 'T_OPEN_CURLY_BRACKET')) { 148 | if ($found < 0) { 149 | $found = 0; 150 | } 151 | 152 | $error = 'Expected 1 blank line before docblock; %s found'; 153 | $data = array($found); 154 | $fix = $phpcsFile->addFixableError($error, $commentStart, 'SpacingBeforeDocblock', $data); 155 | 156 | if ($fix === true) { 157 | if ($found > 1) { 158 | $phpcsFile->fixer->beginChangeset(); 159 | for ($i = ($before + 1); $i < ($commentStart - 1); $i++) { 160 | $phpcsFile->fixer->replaceToken($i, ''); 161 | } 162 | 163 | $phpcsFile->fixer->replaceToken($i, $phpcsFile->eolChar); 164 | $phpcsFile->fixer->endChangeset(); 165 | } else { 166 | // Try and maintain indentation. 167 | if ($tokens[($commentStart - 1)]['code'] === T_WHITESPACE) { 168 | $phpcsFile->fixer->addNewlineBefore($commentStart - 1); 169 | } else { 170 | $phpcsFile->fixer->addNewlineBefore($commentStart); 171 | } 172 | } 173 | } 174 | } 175 | } 176 | 177 | /** 178 | * Is the comment an inheritdoc? 179 | * 180 | * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. 181 | * @param int $stackPtr The position of the current token 182 | * in the stack passed in $tokens. 183 | * 184 | * @return boolean True if the comment is an inheritdoc 185 | */ 186 | protected function isInheritDoc(PHP_CodeSniffer_File $phpcsFile, $stackPtr) 187 | { 188 | $tokens = $phpcsFile->getTokens(); 189 | 190 | $start = $phpcsFile->findPrevious(T_DOC_COMMENT_OPEN_TAG, $stackPtr - 1); 191 | $end = $phpcsFile->findNext(T_DOC_COMMENT_CLOSE_TAG, $start); 192 | 193 | $content = $phpcsFile->getTokensAsString($start, ($end - $start)); 194 | 195 | return preg_match('#{@inheritdoc}#i', $content) === 1; 196 | } 197 | 198 | /** 199 | * Process the function parameter comments. 200 | * 201 | * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. 202 | * @param int $stackPtr The position of the current token 203 | * in the stack passed in $tokens. 204 | * @param int $commentStart The position in the stack 205 | * where the comment started. 206 | * 207 | * @return void 208 | */ 209 | protected function processParams( 210 | PHP_CodeSniffer_File $phpcsFile, 211 | $stackPtr, 212 | $commentStart 213 | ) { 214 | $tokens = $phpcsFile->getTokens(); 215 | 216 | if ($this->isInheritDoc($phpcsFile, $stackPtr)) { 217 | return; 218 | } 219 | 220 | $this->processWhitespace($phpcsFile, $stackPtr, $commentStart); 221 | 222 | parent::processParams($phpcsFile, $stackPtr, $commentStart); 223 | 224 | } 225 | 226 | /** 227 | * Is the return statement matching? 228 | * 229 | * @param array $tokens Array of tokens 230 | * @param int $returnPos Stack position of the T_RETURN token to process 231 | * 232 | * @return boolean True if the return does not return anything 233 | */ 234 | protected function isMatchingReturn($tokens, $returnPos) 235 | { 236 | do { 237 | $returnPos++; 238 | } while ($tokens[$returnPos]['code'] === T_WHITESPACE); 239 | 240 | return $tokens[$returnPos]['code'] !== T_SEMICOLON; 241 | } 242 | } 243 | --------------------------------------------------------------------------------