├── composer.json ├── Standards ├── Laravel │ ├── Sniffs │ │ ├── Functions │ │ │ └── FunctionDeclarationSniff.php │ │ ├── Tabs │ │ │ └── DisallowWhitespaceIndentSniff.php │ │ └── ControlStructures │ │ │ └── ControlSignatureSniff.php │ └── ruleset.xml └── TestFiles │ └── Filesystem.php ├── LICENSE └── readme.md /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "pragmarx/laravelcs", 3 | "description": "PHP_CodeSniffer custom Sniff for Laravel coding standard", 4 | "keywords": ["laravel", "code", "sniffer", "standards", "PHP_CodeSniffer"], 5 | "license": "BSD-3-Clause", 6 | "authors": [ 7 | { 8 | "name": "Antonio Carlos Ribeiro", 9 | "email": "acr@antoniocarlosribeiro.com", 10 | "role": "Creator" 11 | } 12 | ], 13 | "minimum-stability": "stable", 14 | "require": { 15 | "squizlabs/php_codesniffer": "~2.0" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Standards/Laravel/Sniffs/Functions/FunctionDeclarationSniff.php: -------------------------------------------------------------------------------- 1 | 8 | * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence 9 | * @version Release: @package_version@ 10 | * @link http://pear.php.net/package/PHP_CodeSniffer 11 | */ 12 | if (class_exists('PHP_CodeSniffer_Standards_AbstractPatternSniff', true) === false) { 13 | throw new PHP_CodeSniffer_Exception('Class PHP_CodeSniffer_Standards_AbstractPatternSniff not found'); 14 | } 15 | 16 | class Laravel_Sniffs_Functions_FunctionDeclarationSniff extends PHP_CodeSniffer_Standards_AbstractPatternSniff 17 | { 18 | /** 19 | * Returns an array of patterns to check are correct. 20 | * 21 | * @return array 22 | */ 23 | protected function getPatterns() 24 | { 25 | return array( 26 | 'function abc(...);', 27 | "function abc(...)\n", 28 | 'abstract function abc(...);', 29 | ); 30 | }//end getPatterns() 31 | }//end class 32 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014, Antonio Carlos Ribeiro 2 | 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 6 | 7 | 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 8 | 9 | 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 10 | 11 | 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 12 | 13 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 14 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # Laravel PHP_CodeSniffer 2 | ### This is a custom Sniff to detect violations and reformat PHP source code based on [Laravel Coding Standard](http://laravel.com/docs/4.2/contributions#coding-style). 3 | 4 | Your source code will be checked for PSR-1 & the Laravel "flavor" of PSR-2. 5 | 6 | ### Usage wih git 7 | 8 | Clone this repository 9 | 10 | git clone http://github.com/antonioribeiro/laravelcs LaravelCodeSniffer 11 | 12 | Execute CodeSniffer 13 | 14 | phpcs --standard=LaravelCodeSniffer/Standards/Laravel/ /path/to/your/project/files 15 | 16 | ### Usage with [Composer](https://getcomposer.org/doc/00-intro.md#installation-nix) 17 | 18 | The recommended way is to install it globally with the following command: 19 | 20 | composer global require pragmarx/laravelcs 21 | 22 | Make sure you have `~/.composer/vendor/bin/` in your PATH. 23 | 24 | You will then be able to run PHP Code Sniffer with the Laravel Standard: 25 | 26 | phpcs --standard=$HOME/.composer/vendor/pragmarx/laravelcs/Standards/Laravel/ /path/to/your/project/files 27 | 28 | ### Testing the Sniff 29 | 30 | This Sniff was tested using the Laravel Framework source code and some changes, to comply with PSR-2, were required, [click here to see them](http://github.com/antonioribeiro/laravelcs/compare/096884846fa385e54a7e4eeb43547a9137fdf047...d78508f9e5633bc0f776f730dcc6f1e0a9c8daec). Those were the violations found and fixed in Filesystem.php: 31 | 32 | ``` 33 | -------------------------------------------------------------------------------- 34 | FOUND 14 ERRORS AFFECTING 11 LINES 35 | -------------------------------------------------------------------------------- 36 | 29 | ERROR | [x] Inline control structures are not allowed 37 | 44 | ERROR | [x] Inline control structures are not allowed 38 | 113 | ERROR | [x] Expected 1 new line after closing parenthesis; found " " 39 | 113 | ERROR | [x] Expected 1 newline after opening brace; 0 found 40 | 113 | ERROR | [x] Inline control structures are not allowed 41 | 113 | ERROR | [x] Closing brace must be on a line by itself 42 | 241 | ERROR | [x] Inline control structures are not allowed 43 | 247 | ERROR | [ ] Opening brace should be on the same line as the declaration 44 | 249 | ERROR | [x] Closing brace indented incorrectly; expected 2 spaces, found 3 45 | 310 | ERROR | [x] Inline control structures are not allowed 46 | 335 | ERROR | [x] Inline control structures are not allowed 47 | 343 | ERROR | [x] Inline control structures are not allowed 48 | 361 | ERROR | [x] Inline control structures are not allowed 49 | 384 | ERROR | [x] Inline control structures are not allowed 50 | -------------------------------------------------------------------------------- 51 | PHPCBF CAN FIX THE 13 MARKED SNIFF VIOLATIONS AUTOMATICALLY 52 | -------------------------------------------------------------------------------- 53 | ``` 54 | 55 | ### Contributing 56 | 57 | There are probably still a lot to do here, so please, open issues and send pull requests. 58 | -------------------------------------------------------------------------------- /Standards/Laravel/Sniffs/Tabs/DisallowWhitespaceIndentSniff.php: -------------------------------------------------------------------------------- 1 | 8 | * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence 9 | * @version Release: @package_version@ 10 | * @link http://pear.php.net/package/PHP_CodeSniffer 11 | */ 12 | class Laravel_Sniffs_Tabs_DisallowWhitespaceIndentSniff implements PHP_CodeSniffer_Sniff 13 | { 14 | 15 | /** 16 | * A list of tokenizers this sniff supports. 17 | * 18 | * @var array 19 | */ 20 | public $supportedTokenizers = array( 21 | 'PHP', 22 | ); 23 | 24 | 25 | /** 26 | * Returns an array of tokens this test wants to listen for. 27 | * 28 | * @return array 29 | */ 30 | public function register() 31 | { 32 | return array(T_OPEN_TAG); 33 | 34 | }//end register() 35 | 36 | 37 | /** 38 | * Processes this test, when one of its tokens is encountered. 39 | * 40 | * @param PHP_CodeSniffer_File $phpcsFile All the tokens found in the document. 41 | * @param int $stackPtr The position of the current token in 42 | * the stack passed in $tokens. 43 | * 44 | * @return void 45 | */ 46 | public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) 47 | { 48 | $tokens = $phpcsFile->getTokens(); 49 | $error = 'Tabs must be used to indent lines; spaces are not allowed'; 50 | 51 | for ($i = ($stackPtr + 1); $i < $phpcsFile->numTokens; $i++) { 52 | // We always checks doc comments for spaces, but only whitespace 53 | // at the start of a line for everything else. 54 | $inComment = false; 55 | if ($tokens[$i]['code'] !== T_DOC_COMMENT_WHITESPACE 56 | && $tokens[$i]['code'] !== T_DOC_COMMENT_STRING 57 | ) { 58 | if ($tokens[$i]['column'] !== 1 59 | || ($tokens[$i]['code'] !== T_WHITESPACE 60 | && $tokens[$i]['code'] !== T_CONSTANT_ENCAPSED_STRING) 61 | ) { 62 | continue; 63 | } 64 | } else { 65 | $inComment = true; 66 | } 67 | 68 | // If spaces are being converted to tabs by PHPCS, the 69 | // original content should be used instead of the converted content. 70 | if (isset($tokens[$i]['orig_content']) === true) { 71 | $content = $tokens[$i]['orig_content']; 72 | } else { 73 | $content = $tokens[$i]['content']; 74 | } 75 | 76 | $spaceFound = false; 77 | if ($tokens[$i]['column'] === 1) { 78 | if ($content[0] === " ") { 79 | $phpcsFile->recordMetric($i, 'Line indent', 'spaces'); 80 | $spaceFound = true; 81 | } else if ($content[0] === ' ') { 82 | if ($tokens[$i]['code'] === T_DOC_COMMENT_WHITESPACE && $content === ' ') { 83 | // Ignore file/class-level DocBlock. 84 | continue; 85 | } 86 | 87 | if (strpos($content, " ") !== false) { 88 | $phpcsFile->recordMetric($i, 'Line indent', 'mixed'); 89 | $spaceFound = true; 90 | } else { 91 | $phpcsFile->recordMetric($i, 'Line indent', 'tabs'); 92 | } 93 | } 94 | } else { 95 | // Look for 4 spaces so we can report and replace, but don't 96 | // record any metrics about them because they aren't 97 | // line indent tokens. 98 | if ( ! $inComment && strpos($content, " ") !== false) { 99 | $spaceFound = true; 100 | } 101 | }//end if 102 | 103 | if ($spaceFound === false) { 104 | continue; 105 | } 106 | 107 | $fix = $phpcsFile->addFixableError($error, $i, 'SpacesUsed'); 108 | if ($fix === true) { 109 | if (isset($tokens[$i]['orig_content']) === true) { 110 | // Use the replacement that PHPCS has already done. 111 | $phpcsFile->fixer->replaceToken($i, $tokens[$i]['content']); 112 | } else { 113 | // Replace spaces with tabs, using an indent of 4 spaces. 114 | // Other sniffs can then correct the indent if they need to. 115 | $newContent = str_replace(' ', "\t", $tokens[$i]['content']); 116 | $phpcsFile->fixer->replaceToken($i, $newContent); 117 | } 118 | } 119 | }//end for 120 | 121 | // Ignore the rest of the file. 122 | return ($phpcsFile->numTokens + 1); 123 | 124 | }//end process() 125 | 126 | 127 | }//end class 128 | -------------------------------------------------------------------------------- /Standards/Laravel/Sniffs/ControlStructures/ControlSignatureSniff.php: -------------------------------------------------------------------------------- 1 | 8 | * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence 9 | * @version Release: @package_version@ 10 | * @link http://pear.php.net/package/PHP_CodeSniffer 11 | */ 12 | class Laravel_Sniffs_ControlStructures_ControlSignatureSniff implements PHP_CodeSniffer_Sniff 13 | { 14 | /** 15 | * A list of tokenizers this sniff supports. 16 | * 17 | * @var array 18 | */ 19 | public $supportedTokenizers = array( 20 | 'PHP', 21 | 'JS', 22 | ); 23 | /** 24 | * Returns an array of tokens this test wants to listen for. 25 | * 26 | * @return int[] 27 | */ 28 | public function register() 29 | { 30 | return array( 31 | T_TRY, 32 | T_CATCH, 33 | T_DO, 34 | T_WHILE, 35 | T_FOR, 36 | T_IF, 37 | T_FOREACH, 38 | T_ELSE, 39 | T_ELSEIF, 40 | ); 41 | }//end register() 42 | /** 43 | * Processes this test, when one of its tokens is encountered. 44 | * 45 | * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. 46 | * @param int $stackPtr The position of the current token in the 47 | * stack passed in $tokens. 48 | * 49 | * @return void 50 | */ 51 | public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) 52 | { 53 | $tokens = $phpcsFile->getTokens(); 54 | // Single space after the keyword. 55 | $found = 1; 56 | if ($tokens[($stackPtr + 1)]['code'] !== T_WHITESPACE) { 57 | $found = 0; 58 | } else if ( ! in_array($tokens[($stackPtr + 1)]['content'], [' ', $phpcsFile->eolChar])) { 59 | $found = strlen($tokens[($stackPtr + 1)]['content']); 60 | } 61 | if ($found !== 1) { 62 | $error = 'Expected 1 space after %s keyword; %s found'; 63 | $data = array( 64 | strtoupper($tokens[$stackPtr]['content']), 65 | $found, 66 | ); 67 | $fix = $phpcsFile->addFixableError($error, $stackPtr, 'SpaceAfterKeyword', $data); 68 | if ($fix === true) { 69 | if ($found === 0) { 70 | $phpcsFile->fixer->addContent($stackPtr, ' '); 71 | } else { 72 | $phpcsFile->fixer->replaceToken(($stackPtr + 1), ' '); 73 | } 74 | } 75 | } 76 | // Single space after closing parenthesis. 77 | if (isset($tokens[$stackPtr]['parenthesis_closer']) === true 78 | && isset($tokens[$stackPtr]['scope_opener']) === true 79 | ) { 80 | $closer = $tokens[$stackPtr]['parenthesis_closer']; 81 | $opener = $tokens[$stackPtr]['scope_opener']; 82 | $content = $phpcsFile->getTokensAsString(($closer + 1), ($opener - $closer - 1)); 83 | 84 | if (isset($content[0]) && $content[0] !== $phpcsFile->eolChar) { 85 | $error = 'Expected 1 new line after closing parenthesis; found "%s"'; 86 | $data = array(str_replace($phpcsFile->eolChar, '\n', $content)); 87 | $fix = $phpcsFile->addFixableError($error, $closer, 'SpaceAfterCloseParenthesis', $data); 88 | if ($fix === true) { 89 | if ($closer === ($opener - 1)) { 90 | $phpcsFile->fixer->addContent($closer, ' '); 91 | } else { 92 | $phpcsFile->fixer->beginChangeset(); 93 | for ($i = ($closer + 1); $i < $opener; $i++) { 94 | $phpcsFile->fixer->replaceToken($i, ''); 95 | } 96 | $phpcsFile->fixer->addContent($closer, ' '); 97 | $phpcsFile->fixer->endChangeset(); 98 | } 99 | } 100 | } 101 | }//end if 102 | // Single newline after opening brace. 103 | if (isset($tokens[$stackPtr]['scope_opener']) === true) { 104 | $opener = $tokens[$stackPtr]['scope_opener']; 105 | $next = $phpcsFile->findNext(T_WHITESPACE, ($opener + 1), null, true); 106 | $found = ($tokens[$next]['line'] - $tokens[$opener]['line']); 107 | if ($found !== 1) { 108 | $error = 'Expected 1 newline after opening brace; %s found'; 109 | $data = array($found); 110 | $fix = $phpcsFile->addFixableError($error, $opener, 'NewlineAfterOpenBrace', $data); 111 | if ($fix === true) { 112 | $phpcsFile->fixer->beginChangeset(); 113 | for ($i = ($opener + 1); $i < $next; $i++) { 114 | if ($found > 0 && $tokens[$i]['line'] === $tokens[$next]['line']) { 115 | break; 116 | } 117 | $phpcsFile->fixer->replaceToken($i, ''); 118 | } 119 | $phpcsFile->fixer->addContent($opener, $phpcsFile->eolChar); 120 | $phpcsFile->fixer->endChangeset(); 121 | } 122 | } 123 | } else if ($tokens[$stackPtr]['code'] === T_WHILE) { 124 | // Zero spaces after parenthesis closer. 125 | $closer = $tokens[$stackPtr]['parenthesis_closer']; 126 | $found = 0; 127 | if ($tokens[($closer + 1)]['code'] === T_WHITESPACE) { 128 | if (strpos($tokens[($closer + 1)]['content'], $phpcsFile->eolChar) !== false) { 129 | $found = 'newline'; 130 | } else { 131 | $found = strlen($tokens[($closer + 1)]['content']); 132 | } 133 | } 134 | if ($found !== 0) { 135 | $error = 'Expected 0 spaces before semicolon; %s found'; 136 | $data = array($found); 137 | $fix = $phpcsFile->addFixableError($error, $closer, 'SpaceBeforeSemicolon', $data); 138 | if ($fix === true) { 139 | $phpcsFile->fixer->replaceToken(($closer + 1), ''); 140 | } 141 | } 142 | }//end if 143 | // Only want to check multi-keyword structures from here on. 144 | if ($tokens[$stackPtr]['code'] === T_TRY 145 | || $tokens[$stackPtr]['code'] === T_DO 146 | ) { 147 | $closer = $tokens[$stackPtr]['scope_closer']; 148 | } else if ($tokens[$stackPtr]['code'] === T_ELSE 149 | || $tokens[$stackPtr]['code'] === T_ELSEIF 150 | ) { 151 | $closer = $phpcsFile->findPrevious(T_CLOSE_CURLY_BRACKET, ($stackPtr - 1)); 152 | } else { 153 | return; 154 | } 155 | // Single space after closing brace. 156 | $found = 1; 157 | if ($tokens[($closer + 1)]['code'] !== T_WHITESPACE) { 158 | $found = 0; 159 | } else if ( ! in_array($tokens[($closer + 1)]['content'], [' ', $phpcsFile->eolChar])) { 160 | if (strpos($tokens[($closer + 1)]['content'], $phpcsFile->eolChar) !== false) { 161 | $found = 'newline'; 162 | } else { 163 | $found = strlen($tokens[($closer + 1)]['content']); 164 | } 165 | } 166 | if ($found !== 1) { 167 | $error = 'Expected 1 space after closing brace; %s found'; 168 | $data = array($found); 169 | $fix = $phpcsFile->addFixableError($error, $closer, 'SpaceAfterCloseBrace', $data); 170 | if ($fix === true) { 171 | if ($found === 0) { 172 | $phpcsFile->fixer->addContent($closer, ' '); 173 | } else { 174 | $phpcsFile->fixer->replaceToken(($closer + 1), ' '); 175 | } 176 | } 177 | } 178 | }//end process() 179 | }//end class 180 | -------------------------------------------------------------------------------- /Standards/TestFiles/Filesystem.php: -------------------------------------------------------------------------------- 1 | isFile($path)) 30 | { 31 | return file_get_contents($path); 32 | } 33 | 34 | throw new FileNotFoundException("File does not exist at path {$path}"); 35 | } 36 | 37 | /** 38 | * Get the returned value of a file. 39 | * 40 | * @param string $path 41 | * @return mixed 42 | * 43 | * @throws FileNotFoundException 44 | */ 45 | public function getRequire($path) 46 | { 47 | if ($this->isFile($path)) 48 | { 49 | return require $path; 50 | } 51 | 52 | throw new FileNotFoundException("File does not exist at path {$path}"); 53 | } 54 | 55 | /** 56 | * Require the given file once. 57 | * 58 | * @param string $file 59 | * @return mixed 60 | */ 61 | public function requireOnce($file) 62 | { 63 | require_once $file; 64 | } 65 | 66 | /** 67 | * Write the contents of a file. 68 | * 69 | * @param string $path 70 | * @param string $contents 71 | * @return int 72 | */ 73 | public function put($path, $contents) 74 | { 75 | return file_put_contents($path, $contents); 76 | } 77 | 78 | /** 79 | * Prepend to a file. 80 | * 81 | * @param string $path 82 | * @param string $data 83 | * @return int 84 | */ 85 | public function prepend($path, $data) 86 | { 87 | if ($this->exists($path)) 88 | { 89 | return $this->put($path, $data.$this->get($path)); 90 | } 91 | 92 | return $this->put($path, $data); 93 | } 94 | 95 | /** 96 | * Append to a file. 97 | * 98 | * @param string $path 99 | * @param string $data 100 | * @return int 101 | */ 102 | public function append($path, $data) 103 | { 104 | return file_put_contents($path, $data, FILE_APPEND); 105 | } 106 | 107 | /** 108 | * Delete the file at a given path. 109 | * 110 | * @param string|array $paths 111 | * @return bool 112 | */ 113 | public function delete($paths) 114 | { 115 | $paths = is_array($paths) ? $paths : func_get_args(); 116 | 117 | $success = true; 118 | 119 | foreach ($paths as $path) 120 | { 121 | if ( ! @unlink($path)) 122 | { 123 | $success = false; 124 | } 125 | } 126 | 127 | return $success; 128 | } 129 | 130 | /** 131 | * Move a file to a new location. 132 | * 133 | * @param string $path 134 | * @param string $target 135 | * @return bool 136 | */ 137 | public function move($path, $target) 138 | { 139 | return rename($path, $target); 140 | } 141 | 142 | /** 143 | * Copy a file to a new location. 144 | * 145 | * @param string $path 146 | * @param string $target 147 | * @return bool 148 | */ 149 | public function copy($path, $target) 150 | { 151 | return copy($path, $target); 152 | } 153 | 154 | /** 155 | * Extract the file extension from a file path. 156 | * 157 | * @param string $path 158 | * @return string 159 | */ 160 | public function extension($path) 161 | { 162 | return pathinfo($path, PATHINFO_EXTENSION); 163 | } 164 | 165 | /** 166 | * Get the file type of a given file. 167 | * 168 | * @param string $path 169 | * @return string 170 | */ 171 | public function type($path) 172 | { 173 | return filetype($path); 174 | } 175 | 176 | /** 177 | * Get the file size of a given file. 178 | * 179 | * @param string $path 180 | * @return int 181 | */ 182 | public function size($path) 183 | { 184 | return filesize($path); 185 | } 186 | 187 | /** 188 | * Get the file's last modification time. 189 | * 190 | * @param string $path 191 | * @return int 192 | */ 193 | public function lastModified($path) 194 | { 195 | return filemtime($path); 196 | } 197 | 198 | /** 199 | * Determine if the given path is a directory. 200 | * 201 | * @param string $directory 202 | * @return bool 203 | */ 204 | public function isDirectory($directory) 205 | { 206 | return is_dir($directory); 207 | } 208 | 209 | /** 210 | * Determine if the given path is writable. 211 | * 212 | * @param string $path 213 | * @return bool 214 | */ 215 | public function isWritable($path) 216 | { 217 | return is_writable($path); 218 | } 219 | 220 | /** 221 | * Determine if the given path is a file. 222 | * 223 | * @param string $file 224 | * @return bool 225 | */ 226 | public function isFile($file) 227 | { 228 | return is_file($file); 229 | } 230 | 231 | /** 232 | * Find path names matching a given pattern. 233 | * 234 | * @param string $pattern 235 | * @param int $flags 236 | * @return array 237 | */ 238 | public function glob($pattern, $flags = 0) 239 | { 240 | return glob($pattern, $flags); 241 | } 242 | 243 | /** 244 | * Get an array of all files in a directory. 245 | * 246 | * @param string $directory 247 | * @return array 248 | */ 249 | public function files($directory) 250 | { 251 | $glob = glob($directory.'/*'); 252 | 253 | if ($glob === false) 254 | { 255 | return array(); 256 | } 257 | 258 | // To get the appropriate files, we'll simply glob the directory and filter 259 | // out any "files" that are not truly files so we do not end up with any 260 | // directories in our list, but only true files within the directory. 261 | return array_filter($glob, function($file) { 262 | return filetype($file) == 'file'; 263 | }); 264 | } 265 | 266 | /** 267 | * Get all of the files from the given directory (recursive). 268 | * 269 | * @param string $directory 270 | * @return array 271 | */ 272 | public function allFiles($directory) 273 | { 274 | return iterator_to_array(Finder::create()->files()->in($directory), false); 275 | } 276 | 277 | /** 278 | * Get all of the directories within a given directory. 279 | * 280 | * @param string $directory 281 | * @return array 282 | */ 283 | public function directories($directory) 284 | { 285 | $directories = array(); 286 | 287 | foreach (Finder::create()->in($directory)->directories()->depth(0) as $dir) 288 | { 289 | $directories[] = $dir->getPathname(); 290 | } 291 | 292 | return $directories; 293 | } 294 | 295 | /** 296 | * Create a directory. 297 | * 298 | * @param string $path 299 | * @param int $mode 300 | * @param bool $recursive 301 | * @param bool $force 302 | * @return bool 303 | */ 304 | public function makeDirectory($path, $mode = 0755, $recursive = false, $force = false) 305 | { 306 | if ($force) 307 | { 308 | return @mkdir($path, $mode, $recursive); 309 | } 310 | 311 | return mkdir($path, $mode, $recursive); 312 | } 313 | 314 | /** 315 | * Copy a directory from one location to another. 316 | * 317 | * @param string $directory 318 | * @param string $destination 319 | * @param int $options 320 | * @return bool 321 | */ 322 | public function copyDirectory($directory, $destination, $options = null) 323 | { 324 | if ( ! $this->isDirectory($directory)) 325 | { 326 | return false; 327 | } 328 | 329 | $options = $options ?: FilesystemIterator::SKIP_DOTS; 330 | 331 | // If the destination directory does not actually exist, we will go ahead and 332 | // create it recursively, which just gets the destination prepared to copy 333 | // the files over. Once we make the directory we'll proceed the copying. 334 | if ( ! $this->isDirectory($destination)) 335 | { 336 | $this->makeDirectory($destination, 0777, true); 337 | } 338 | 339 | $items = new FilesystemIterator($directory, $options); 340 | 341 | foreach ($items as $item) 342 | { 343 | // As we spin through items, we will check to see if the current file is actually 344 | // a directory or a file. When it is actually a directory we will need to call 345 | // back into this function recursively to keep copying these nested folders. 346 | $target = $destination.'/'.$item->getBasename(); 347 | 348 | if ($item->isDir()) 349 | { 350 | $path = $item->getPathname(); 351 | 352 | if ( ! $this->copyDirectory($path, $target, $options)) 353 | { 354 | return false; 355 | } 356 | } 357 | 358 | // If the current items is just a regular file, we will just copy this to the new 359 | // location and keep looping. If for some reason the copy fails we'll bail out 360 | // and return false, so the developer is aware that the copy process failed. 361 | else 362 | { 363 | if ( ! $this->copy($item->getPathname(), $target)) 364 | { 365 | return false; 366 | } 367 | } 368 | } 369 | 370 | return true; 371 | } 372 | 373 | /** 374 | * Recursively delete a directory. 375 | * 376 | * The directory itself may be optionally preserved. 377 | * 378 | * @param string $directory 379 | * @param bool $preserve 380 | * @return bool 381 | */ 382 | public function deleteDirectory($directory, $preserve = false) 383 | { 384 | if ( ! $this->isDirectory($directory)) 385 | { 386 | return false; 387 | } 388 | 389 | $items = new FilesystemIterator($directory); 390 | 391 | foreach ($items as $item) 392 | { 393 | // If the item is a directory, we can just recurse into the function and 394 | // delete that sub-directory otherwise we'll just delete the file and 395 | // keep iterating through each file until the directory is cleaned. 396 | if ($item->isDir()) 397 | { 398 | $this->deleteDirectory($item->getPathname()); 399 | } 400 | 401 | // If the item is just a file, we can go ahead and delete it since we're 402 | // just looping through and waxing all of the files in this directory 403 | // and calling directories recursively, so we delete the real path. 404 | else 405 | { 406 | $this->delete($item->getPathname()); 407 | } 408 | } 409 | 410 | if ( ! $preserve) 411 | { 412 | @rmdir($directory); 413 | } 414 | 415 | return true; 416 | } 417 | 418 | /** 419 | * Empty the specified directory of all files and folders. 420 | * 421 | * @param string $directory 422 | * @return bool 423 | */ 424 | public function cleanDirectory($directory) 425 | { 426 | return $this->deleteDirectory($directory, true); 427 | } 428 | 429 | } 430 | -------------------------------------------------------------------------------- /Standards/Laravel/ruleset.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | The Laravel Framework coding standard. 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 0 45 | 46 | 47 | 0 48 | 49 | 50 | 0 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 86 | 87 | 88 | 89 | 90 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 0 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 131 | 132 | 133 | 134 | 135 | 137 | 138 | 139 | 0 140 | 141 | 142 | 143 | 144 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 184 | 185 | 186 | --------------------------------------------------------------------------------