├── Joomla
├── ExampleRulesets
│ ├── Joomla-CMS
│ │ └── ruleset.xml
│ ├── Joomla-Stats
│ │ └── ruleset.xml
│ └── README.md
├── Sniffs
│ ├── Classes
│ │ └── InstantiateNewClassesSniff.php
│ ├── Commenting
│ │ ├── ClassCommentSniff.php
│ │ ├── FileCommentSniff.php
│ │ ├── FunctionCommentSniff.php
│ │ └── SingleCommentSniff.php
│ ├── ControlStructures
│ │ ├── ControlSignatureSniff.php
│ │ ├── ControlStructuresBracketsSniff.php
│ │ └── WhiteSpaceBeforeSniff.php
│ ├── Functions
│ │ └── StatementNotFunctionSniff.php
│ ├── NamingConventions
│ │ ├── ValidFunctionNameSniff.php
│ │ └── ValidVariableNameSniff.php
│ ├── Operators
│ │ └── ValidLogicalOperatorsSniff.php
│ └── WhiteSpace
│ │ └── MemberVarSpacingSniff.php
└── ruleset.xml
├── LICENSE
├── README.md
├── composer.json
├── manual
├── README.md
├── appendices
│ ├── analysis.md
│ └── examples.md
├── basic-guidelines.md
├── css.md
├── docblocks.md
├── html.md
├── ini.md
├── inline-comments.md
├── introduction.md
├── javascript-j3.md
├── javascript-j4.md
├── license.md
├── php.md
├── scss.md
├── source-code-management.md
├── version.md
└── xml.md
└── notes.txt
/Joomla/ExampleRulesets/Joomla-Stats/ruleset.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | */build/*
12 | */tests/*
13 | */lib/*
14 | */tmpl/*
15 | */layouts/*
16 |
17 |
18 | */libraries/*
19 | */vendor/*
20 | */editors/*
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/Joomla/ExampleRulesets/README.md:
--------------------------------------------------------------------------------
1 | ### Selectively Applying Rules
2 |
3 | #### NOTE: this is an exact copy of the "Selectively Applying Rules" section of the main README and is here only for reference
4 |
5 | For consuming packages there are some items that will typically result in creating their own project ruleset.xml, rather than just directly using the Joomla ruleset.xml. A project ruleset.xml allows the coding standard to be selectivly applied for excluding 3rd party libraries, for consideration of backwards compatability in existing projects, or for adjustments necessary for projects that do not need php 5.3 compatability (which will be removed in a future version of the Joomla Coding Standard in connection of the end of php 5.3 support in all active Joomla Projects).
6 |
7 | For information on [selectivly applying rules read details in the PHP CodeSniffer wiki](https://github.com/squizlabs/PHP_CodeSniffer/wiki/Annotated-ruleset.xml#selectively-applying-rules)
8 |
9 | #### Common Rule Set Adjustments
10 |
11 | The most common adjustment is to exclude folders with 3rd party libraries, or where the code has yet to have coding standards applied.
12 |
13 | ```xml
14 |
15 | build/*
16 | tests/*
17 |
18 |
19 | libraries/*
20 | vendor/*
21 | ```
22 |
23 | Another common adjustment is to exclude the [camelCase format requirement](http://joomla.github.io/coding-standards/?coding-standards/chapters/php.md) for "Classes, Functions, Methods, Regular Variables and Class Properties" the essentially allows for B/C with snake_case variables which were only allowed in the context of interacting with the database.
24 |
25 | ```xml
26 |
27 |
28 |
29 |
30 |
31 |
32 | ```
33 |
34 | Old Protected method names were at one time prefixed with an underscore. These Protected method names with underscores are depreceated in Joomla projects but for B\C reasons are still in the projects. As such excluding the MethodUnderscore sniff is a common ruleset adjustment
35 |
36 | ```xml
37 |
38 |
39 |
40 |
41 | ```
42 |
43 | The last most common adjustment is removing PHP 5.3 specific rules which prevent short array syntax, and allowing short array syntax for method parameters.
44 |
45 | ```xml
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 | ```
56 |
--------------------------------------------------------------------------------
/Joomla/Sniffs/Classes/InstantiateNewClassesSniff.php:
--------------------------------------------------------------------------------
1 | getTokens();
46 |
47 | $running = true;
48 | $valid = false;
49 | $started = false;
50 |
51 | $cnt = $stackPtr + 1;
52 |
53 | do
54 | {
55 | if (false === isset($tokens[$cnt]))
56 | {
57 | $running = false;
58 | }
59 | else
60 | {
61 | switch ($tokens[$cnt]['code'])
62 | {
63 | case T_SEMICOLON :
64 | case T_COMMA :
65 | $valid = true;
66 | $running = false;
67 | break;
68 |
69 | case T_OPEN_PARENTHESIS :
70 | $started = true;
71 | break;
72 |
73 | case T_VARIABLE :
74 | case T_STRING :
75 | case T_LNUMBER :
76 | case T_CONSTANT_ENCAPSED_STRING :
77 | case T_DOUBLE_QUOTED_STRING :
78 | case T_ARRAY :
79 | case T_TRUE :
80 | case T_FALSE :
81 | case T_NULL :
82 | if ($started === true)
83 | {
84 | $valid = true;
85 | $running = false;
86 | }
87 |
88 | break;
89 |
90 | case T_CLOSE_PARENTHESIS :
91 | if ($started === false)
92 | {
93 | $valid = true;
94 | }
95 |
96 | $running = false;
97 | break;
98 |
99 | case T_WHITESPACE :
100 | break;
101 |
102 | case T_OPEN_SHORT_ARRAY :
103 | if ($this->shortArraySyntax === true)
104 | {
105 | if ($started === true)
106 | {
107 | $valid = true;
108 | $running = false;
109 | }
110 | }
111 | break;
112 | }
113 |
114 | $cnt++;
115 | }
116 | }
117 | while ($running === true);
118 |
119 | if ($valid === false)
120 | {
121 | $error = 'Instanciating new class without parameters does not require brackets.';
122 | $fix = $phpcsFile->addFixableError($error, $stackPtr, 'NewClass');
123 |
124 | if ($fix === true)
125 | {
126 | $classNameEnd = $phpcsFile->findNext(
127 | array(
128 | T_VARIABLE,
129 | T_WHITESPACE,
130 | T_NS_SEPARATOR,
131 | T_STRING,
132 | T_SELF,
133 | ),
134 | ($stackPtr + 1),
135 | null,
136 | true,
137 | null,
138 | true
139 | );
140 |
141 | $phpcsFile->fixer->beginChangeset();
142 |
143 | if ($tokens[($stackPtr + 3)]['code'] === T_WHITESPACE)
144 | {
145 | $phpcsFile->fixer->replaceToken(($stackPtr + 3), '');
146 | }
147 |
148 | for ($i = $classNameEnd; $i < $cnt; $i++)
149 | {
150 | $phpcsFile->fixer->replaceToken($i, '');
151 | }
152 |
153 | $phpcsFile->fixer->endChangeset();
154 | }
155 | }
156 | }
157 | }
158 |
--------------------------------------------------------------------------------
/Joomla/Sniffs/Commenting/ClassCommentSniff.php:
--------------------------------------------------------------------------------
1 | array(
29 | 'required' => false,
30 | 'allow_multiple' => false,
31 | 'order_text' => 'is first',
32 | ),
33 | '@package' => array(
34 | 'required' => false,
35 | 'allow_multiple' => false,
36 | 'order_text' => 'must follow @category (if used)',
37 | ),
38 | '@subpackage' => array(
39 | 'required' => false,
40 | 'allow_multiple' => false,
41 | 'order_text' => 'must follow @package',
42 | ),
43 | '@author' => array(
44 | 'required' => false,
45 | 'allow_multiple' => true,
46 | 'order_text' => 'is first',
47 | ),
48 | '@copyright' => array(
49 | 'required' => false,
50 | 'allow_multiple' => true,
51 | 'order_text' => 'must follow @author (if used) or @subpackage (if used) or @package (if used)',
52 | ),
53 | '@license' => array(
54 | 'required' => false,
55 | 'allow_multiple' => false,
56 | 'order_text' => 'must follow @copyright (if used)',
57 | ),
58 | '@link' => array(
59 | 'required' => false,
60 | 'allow_multiple' => true,
61 | 'order_text' => 'must follow @license (if used)',
62 | ),
63 | '@see' => array(
64 | 'required' => false,
65 | 'allow_multiple' => true,
66 | 'order_text' => 'must follow @link (if used)',
67 | ),
68 | '@since' => array(
69 | 'required' => true,
70 | 'allow_multiple' => false,
71 | 'order_text' => 'must follow @see (if used) or @link (if used)',
72 | ),
73 | '@deprecated' => array(
74 | 'required' => false,
75 | 'allow_multiple' => false,
76 | 'order_text' => 'must follow @since (if used) or @see (if used) or @link (if used)',
77 | ),
78 | );
79 |
80 | /**
81 | * Returns an array of tokens this test wants to listen for.
82 | *
83 | * @return array
84 | */
85 | public function register()
86 | {
87 | return array(
88 | T_CLASS,
89 | T_INTERFACE,
90 | T_TRAIT
91 | );
92 | }
93 |
94 | /**
95 | * Processes this test, when one of its tokens is encountered.
96 | *
97 | * @param PHP_CodeSniffer_File $phpcsFile The file being scanned.
98 | * @param int $stackPtr The position of the current token
99 | * in the stack passed in $tokens.
100 | *
101 | * @return void
102 | */
103 | public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr)
104 | {
105 | $this->currentFile = $phpcsFile;
106 | $tokens = $phpcsFile->getTokens();
107 | $type = strtolower($tokens[$stackPtr]['content']);
108 | $errorData = array($type);
109 | $find = PHP_CodeSniffer_Tokens::$methodPrefixes;
110 | $find[] = T_WHITESPACE;
111 | $commentEnd = $phpcsFile->findPrevious($find, ($stackPtr - 1), null, true);
112 |
113 | if ($tokens[$commentEnd]['code'] !== T_DOC_COMMENT_CLOSE_TAG
114 | && $tokens[$commentEnd]['code'] !== T_COMMENT
115 | )
116 | {
117 | $phpcsFile->addError('Missing class doc comment', $stackPtr, 'Missing');
118 | $phpcsFile->recordMetric($stackPtr, 'Class has doc comment', 'no');
119 |
120 | return;
121 | }
122 |
123 | $phpcsFile->recordMetric($stackPtr, 'Class has doc comment', 'yes');
124 |
125 | if ($tokens[$commentEnd]['code'] === T_COMMENT)
126 | {
127 | $phpcsFile->addError('You must use "/**" style comments for a class comment', $stackPtr, 'WrongStyle');
128 |
129 | return;
130 | }
131 |
132 | // Check each tag.
133 | $this->processTags($phpcsFile, $stackPtr, $tokens[$commentEnd]['comment_opener']);
134 | }//end process()
135 | }
136 |
--------------------------------------------------------------------------------
/Joomla/Sniffs/Commenting/FileCommentSniff.php:
--------------------------------------------------------------------------------
1 |
16 | * @author Marc McIntyre
17 | * @copyright 2006-2014 Squiz Pty Ltd (ABN 77 084 670 600)
18 | * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
19 | * @link http://pear.php.net/package/PHP_CodeSniffer
20 | *
21 | * @since 1.0
22 | */
23 | class Joomla_Sniffs_Commenting_FileCommentSniff implements PHP_CodeSniffer_Sniff
24 | {
25 | /**
26 | * Tags in correct order and related info.
27 | *
28 | * @var array
29 | */
30 | protected $tags = array(
31 | '@version' => array(
32 | 'required' => false,
33 | 'allow_multiple' => false,
34 | 'order_text' => 'must be first',
35 | ),
36 | '@category' => array(
37 | 'required' => false,
38 | 'allow_multiple' => false,
39 | 'order_text' => 'precedes @package',
40 | ),
41 | '@package' => array(
42 | 'required' => false,
43 | 'allow_multiple' => false,
44 | 'order_text' => 'must follows @category (if used)',
45 | ),
46 | '@subpackage' => array(
47 | 'required' => false,
48 | 'allow_multiple' => false,
49 | 'order_text' => 'must follow @package',
50 | ),
51 | '@author' => array(
52 | 'required' => false,
53 | 'allow_multiple' => true,
54 | 'order_text' => 'must follow @subpackage (if used) or @package',
55 | ),
56 | '@copyright' => array(
57 | 'required' => true,
58 | 'allow_multiple' => true,
59 | 'order_text' => 'must follow @author (if used), @subpackage (if used) or @package',
60 | ),
61 | '@license' => array(
62 | 'required' => true,
63 | 'allow_multiple' => false,
64 | 'order_text' => 'must follow @copyright',
65 | ),
66 | '@link' => array(
67 | 'required' => false,
68 | 'allow_multiple' => true,
69 | 'order_text' => 'must follow @license',
70 | ),
71 | '@see' => array(
72 | 'required' => false,
73 | 'allow_multiple' => true,
74 | 'order_text' => 'must follow @link (if used) or @license',
75 | ),
76 | '@since' => array(
77 | 'required' => false,
78 | 'allow_multiple' => false,
79 | 'order_text' => 'must follows @see (if used), @link (if used) or @license',
80 | ),
81 | '@deprecated' => array(
82 | 'required' => false,
83 | 'allow_multiple' => false,
84 | 'order_text' => 'must follow @since (if used), @see (if used), @link (if used) or @license',
85 | ),
86 | );
87 |
88 | /**
89 | * A list of tokenizers this sniff supports.
90 | *
91 | * @var array
92 | */
93 | public $supportedTokenizers = array(
94 | 'PHP',
95 | 'JS',
96 | );
97 |
98 | /**
99 | * The header comment parser for the current file.
100 | *
101 | * @var PHP_CodeSniffer_Comment_Parser_ClassCommentParser
102 | */
103 | protected $commentParser = null;
104 |
105 | /**
106 | * The current PHP_CodeSniffer_File object we are processing.
107 | *
108 | * @var PHP_CodeSniffer_File
109 | */
110 | protected $currentFile = null;
111 |
112 | /**
113 | * Returns an array of tokens this test wants to listen for.
114 | *
115 | * @return array
116 | */
117 | public function register()
118 | {
119 | return array(T_OPEN_TAG);
120 | }//end register()
121 |
122 | /**
123 | * Processes this test, when one of its tokens is encountered.
124 | *
125 | * @param PHP_CodeSniffer_File $phpcsFile The file being scanned.
126 | * @param int $stackPtr The position of the current token in the stack passed in $tokens.
127 | *
128 | * @return integer
129 | */
130 | public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr)
131 | {
132 | $tokens = $phpcsFile->getTokens();
133 |
134 | // Find the next non whitespace token.
135 | $commentStart = $phpcsFile->findNext(T_WHITESPACE, ($stackPtr + 1), null, true);
136 |
137 | // Allow declare() statements at the top of the file.
138 | if ($tokens[$commentStart]['code'] === T_DECLARE)
139 | {
140 | $semicolon = $phpcsFile->findNext(T_SEMICOLON, ($commentStart + 1));
141 | $commentStart = $phpcsFile->findNext(T_WHITESPACE, ($semicolon + 1), null, true);
142 | }
143 |
144 | // Ignore vim header.
145 | if ($tokens[$commentStart]['code'] === T_COMMENT)
146 | {
147 | if (strstr($tokens[$commentStart]['content'], 'vim:') !== false)
148 | {
149 | $commentStart = $phpcsFile->findNext(
150 | T_WHITESPACE,
151 | ($commentStart + 1),
152 | null,
153 | true
154 | );
155 | }
156 | }
157 |
158 | $errorToken = ($stackPtr + 1);
159 |
160 | if (isset($tokens[$errorToken]) === false)
161 | {
162 | $errorToken--;
163 | }
164 |
165 | if ($tokens[$commentStart]['code'] === T_CLOSE_TAG)
166 | {
167 | // We are only interested if this is the first open tag.
168 | return ($phpcsFile->numTokens + 1);
169 | }
170 | elseif ($tokens[$commentStart]['code'] === T_COMMENT)
171 | {
172 | $error = 'You must use "/**" style comments for a file comment';
173 | $phpcsFile->addError($error, $errorToken, 'WrongStyle');
174 | $phpcsFile->recordMetric($stackPtr, 'File has doc comment', 'yes');
175 |
176 | return ($phpcsFile->numTokens + 1);
177 | }
178 | elseif ($commentStart === false
179 | || $tokens[$commentStart]['code'] !== T_DOC_COMMENT_OPEN_TAG
180 | )
181 | {
182 | $phpcsFile->addError('Missing file doc comment', $errorToken, 'Missing');
183 | $phpcsFile->recordMetric($stackPtr, 'File has doc comment', 'no');
184 |
185 | return ($phpcsFile->numTokens + 1);
186 | }
187 | else
188 | {
189 | $phpcsFile->recordMetric($stackPtr, 'File has doc comment', 'yes');
190 | }
191 |
192 | // Check each tag.
193 | $this->processTags($phpcsFile, $stackPtr, $commentStart);
194 |
195 | // Ignore the rest of the file.
196 | return ($phpcsFile->numTokens + 1);
197 | }//end process()
198 |
199 | /**
200 | * Processes each required or optional tag.
201 | *
202 | * @param PHP_CodeSniffer_File $phpcsFile The file being scanned.
203 | * @param int $stackPtr The position of the current token
204 | * in the stack passed in $tokens.
205 | * @param int $commentStart Position in the stack where the comment started.
206 | *
207 | * @return void
208 | */
209 | protected function processTags(PHP_CodeSniffer_File $phpcsFile, $stackPtr, $commentStart)
210 | {
211 | $tokens = $phpcsFile->getTokens();
212 |
213 | if (get_class($this) === 'Joomla_Sniffs_Commenting_FileCommentSniff')
214 | {
215 | $docBlock = 'file';
216 | }
217 | else
218 | {
219 | $docBlock = 'class';
220 | }
221 |
222 | $commentEnd = $tokens[$commentStart]['comment_closer'];
223 | $foundTags = array();
224 | $tagTokens = array();
225 |
226 | foreach ($tokens[$commentStart]['comment_tags'] as $tag)
227 | {
228 | $name = $tokens[$tag]['content'];
229 |
230 | if (isset($this->tags[$name]) === false)
231 | {
232 | continue;
233 | }
234 |
235 | if ($this->tags[$name]['allow_multiple'] === false && isset($tagTokens[$name]) === true)
236 | {
237 | $error = 'Only one %s tag is allowed in a %s comment';
238 | $data = array(
239 | $name,
240 | $docBlock,
241 | );
242 | $phpcsFile->addError($error, $tag, 'Duplicate' . ucfirst(substr($name, 1)) . 'Tag', $data);
243 | }
244 |
245 | $foundTags[] = $name;
246 | $tagTokens[$name][] = $tag;
247 | $string = $phpcsFile->findNext(T_DOC_COMMENT_STRING, $tag, $commentEnd);
248 |
249 | if ($string === false || $tokens[$string]['line'] !== $tokens[$tag]['line'])
250 | {
251 | $error = 'Content missing for %s tag in %s comment';
252 | $data = array(
253 | $name,
254 | $docBlock,
255 | );
256 | $phpcsFile->addError($error, $tag, 'Empty' . ucfirst(substr($name, 1)) . 'Tag', $data);
257 | continue;
258 | }
259 | }//end foreach
260 |
261 | // Check if the tags are in the correct position.
262 | $pos = 0;
263 |
264 | foreach ($this->tags as $tag => $tagData)
265 | {
266 | // We don't use package tags in namespaced classes.
267 | if ($tag === '@package' || $tag === '@subpackage')
268 | {
269 | // Check for a namespace token, if certain other tokens are found we can move on. This keeps us from searching the whole file.
270 | $namespaced = $phpcsFile->findNext(array(T_NAMESPACE, T_CLASS, T_INTERFACE, T_TRAIT), 0);
271 | $classes = array(T_CLASS, T_INTERFACE, T_TRAIT);
272 | $class = $phpcsFile->findNext($classes, 0);
273 |
274 | // If we found a namespaced class trigger the error.
275 | if ($tokens[$namespaced]['code'] === T_NAMESPACE && in_array($tokens[$class]['code'], $classes, true))
276 | {
277 | if (isset($tagTokens[$tag]) === true)
278 | {
279 | $error = '%s tag found in namespaced %s comment';
280 | $data = array(
281 | $tag,
282 | $docBlock,
283 | );
284 | $phpcsFile->addError($error, $commentEnd, ucfirst(substr($tag, 1)) . 'TagInNamespace', $data);
285 | }
286 |
287 | continue;
288 | }
289 | }
290 |
291 | if (isset($tagTokens[$tag]) === false)
292 | {
293 | if ($tagData['required'] === true)
294 | {
295 | $error = 'Missing %s tag in %s comment';
296 | $data = array(
297 | $tag,
298 | $docBlock,
299 | );
300 | $phpcsFile->addError($error, $commentEnd, 'Missing' . ucfirst(substr($tag, 1)) . 'Tag', $data);
301 | }
302 |
303 | continue;
304 | }
305 | else
306 | {
307 | $method = 'process' . substr($tag, 1);
308 |
309 | if (method_exists($this, $method) === true)
310 | {
311 | // Process each tag if a method is defined.
312 | call_user_func(array($this, $method), $phpcsFile, $tagTokens[$tag]);
313 | }
314 | }
315 |
316 | if (isset($foundTags[$pos]) === false)
317 | {
318 | break;
319 | }
320 |
321 | if ($foundTags[$pos] !== $tag)
322 | {
323 | $error = 'The tag in position %s should be the %s tag';
324 | $data = array(
325 | ($pos + 1),
326 | $tag,
327 | );
328 | $phpcsFile->addError($error, $tokens[$commentStart]['comment_tags'][$pos], ucfirst(substr($tag, 1)) . 'TagOrder', $data);
329 | }
330 |
331 | // Account for multiple tags.
332 | $pos++;
333 |
334 | while (isset($foundTags[$pos]) === true && $foundTags[$pos] === $tag)
335 | {
336 | $pos++;
337 | }
338 | }//end foreach
339 | }//end processTags()
340 |
341 | /**
342 | * Process the category tag.
343 | *
344 | * @param PHP_CodeSniffer_File $phpcsFile The file being scanned.
345 | * @param array $tags The tokens for these tags.
346 | *
347 | * @return void
348 | */
349 | protected function processCategory(PHP_CodeSniffer_File $phpcsFile, array $tags)
350 | {
351 | $tokens = $phpcsFile->getTokens();
352 |
353 | foreach ($tags as $tag)
354 | {
355 | if ($tokens[($tag + 2)]['code'] !== T_DOC_COMMENT_STRING)
356 | {
357 | // No content.
358 | continue;
359 | }
360 |
361 | $content = $tokens[($tag + 2)]['content'];
362 |
363 | if (PHP_CodeSniffer::isUnderscoreName($content) !== true)
364 | {
365 | $newContent = str_replace(' ', '_', $content);
366 | $nameBits = explode('_', $newContent);
367 | $firstBit = array_shift($nameBits);
368 | $newName = ucfirst($firstBit) . '_';
369 |
370 | foreach ($nameBits as $bit)
371 | {
372 | if ($bit !== '')
373 | {
374 | $newName .= ucfirst($bit) . '_';
375 | }
376 | }
377 |
378 | $error = 'Category name "%s" is not valid; consider "%s" instead';
379 | $validName = trim($newName, '_');
380 | $data = array(
381 | $content,
382 | $validName,
383 | );
384 | $phpcsFile->addError($error, $tag, 'InvalidCategory', $data);
385 | }
386 | }//end foreach
387 | }//end processCategory()
388 |
389 | /**
390 | * Process the package tag.
391 | *
392 | * @param PHP_CodeSniffer_File $phpcsFile The file being scanned.
393 | * @param array $tags The tokens for these tags.
394 | *
395 | * @return void
396 | */
397 | protected function processPackage(PHP_CodeSniffer_File $phpcsFile, array $tags)
398 | {
399 | $tokens = $phpcsFile->getTokens();
400 |
401 | foreach ($tags as $tag)
402 | {
403 | if ($tokens[($tag + 2)]['code'] !== T_DOC_COMMENT_STRING)
404 | {
405 | // No content.
406 | continue;
407 | }
408 |
409 | $content = $tokens[($tag + 2)]['content'];
410 |
411 | if (PHP_CodeSniffer::isUnderscoreName($content) === true)
412 | {
413 | continue;
414 | }
415 |
416 | $newContent = str_replace(' ', '_', $content);
417 | $newContent = trim($newContent, '_');
418 | $newContent = preg_replace('/[^A-Za-z_]/', '', $newContent);
419 |
420 | if ($newContent === '')
421 | {
422 | $error = 'Package name "%s" is not valid';
423 | $data = array($content);
424 | $phpcsFile->addError($error, $tag, 'InvalidPackageValue', $data);
425 | }
426 | else
427 | {
428 | $nameBits = explode('_', $newContent);
429 | $firstBit = array_shift($nameBits);
430 | $newName = strtoupper($firstBit[0]) . substr($firstBit, 1) . '_';
431 |
432 | foreach ($nameBits as $bit)
433 | {
434 | if ($bit !== '')
435 | {
436 | $newName .= strtoupper($bit[0]) . substr($bit, 1) . '_';
437 | }
438 | }
439 |
440 | $error = 'Package name "%s" is not valid; consider "%s" instead';
441 | $validName = trim($newName, '_');
442 | $data = array(
443 | $content,
444 | $validName,
445 | );
446 | $phpcsFile->addError($error, $tag, 'InvalidPackage', $data);
447 | }//end if
448 | }//end foreach
449 | }//end processPackage()
450 |
451 | /**
452 | * Process the subpackage tag.
453 | *
454 | * @param PHP_CodeSniffer_File $phpcsFile The file being scanned.
455 | * @param array $tags The tokens for these tags.
456 | *
457 | * @return void
458 | */
459 | protected function processSubpackage(PHP_CodeSniffer_File $phpcsFile, array $tags)
460 | {
461 | $tokens = $phpcsFile->getTokens();
462 |
463 | foreach ($tags as $tag)
464 | {
465 | if ($tokens[($tag + 2)]['code'] !== T_DOC_COMMENT_STRING)
466 | {
467 | // No content.
468 | continue;
469 | }
470 |
471 | $content = $tokens[($tag + 2)]['content'];
472 |
473 | // Is the subpackage included and empty.
474 | if (empty($content) || $content == '')
475 | {
476 | $error = 'if included, @subpackage tag must contain a name';
477 | $phpcsFile->addError($error, $tag, 'EmptySubpackage');
478 | }
479 | }//end foreach
480 | }//end processSubpackage()
481 |
482 | /**
483 | * Process the author tag(s) that this header comment has.
484 | *
485 | * @param PHP_CodeSniffer_File $phpcsFile The file being scanned.
486 | * @param array $tags The tokens for these tags.
487 | *
488 | * @return void
489 | */
490 | protected function processAuthor(PHP_CodeSniffer_File $phpcsFile, array $tags)
491 | {
492 | $tokens = $phpcsFile->getTokens();
493 |
494 | foreach ($tags as $tag)
495 | {
496 | if ($tokens[($tag + 2)]['code'] !== T_DOC_COMMENT_STRING)
497 | {
498 | // No content.
499 | continue;
500 | }
501 |
502 | $content = $tokens[($tag + 2)]['content'];
503 | $local = '\da-zA-Z-_+';
504 |
505 | // Dot character cannot be the first or last character in the local-part.
506 | $localMiddle = $local . '.\w';
507 |
508 | if (preg_match(
509 | '/^([^<]*)\s+<([' . $local . ']([' . $localMiddle . ']*[' . $local . '])*@[\da-zA-Z][-.\w]*[\da-zA-Z]\.[a-zA-Z]{2,7})>$/',
510 | $content
511 | ) === 0)
512 | {
513 | $error = 'Content of the @author tag must be in the form "Display Name "';
514 | $phpcsFile->addError($error, $tag, 'InvalidAuthors');
515 | }
516 | }
517 | }//end processAuthor()
518 |
519 | /**
520 | * Process the copyright tags.
521 | *
522 | * @param PHP_CodeSniffer_File $phpcsFile The file being scanned.
523 | * @param array $tags The tokens for these tags.
524 | *
525 | * @return void
526 | */
527 | protected function processCopyright(PHP_CodeSniffer_File $phpcsFile, array $tags)
528 | {
529 | $tokens = $phpcsFile->getTokens();
530 |
531 | foreach ($tags as $tag)
532 | {
533 | if ($tokens[($tag + 2)]['code'] !== T_DOC_COMMENT_STRING)
534 | {
535 | // No content.
536 | continue;
537 | }
538 |
539 | $content = $tokens[($tag + 2)]['content'];
540 | $matches = array();
541 |
542 | if (preg_match('/^.*?([0-9]{4})((.{1})([0-9]{4}))? (.+)$/', $content, $matches) !== 0)
543 | {
544 | // Check earliest-latest year order.
545 | if ($matches[3] !== '' && $matches[3] !== null)
546 | {
547 | if ($matches[3] !== '-')
548 | {
549 | $error = 'A hyphen must be used between the earliest and latest year';
550 | $phpcsFile->addError($error, $tag, 'CopyrightHyphen');
551 | }
552 |
553 | if ($matches[4] !== '' && $matches[4] !== null && $matches[4] < $matches[1])
554 | {
555 | $error = "Invalid year span \"$matches[1]$matches[3]$matches[4]\" found; consider \"$matches[4]-$matches[1]\" instead";
556 | $phpcsFile->addWarning($error, $tag, 'InvalidCopyright');
557 | }
558 | }
559 | }
560 | else
561 | {
562 | $error = '@copyright tag must contain a year and the name of the copyright holder';
563 | $phpcsFile->addError($error, $tag, 'IncompleteCopyright');
564 | }
565 | }//end foreach
566 | }//end processCopyright()
567 |
568 | /**
569 | * Process the license tag.
570 | *
571 | * @param PHP_CodeSniffer_File $phpcsFile The file being scanned.
572 | * @param array $tags The tokens for these tags.
573 | *
574 | * @return void
575 | */
576 | protected function processLicense(PHP_CodeSniffer_File $phpcsFile, array $tags)
577 | {
578 | $tokens = $phpcsFile->getTokens();
579 |
580 | foreach ($tags as $tag)
581 | {
582 | if ($tokens[($tag + 2)]['code'] !== T_DOC_COMMENT_STRING)
583 | {
584 | // No content.
585 | continue;
586 | }
587 |
588 | $content = $tokens[($tag + 2)]['content'];
589 | $matches = array();
590 | preg_match('/^([^\s]+)\s+(.*)/', $content, $matches);
591 |
592 | if (count($matches) !== 3)
593 | {
594 | $error = '@license tag must contain a URL and a license name';
595 | $phpcsFile->addError($error, $tag, 'IncompleteLicense');
596 | }
597 | }
598 | }//end processLicense()
599 |
600 | /**
601 | * Process the version tag.
602 | *
603 | * @param PHP_CodeSniffer_File $phpcsFile The file being scanned.
604 | * @param array $tags The tokens for these tags.
605 | *
606 | * @return void
607 | */
608 | protected function processVersion(PHP_CodeSniffer_File $phpcsFile, array $tags)
609 | {
610 | $tokens = $phpcsFile->getTokens();
611 |
612 | foreach ($tags as $tag)
613 | {
614 | $content = $tokens[($tag)]['code'];
615 |
616 | if ($content === '@version')
617 | {
618 | $error = '@version tag in file comment in not required; consider removing or using @since';
619 | $data = array($content);
620 | $phpcsFile->addWarning($error, $tag, 'IncludedVersion', $data);
621 | }
622 | }
623 | }//end processVersion()
624 | }//end class
625 |
--------------------------------------------------------------------------------
/Joomla/Sniffs/Commenting/FunctionCommentSniff.php:
--------------------------------------------------------------------------------
1 | getTokens();
39 |
40 | $methodName = $phpcsFile->getDeclarationName($stackPtr);
41 | $isSpecialMethod = ($methodName === '__construct' || $methodName === '__destruct');
42 |
43 | $return = null;
44 |
45 | foreach ($tokens[$commentStart]['comment_tags'] as $tag)
46 | {
47 | if ($tokens[$tag]['content'] === '@return')
48 | {
49 | // Joomla Standard - Constructors and destructors should not have a @return tag
50 | if ($isSpecialMethod)
51 | {
52 | $error = 'Constructor and destructor comments must not have a @return tag';
53 | $phpcsFile->addError($error, $tag, 'UselessReturn');
54 |
55 | return;
56 | }
57 | elseif ($return !== null)
58 | {
59 | $error = 'Only 1 @return tag is allowed in a function comment';
60 | $phpcsFile->addError($error, $tag, 'DuplicateReturn');
61 |
62 | return;
63 | }
64 |
65 | $return = $tag;
66 | }
67 | }
68 |
69 | if ($isSpecialMethod === true)
70 | {
71 | return;
72 | }
73 |
74 | if ($return !== null)
75 | {
76 | $content = $tokens[($return + 2)]['content'];
77 |
78 | if (empty($content) === true || $tokens[($return + 2)]['code'] !== T_DOC_COMMENT_STRING)
79 | {
80 | $error = 'Return type missing for @return tag in function comment';
81 | $phpcsFile->addError($error, $return, 'MissingReturnType');
82 | }
83 | else
84 | {
85 | // Support both a return type and a description.
86 | preg_match('`^((?:\|?(?:array\([^\)]*\)|[\\\\a-z0-9\[\]]+))*)( .*)?`i', $content, $returnParts);
87 |
88 | if (isset($returnParts[1]) === false)
89 | {
90 | return;
91 | }
92 |
93 | $returnType = $returnParts[1];
94 |
95 | // Check return type (can have multiple return types separated by '|').
96 | $typeNames = explode('|', $returnType);
97 | $suggestedNames = array();
98 |
99 | foreach ($typeNames as $i => $typeName)
100 | {
101 | $suggestedName = PHP_CodeSniffer::suggestType($typeName);
102 |
103 | if (in_array($suggestedName, $suggestedNames) === false)
104 | {
105 | $suggestedNames[] = $suggestedName;
106 | }
107 | }
108 |
109 | $suggestedType = implode('|', $suggestedNames);
110 |
111 | if ($returnType !== $suggestedType)
112 | {
113 | $error = 'Expected "%s" but found "%s" for function return type';
114 | $data = array(
115 | $suggestedType,
116 | $returnType
117 | );
118 |
119 | $fix = $phpcsFile->addFixableError($error, $return, 'InvalidReturn', $data);
120 |
121 | if ($fix === true)
122 | {
123 | $replacement = $suggestedType;
124 |
125 | if (empty($returnParts[2]) === false)
126 | {
127 | $replacement .= $returnParts[2];
128 | }
129 |
130 | $phpcsFile->fixer->replaceToken(($return + 2), $replacement);
131 | unset($replacement);
132 | }
133 | }
134 |
135 | /*
136 | * If return type is not void, there needs to be a return statement
137 | * somewhere in the function that returns something.
138 | * Skip this check for mixed return types.
139 | */
140 | if ($returnType === 'void')
141 | {
142 | if (isset($tokens[$stackPtr]['scope_closer']) === true)
143 | {
144 | $endToken = $tokens[$stackPtr]['scope_closer'];
145 |
146 | for ($returnToken = $stackPtr; $returnToken < $endToken; $returnToken++)
147 | {
148 | if ($tokens[$returnToken]['code'] === T_CLOSURE
149 | || $tokens[$returnToken]['code'] === T_ANON_CLASS
150 | )
151 | {
152 | $returnToken = $tokens[$returnToken]['scope_closer'];
153 | continue;
154 | }
155 |
156 | if ($tokens[$returnToken]['code'] === T_RETURN
157 | || $tokens[$returnToken]['code'] === T_YIELD
158 | || $tokens[$returnToken]['code'] === T_YIELD_FROM
159 | )
160 | {
161 | break;
162 | }
163 | }
164 |
165 | if ($returnToken !== $endToken)
166 | {
167 | // If the function is not returning anything, just exiting, then there is no problem.
168 | $semicolon = $phpcsFile->findNext(T_WHITESPACE, ($returnToken + 1), null, true);
169 |
170 | if ($tokens[$semicolon]['code'] !== T_SEMICOLON)
171 | {
172 | $error = 'Function return type is void, but function contains return statement';
173 | $phpcsFile->addError($error, $return, 'InvalidReturnVoid');
174 | }
175 | }
176 | }//end if
177 | }
178 | elseif ($returnType !== 'mixed' && in_array('void', $typeNames, true) === false)
179 | {
180 | // If return type is not void, there needs to be a return statement somewhere in the function that returns something.
181 | if (isset($tokens[$stackPtr]['scope_closer']) === true)
182 | {
183 | $endToken = $tokens[$stackPtr]['scope_closer'];
184 |
185 | for ($returnToken = $stackPtr; $returnToken < $endToken; $returnToken++)
186 | {
187 | if ($tokens[$returnToken]['code'] === T_CLOSURE
188 | || $tokens[$returnToken]['code'] === T_ANON_CLASS
189 | )
190 | {
191 | $returnToken = $tokens[$returnToken]['scope_closer'];
192 | continue;
193 | }
194 |
195 | if ($tokens[$returnToken]['code'] === T_RETURN
196 | || $tokens[$returnToken]['code'] === T_YIELD
197 | || $tokens[$returnToken]['code'] === T_YIELD_FROM
198 | )
199 | {
200 | break;
201 | }
202 | }
203 |
204 | if ($returnToken === $endToken)
205 | {
206 | $error = 'Function return type is not void, but function has no return statement';
207 | $phpcsFile->addError($error, $return, 'InvalidNoReturn');
208 | }
209 | else
210 | {
211 | $semicolon = $phpcsFile->findNext(T_WHITESPACE, ($returnToken + 1), null, true);
212 |
213 | if ($tokens[$semicolon]['code'] === T_SEMICOLON)
214 | {
215 | $error = 'Function return type is not void, but function is returning void here';
216 | $phpcsFile->addError($error, $returnToken, 'InvalidReturnNotVoid');
217 | }
218 | }
219 | }
220 | }
221 | }
222 | }
223 | else
224 | {
225 | $error = 'Missing @return tag in function comment';
226 | $phpcsFile->addError($error, $tokens[$commentStart]['comment_closer'], 'MissingReturn');
227 | }
228 | }
229 |
230 | /**
231 | * Process the function parameter comments.
232 | *
233 | * Extends PEAR.Commenting.FunctionComment.processReturn to enforce correct alignment of the doc block.
234 | *
235 | * @param PHP_CodeSniffer_File $phpcsFile The file being scanned.
236 | * @param integer $stackPtr The position of the current token in the stack passed in $tokens.
237 | * @param integer $commentStart The position in the stack where the comment started.
238 | *
239 | * @return void
240 | *
241 | * @todo Reinstate the check that params come after the function's comment and has a blank line before them
242 | * @todo Reinstate the check that there is a blank line after all params are declared
243 | */
244 | protected function processParams(PHP_CodeSniffer_File $phpcsFile, $stackPtr, $commentStart)
245 | {
246 | $tokens = $phpcsFile->getTokens();
247 |
248 | $params = array();
249 | $maxType = 0;
250 | $maxVar = 0;
251 |
252 | foreach ($tokens[$commentStart]['comment_tags'] as $pos => $tag)
253 | {
254 | if ($tokens[$tag]['content'] !== '@param')
255 | {
256 | continue;
257 | }
258 |
259 | $type = '';
260 | $typeSpace = 0;
261 | $var = '';
262 | $varSpace = 0;
263 | $comment = '';
264 | $commentEnd = 0;
265 |
266 | if ($tokens[($tag + 2)]['code'] === T_DOC_COMMENT_STRING)
267 | {
268 | $matches = array();
269 | preg_match('/([^$&.]+)(?:((?:\.\.\.)?(?:\$|&)[^\s]+)(?:(\s+)(.*))?)?/', $tokens[($tag + 2)]['content'], $matches);
270 |
271 | if (empty($matches) === false)
272 | {
273 | $typeLen = strlen($matches[1]);
274 | $type = trim($matches[1]);
275 | $typeSpace = ($typeLen - strlen($type));
276 | $typeLen = strlen($type);
277 |
278 | if ($typeLen > $maxType)
279 | {
280 | $maxType = $typeLen;
281 | }
282 | }
283 |
284 | if (isset($matches[2]) === true)
285 | {
286 | $var = $matches[2];
287 | $varLen = strlen($var);
288 |
289 | if ($varLen > $maxVar)
290 | {
291 | $maxVar = $varLen;
292 | }
293 |
294 | if (isset($matches[4]) === true)
295 | {
296 | $varSpace = strlen($matches[3]);
297 | $comment = $matches[4];
298 |
299 | // Any strings until the next tag belong to this comment.
300 | if (isset($tokens[$commentStart]['comment_tags'][($pos + 1)]) === true)
301 | {
302 | $end = $tokens[$commentStart]['comment_tags'][($pos + 1)];
303 | }
304 | else
305 | {
306 | $end = $tokens[$commentStart]['comment_closer'];
307 | }
308 |
309 | for ($i = ($tag + 3); $i < $end; $i++)
310 | {
311 | if ($tokens[$i]['code'] === T_DOC_COMMENT_STRING)
312 | {
313 | $comment .= ' ' . $tokens[$i]['content'];
314 | $commentEnd = $i;
315 | }
316 | }
317 | }
318 | else
319 | {
320 | $error = 'Missing parameter comment';
321 | $phpcsFile->addError($error, $tag, 'MissingParamComment');
322 | }
323 | }
324 | else
325 | {
326 | $error = 'Missing parameter name';
327 | $phpcsFile->addError($error, $tag, 'MissingParamName');
328 | }
329 | }
330 | else
331 | {
332 | $error = 'Missing parameter type';
333 | $phpcsFile->addError($error, $tag, 'MissingParamType');
334 | }
335 |
336 | $params[] = array(
337 | 'tag' => $tag,
338 | 'type' => $type,
339 | 'var' => $var,
340 | 'comment' => $comment,
341 | 'comment_end' => $commentEnd,
342 | 'type_space' => $typeSpace,
343 | 'var_space' => $varSpace,
344 | 'align_space' => $tokens[($tag + 1)]['content']
345 | );
346 | }
347 |
348 | $realParams = $phpcsFile->getMethodParameters($stackPtr);
349 | $foundParams = array();
350 | $previousParam = null;
351 |
352 | /*
353 | * We want to use ... for all variable length arguments,
354 | * so added this prefix to the variable name so comparisons are easier.
355 | */
356 | foreach ($realParams as $pos => $param)
357 | {
358 | if ($param['variable_length'] === true)
359 | {
360 | $realParams[$pos]['name'] = '...' . $realParams[$pos]['name'];
361 | }
362 | }
363 |
364 | foreach ($params as $pos => $param)
365 | {
366 | if ($param['var'] === '')
367 | {
368 | continue;
369 | }
370 |
371 | $foundParams[] = $param['var'];
372 |
373 | // Joomla change: There must be 3 spaces after the @param tag to make it line up with the @return tag
374 | if ($param['align_space'] !== ' ')
375 | {
376 | $error = 'Expected 3 spaces before variable type, found %s';
377 | $spaces = strlen($param['align_space']);
378 | $data = array($spaces);
379 | $fix = $phpcsFile->addFixableError($error, $param['tag'], 'BeforeParamType', $data);
380 |
381 | if ($fix === true)
382 | {
383 | $phpcsFile->fixer->beginChangeset();
384 |
385 | for ($i = 0; $i < $spaces; $i++)
386 | {
387 | $phpcsFile->fixer->replaceToken(($param['tag'] + 1), '');
388 | }
389 |
390 | $phpcsFile->fixer->addContent($param['tag'], ' ');
391 | $phpcsFile->fixer->endChangeset();
392 | }
393 | }
394 |
395 | // Make sure the param name is correct.
396 | if (isset($realParams[$pos]) === true)
397 | {
398 | $realName = $realParams[$pos]['name'];
399 |
400 | if ($realName !== $param['var'])
401 | {
402 | $code = 'ParamNameNoMatch';
403 | $data = array(
404 | $param['var'],
405 | $realName
406 | );
407 |
408 | $error = 'Doc comment for parameter %s does not match ';
409 |
410 | if (strtolower($param['var']) === strtolower($realName))
411 | {
412 | $error .= 'case of ';
413 | $code = 'ParamNameNoCaseMatch';
414 | }
415 |
416 | $error .= 'actual variable name %s';
417 |
418 | $phpcsFile->addError($error, $param['tag'], $code, $data);
419 | }
420 | }
421 | elseif (substr($param['var'], -4) !== ',...')
422 | {
423 | // We must have an extra parameter comment.
424 | $error = 'Superfluous parameter comment';
425 | $phpcsFile->addError($error, $param['tag'], 'ExtraParamComment');
426 | }
427 |
428 | if ($param['comment'] === '')
429 | {
430 | continue;
431 | }
432 |
433 | // Joomla change: Enforces alignment of the param variables and comments
434 | if ($previousParam !== null)
435 | {
436 | $previousName = ($previousParam['var'] !== '') ? $previousParam['var'] : 'UNKNOWN';
437 |
438 | // Check to see if the parameters align properly.
439 | if (!$this->paramVarsAlign($param, $previousParam))
440 | {
441 | $error = 'The variable names for parameters %s and %s do not align';
442 | $data = array(
443 | $previousName,
444 | $param['var']
445 | );
446 | $phpcsFile->addError($error, $param['tag'], 'ParameterNamesNotAligned', $data);
447 | }
448 |
449 | // Check to see if the comments align properly.
450 | if (!$this->paramCommentsAlign($param, $previousParam))
451 | {
452 | $error = 'The comments for parameters %s and %s do not align';
453 | $data = array(
454 | $previousName,
455 | $param['var']
456 | );
457 | $phpcsFile->addError($error, $param['tag'], 'ParameterCommentsNotAligned', $data);
458 | }
459 | }
460 |
461 | $previousParam = $param;
462 | }
463 |
464 | $realNames = array();
465 |
466 | foreach ($realParams as $realParam)
467 | {
468 | $realNames[] = $realParam['name'];
469 | }
470 |
471 | // Report missing comments.
472 | $diff = array_diff($realNames, $foundParams);
473 |
474 | foreach ($diff as $neededParam)
475 | {
476 | $error = 'Doc comment for parameter "%s" missing';
477 | $data = array($neededParam);
478 | $phpcsFile->addError($error, $commentStart, 'MissingParamTag', $data);
479 | }
480 |
481 | }
482 |
483 | /**
484 | * Ensure the method's parameter comments align
485 | *
486 | * @param array $param The current parameter being checked
487 | * @param array $previousParam The previous parameter that was checked
488 | *
489 | * @return boolean
490 | */
491 | private function paramCommentsAlign($param, $previousParam)
492 | {
493 | $paramLength = strlen($param['type']) + $param['type_space'] + strlen($param['var']) + $param['var_space'];
494 | $prevLength = strlen($previousParam['type']) + $previousParam['type_space'] + strlen($previousParam['var']) + $previousParam['var_space'];
495 |
496 | return $paramLength === $prevLength;
497 | }
498 |
499 | /**
500 | * Ensure the method's parameter variable names align
501 | *
502 | * @param array $param The current parameter being checked
503 | * @param array $previousParam The previous parameter that was checked
504 | *
505 | * @return boolean
506 | */
507 | private function paramVarsAlign($param, $previousParam)
508 | {
509 | $paramStringLength = strlen($param['type']) + $param['type_space'];
510 | $previousParamStringLength = strlen($previousParam['type']) + $previousParam['type_space'];
511 |
512 | return $paramStringLength === $previousParamStringLength;
513 | }
514 | }
515 |
--------------------------------------------------------------------------------
/Joomla/Sniffs/Commenting/SingleCommentSniff.php:
--------------------------------------------------------------------------------
1 | getTokens();
38 | $singleLine = false;
39 | $comment = trim($tokens[$stackPtr]['content']);
40 |
41 | // Hash comments are not allowed.
42 | if ($tokens[$stackPtr]['content'][0] === '#')
43 | {
44 | $phpcsFile->recordMetric($stackPtr, 'Inline comment style', '# ...');
45 |
46 | $error = 'Perl-style Hash comments are prohibited. Use "// Comment."';
47 | $error .= ' or "/* comment */" instead.';
48 | $fix = $phpcsFile->addFixableError($error, $stackPtr, 'WrongStyle');
49 |
50 | if ($fix === true)
51 | {
52 | $newComment = ltrim($tokens[$stackPtr]['content'], '# ');
53 | $newComment = '// ' . $newComment;
54 | $phpcsFile->fixer->replaceToken($stackPtr, $newComment);
55 | }
56 | }
57 | elseif ($tokens[$stackPtr]['content'][0] === '/' && $tokens[$stackPtr]['content'][1] === '/')
58 | {
59 | $phpcsFile->recordMetric($stackPtr, 'Inline comment style', '// ...');
60 | $singleLine = true;
61 | }
62 | elseif ($tokens[$stackPtr]['content'][0] === '/' && $tokens[$stackPtr]['content'][1] === '*')
63 | {
64 | $phpcsFile->recordMetric($stackPtr, 'Inline comment style', '/* ... */');
65 | }
66 |
67 | // Always have a space between // and the start of the comment text.
68 | // The exception to this is if the preceding line consists of a single open bracket.
69 | if ($tokens[$stackPtr]['content'][0] === '/' && $tokens[$stackPtr]['content'][1] === '/' && isset($tokens[$stackPtr]['content'][2])
70 | && $tokens[$stackPtr]['content'][2] !== ' ' && isset($tokens[($stackPtr - 1)]['content'][0])
71 | && $tokens[($stackPtr - 1)]['content'][0] !== '}'
72 | )
73 | {
74 | $error = 'Missing space between the // and the start of the comment text.';
75 | $fix = $phpcsFile->addFixableError($error, $stackPtr, 'NoSpace');
76 |
77 | if ($fix === true)
78 | {
79 | $newComment = ltrim($tokens[$stackPtr]['content'], '\//');
80 | $newComment = '// ' . $newComment;
81 |
82 | $phpcsFile->fixer->replaceToken($stackPtr, $newComment);
83 | }
84 | }
85 |
86 | /*
87 | * New lines should always start with an upper case letter, unless
88 | * the line is a continuation of a complete sentence,
89 | * the term is code and is case sensitive.(@todo)
90 | */
91 | if (($singleLine === true && isset($tokens[$stackPtr]['content'][3]) && $tokens[$stackPtr]['content'][2] === ' '
92 | && $tokens[$stackPtr]['content'][3] !== strtoupper($tokens[$stackPtr]['content'][3])) || (isset($comment[2]) && $comment[0] === '*'
93 | && $comment[1] === ' ' && $comment[2] !== strtoupper($comment[2]))
94 | )
95 | {
96 | $error = 'Comment must start with a capital letter; found "%s"';
97 | $previous = $phpcsFile->findPrevious(T_COMMENT, $stackPtr - 1);
98 |
99 | if ($singleLine === true)
100 | {
101 | $data = array($comment[3]);
102 | $newComment = ltrim($tokens[$stackPtr]['content'], '\// ');
103 | $newComment = '// ' . ucfirst($newComment);
104 | }
105 | else
106 | {
107 | $data = array($comment[2]);
108 | $padding = (strlen($tokens[$stackPtr]['content']) - strlen($comment));
109 | $padding = str_repeat("\t", $padding - 2);
110 | $newComment = ltrim($comment, '* ');
111 | $newComment = $padding . ' * ' . ucfirst($newComment) . $phpcsFile->eolChar;
112 | }
113 |
114 | // Check for a comment on the previous line.
115 | if ($tokens[$previous]['line'] === $tokens[$stackPtr]['line'] - 1 && '/*' !== substr(ltrim($tokens[$previous]['content']), 0, 2))
116 | {
117 | $test = trim($tokens[$previous]['content']);
118 |
119 | if ('.' === $test[(strlen($test) - 1)])
120 | {
121 | $fix = $phpcsFile->addFixableError($error, $stackPtr, 'LowerCaseAfterSentenceEnd', $data);
122 |
123 | if ($fix === true)
124 | {
125 | $phpcsFile->fixer->replaceToken($stackPtr, $newComment);
126 | }
127 | }
128 | }
129 | else
130 | {
131 | $fix = $phpcsFile->addFixableError($error, $stackPtr, 'LowerCaseStart', $data);
132 |
133 | if ($fix === true)
134 | {
135 | $phpcsFile->fixer->replaceToken($stackPtr, $newComment);
136 | }
137 | }
138 | }
139 |
140 | /*
141 | * Comments should not be on the same line as the code to which they refer
142 | * (which puts them after the code they reference).
143 | * They should be on their own lines.
144 | * @todo Add fixer
145 | */
146 | $previous = $phpcsFile->findPrevious(T_SEMICOLON, $stackPtr);
147 |
148 | if (isset($tokens[$previous]['line']) && $tokens[$previous]['line'] === $tokens[$stackPtr]['line'])
149 | {
150 | $error = 'Please put your comment on a separate line *preceding* your code; found "%s"';
151 | $data = array($comment);
152 | $phpcsFile->addError($error, $stackPtr, 'SameLine', $data);
153 | }
154 |
155 | /*
156 | * Always have a single blank line before a comment or block of comments.
157 | * Don't allow preceding "code" - identified by a semicolon ;)
158 | */
159 | if (isset($tokens[$previous]['line']) && $tokens[$previous]['line'] === $tokens[$stackPtr]['line'] - 1
160 | && $tokens[($stackPtr - 1)]['content'] !== '}'
161 | )
162 | {
163 | $error = 'Please consider a blank line preceding your comment.';
164 | $fix = $phpcsFile->addFixableError($error, $stackPtr, 'BlankBefore');
165 |
166 | if ($fix === true)
167 | {
168 | $phpcsFile->fixer->addContent(($previous + 1), $phpcsFile->eolChar);
169 | }
170 | }
171 |
172 | /*
173 | * Comment blocks that introduce large sections of code and are more than 2 lines long
174 | * should use /* * / and should use * on each line with the same space/tab rules as doc
175 | * blocks.
176 | * If you need a large introduction consider whether this block should be separated into a
177 | * method to reduce complexity and therefore providing a full docblock.
178 | */
179 | $next = $phpcsFile->findNext(T_COMMENT, $stackPtr + 1);
180 |
181 | if ($singleLine === true && isset($tokens[$next]['line']) && $tokens[$next]['line'] === $tokens[$stackPtr]['line'] + 1
182 | && $tokens[($stackPtr - 1)]['content'] !== '}'
183 | )
184 | {
185 | // The following line contains also a comment.
186 | $nextNext = $phpcsFile->findNext(T_COMMENT, $next + 1);
187 |
188 | if ($tokens[$nextNext]['line'] === $tokens[$next]['line'] + 1)
189 | {
190 | // Found 3 lines of // comments - too much.
191 | $error = 'Use the /* */ style for comments that span over multiple lines.';
192 | $phpcsFile->addError($error, $stackPtr, 'MultiLine');
193 | }
194 | }
195 | }
196 | }
197 |
--------------------------------------------------------------------------------
/Joomla/Sniffs/ControlStructures/ControlSignatureSniff.php:
--------------------------------------------------------------------------------
1 |
16 | * @copyright 2006-2014 Squiz Pty Ltd (ABN 77 084 670 600)
17 | * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
18 | * @link http://pear.php.net/package/PHP_CodeSniffer
19 | *
20 | * @since 1.0
21 | */
22 | class Joomla_Sniffs_ControlStructures_ControlSignatureSniff implements PHP_CodeSniffer_Sniff
23 | {
24 | /**
25 | * The number of spaces code should be indented.
26 | *
27 | * @var integer
28 | */
29 | public $indent = 1;
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 int[]
45 | */
46 | public function register()
47 | {
48 | return array(
49 | T_TRY,
50 | T_CATCH,
51 | T_FINALLY,
52 | T_DO,
53 | T_WHILE,
54 | T_FOR,
55 | T_FOREACH,
56 | T_IF,
57 | T_ELSE,
58 | T_ELSEIF,
59 | T_SWITCH,
60 | );
61 | }
62 |
63 | /**
64 | * Processes this test, when one of its tokens is encountered.
65 | *
66 | * @param PHP_CodeSniffer_File $phpcsFile The file being scanned.
67 | * @param int $stackPtr The position of the current token in the stack passed in $tokens.
68 | *
69 | * @return void
70 | */
71 | public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr)
72 | {
73 | $tokens = $phpcsFile->getTokens();
74 |
75 | if (isset($tokens[($stackPtr + 1)]) === false)
76 | {
77 | return;
78 | }
79 |
80 | // Single space after the keyword.
81 | $found = 1;
82 |
83 | if ($tokens[($stackPtr + 1)]['code'] !== T_WHITESPACE)
84 | {
85 | $found = 0;
86 | }
87 | elseif ($tokens[($stackPtr + 1)]['content'] !== ' ')
88 | {
89 | if (strpos($tokens[($stackPtr + 1)]['content'], $phpcsFile->eolChar) !== false)
90 | {
91 | $found = 'newline';
92 | }
93 | else
94 | {
95 | $found = strlen($tokens[($stackPtr + 1)]['content']);
96 | }
97 | }
98 |
99 | if ($found !== 1
100 | && $tokens[($stackPtr)]['code'] !== T_ELSE
101 | && $tokens[($stackPtr)]['code'] !== T_TRY
102 | && $tokens[($stackPtr)]['code'] !== T_DO
103 | && $tokens[($stackPtr)]['code'] !== T_FINALLY
104 | )
105 | {
106 | $error = 'Expected 1 space after %s keyword; %s found';
107 | $data = array(
108 | strtoupper($tokens[$stackPtr]['content']),
109 | $found,
110 | );
111 | $fix = $phpcsFile->addFixableError($error, $stackPtr, 'SpaceAfterKeyword', $data);
112 |
113 | if ($fix === true)
114 | {
115 | if ($found === 0)
116 | {
117 | $phpcsFile->fixer->addContent($stackPtr, ' ');
118 | }
119 | else
120 | {
121 | $phpcsFile->fixer->replaceToken(($stackPtr + 1), ' ');
122 | }
123 | }
124 | }
125 |
126 | if ($tokens[$stackPtr]['code'] === T_WHILE && !isset($tokens[$stackPtr]['scope_opener']) === true)
127 | {
128 | // Zero spaces after parenthesis closer.
129 | $closer = $tokens[$stackPtr]['parenthesis_closer'];
130 | $found = 0;
131 |
132 | if ($tokens[($closer + 1)]['code'] === T_WHITESPACE)
133 | {
134 | if (strpos($tokens[($closer + 1)]['content'], $phpcsFile->eolChar) !== false)
135 | {
136 | $found = 'newline';
137 | }
138 | else
139 | {
140 | $found = strlen($tokens[($closer + 1)]['content']);
141 | }
142 | }
143 |
144 | if ($found !== 0)
145 | {
146 | $error = 'Expected 0 spaces before semicolon; %s found';
147 | $data = array($found);
148 | $fix = $phpcsFile->addFixableError($error, $closer, 'SpaceBeforeSemicolon', $data);
149 |
150 | if ($fix === true)
151 | {
152 | $phpcsFile->fixer->replaceToken(($closer + 1), '');
153 | }
154 | }
155 | }//end if
156 |
157 | // Only want to check multi-keyword structures from here on.
158 | if ($tokens[$stackPtr]['code'] === T_DO)
159 | {
160 | if (isset($tokens[$stackPtr]['scope_closer']) === false)
161 | {
162 | return;
163 | }
164 |
165 | $closer = $tokens[$stackPtr]['scope_closer'];
166 | }
167 | elseif ($tokens[$stackPtr]['code'] === T_ELSE
168 | || $tokens[$stackPtr]['code'] === T_ELSEIF
169 | || $tokens[$stackPtr]['code'] === T_CATCH
170 | )
171 | {
172 | $closer = $phpcsFile->findPrevious(PHP_CodeSniffer_Tokens::$emptyTokens, ($stackPtr - 1), null, true);
173 |
174 | if ($closer === false || $tokens[$closer]['code'] !== T_CLOSE_CURLY_BRACKET)
175 | {
176 | return;
177 | }
178 | }
179 | else
180 | {
181 | return;
182 | }
183 |
184 | // Own line for do, else, elseif, catch and no white space after closing brace
185 | $found = 0;
186 |
187 | if ($tokens[($closer + 1)]['code'] === T_WHITESPACE
188 | && $tokens[($closer + 1)]['content'] !== $phpcsFile->eolChar
189 | )
190 | {
191 | $found = strlen($tokens[($closer + 1)]['content']);
192 | }
193 |
194 | if (0 !== $found)
195 | {
196 | $error = 'Expected 0 space after closing brace; %s found';
197 | $data = array($found);
198 | $fix = $phpcsFile->addFixableError($error, $closer, 'SpaceAfterCloseBrace', $data);
199 |
200 | if (true === $fix)
201 | {
202 | $phpcsFile->fixer->replaceToken(($closer + 1), '' . $phpcsFile->eolChar);
203 | }
204 | }
205 |
206 | if ($tokens[($closer + 1)]['content'] !== $phpcsFile->eolChar && 0 === $found)
207 | {
208 | $error = 'Definition of do,else,elseif,catch must be on their own line.';
209 | $fix = $phpcsFile->addFixableError($error, $closer, 'NewLineAfterCloseBrace');
210 | $blanks = substr($tokens[($closer - 1)]['content'], strpos($tokens[($closer - 1)]['content'], $phpcsFile->eolChar));
211 | $spaces = str_repeat("\t", strlen($blanks));
212 |
213 | if (true === $fix)
214 | {
215 | $phpcsFile->fixer->beginChangeset();
216 | $phpcsFile->fixer->addContent($closer, $phpcsFile->eolChar);
217 | $phpcsFile->fixer->addContentBefore(($closer + 1), $spaces);
218 | $phpcsFile->fixer->endChangeset();
219 | }
220 | }
221 | }
222 | }
223 |
--------------------------------------------------------------------------------
/Joomla/Sniffs/ControlStructures/ControlStructuresBracketsSniff.php:
--------------------------------------------------------------------------------
1 | getTokens();
61 | $errorData = array(strtolower($tokens[$stackPtr]['content']));
62 |
63 | if (isset($tokens[$stackPtr]['scope_opener']) === false)
64 | {
65 | if ($tokens[$stackPtr]['code'] !== T_WHILE)
66 | {
67 | $error = 'Possible parse error: %s missing opening or closing brace';
68 | $phpcsFile->addWarning($error, $stackPtr, 'MissingBrace', $errorData);
69 | }
70 |
71 | return;
72 | }
73 |
74 | $openBrace = $tokens[$stackPtr]['scope_opener'];
75 | $lastContent = $phpcsFile->findPrevious(T_WHITESPACE, ($openBrace - 1), $stackPtr, true);
76 | $controlStructureLine = $tokens[$lastContent]['line'];
77 | $braceLine = $tokens[$openBrace]['line'];
78 |
79 | if ($braceLine === $controlStructureLine)
80 | {
81 | $phpcsFile->recordMetric($stackPtr, 'Control Structure opening brace placement', 'same line');
82 | $error = 'Opening brace of a %s must be on the line after the definition';
83 | $fix = $phpcsFile->addFixableError($error, $openBrace, 'OpenBraceNewLine', $errorData);
84 |
85 | if ($fix === true)
86 | {
87 | $phpcsFile->fixer->beginChangeset();
88 |
89 | if ($tokens[($openBrace - 1)]['code'] === T_WHITESPACE)
90 | {
91 | $phpcsFile->fixer->replaceToken(($openBrace - 1), '');
92 | }
93 |
94 | $phpcsFile->fixer->addNewlineBefore($openBrace);
95 | $phpcsFile->fixer->endChangeset();
96 | }
97 |
98 | return;
99 | }
100 | else
101 | {
102 | $phpcsFile->recordMetric($stackPtr, 'Control Structure opening brace placement', 'new line');
103 |
104 | if ($braceLine > ($controlStructureLine + 1))
105 | {
106 | $error = 'Opening brace of a %s must be on the line following the %s declaration.; Found %s line(s).';
107 | $data = array(
108 | $tokens[$stackPtr]['content'],
109 | $tokens[$stackPtr]['content'],
110 | ($braceLine - $controlStructureLine - 1),
111 | );
112 | $fix = $phpcsFile->addFixableError($error, $openBrace, 'OpenBraceWrongLine', $data);
113 |
114 | if ($fix === true)
115 | {
116 | $phpcsFile->fixer->beginChangeset();
117 |
118 | for ($i = ($openBrace - 1); $i > $lastContent; $i--)
119 | {
120 | if ($tokens[$i]['line'] === ($tokens[$openBrace]['line'] + 1))
121 | {
122 | break;
123 | }
124 |
125 | $phpcsFile->fixer->replaceToken($i, '');
126 | }
127 |
128 | $phpcsFile->fixer->endChangeset();
129 | }
130 |
131 | return;
132 | }
133 | }
134 |
135 | if ($tokens[($openBrace + 1)]['content'] !== $phpcsFile->eolChar)
136 | {
137 | $error = 'Opening %s brace must be on a line by itself.';
138 | $fix = $phpcsFile->addFixableError($error, $openBrace, 'OpenBraceNotAlone', $errorData);
139 |
140 | if ($fix === true)
141 | {
142 | $phpcsFile->fixer->addNewline($openBrace);
143 | }
144 | }
145 |
146 | if ($tokens[($openBrace - 1)]['code'] === T_WHITESPACE)
147 | {
148 | $prevContent = $tokens[($openBrace - 1)]['content'];
149 |
150 | if ($prevContent === $phpcsFile->eolChar)
151 | {
152 | $spaces = 0;
153 | }
154 | else
155 | {
156 | $blankSpace = substr($prevContent, strpos($prevContent, $phpcsFile->eolChar));
157 | $spaces = 0;
158 |
159 | /**
160 | * A tab is only counted with strlen as 1 character but we want to count
161 | * the number of spaces so add 4 characters for a tab otherwise the strlen
162 | */
163 | for ($i = 0; $length = strlen($blankSpace), $i < $length; $i++)
164 | {
165 | if ($blankSpace[$i] === "\t")
166 | {
167 | $spaces += $this->indent;
168 | }
169 | else
170 | {
171 | $spaces += strlen($blankSpace[$i]);
172 | }
173 | }
174 | }
175 |
176 | $baseLevel = $tokens[$stackPtr]['level'];
177 |
178 | /**
179 | * Take into account any nested parenthesis that don't contribute to the level (often required for
180 | * closures and anonymous classes
181 | */
182 | if (array_key_exists('nested_parenthesis', $tokens[$stackPtr]) === true)
183 | {
184 | $nestedStructures = $tokens[$stackPtr]['nested_parenthesis'];
185 | $nestedCount = 0;
186 |
187 | foreach ($nestedStructures as $start => $end)
188 | {
189 | /**
190 | * Crude way of checking for a chained method which requires an extra indent. We navigate to the open
191 | * parenthesis of the nested structure. The element before that is the function name. Before that we
192 | * check for an operator (->) and a whitespace before it (which makes it a chained method on a new line)
193 | * TODO: Is there a better way to check for a chained method? This feels very dirty!
194 | */
195 | if ($tokens[$start - 2]['type'] === 'T_OBJECT_OPERATOR' && $tokens[$start - 3]['type'] === 'T_WHITESPACE')
196 | {
197 | /**
198 | * If we have an anonymous function/class on the same line as our chained method then we
199 | * balance out so only increase the count by 1. Else by 2.
200 | */
201 | if ($tokens[$start + 1]['type'] === 'T_CLOSURE' || $tokens[$start + 1]['type'] === 'T_ANON_CLASS')
202 | {
203 | $nestedCount++;
204 | }
205 | else
206 | {
207 | $nestedCount += 2;
208 | }
209 | }
210 | else
211 | {
212 | $nestedCount++;
213 | }
214 | }
215 |
216 | $baseLevel += $nestedCount;
217 | }
218 |
219 | $expected = $baseLevel * $this->indent;
220 |
221 | // We need to divide by 4 here since there is a space vs tab intent in the check vs token
222 | $expected /= $this->indent;
223 | $spaces /= $this->indent;
224 |
225 | if ($spaces !== $expected)
226 | {
227 | $error = 'Expected %s tabs before opening brace; %s found';
228 | $data = array(
229 | $expected,
230 | $spaces,
231 | );
232 | $fix = $phpcsFile->addFixableError($error, $openBrace, 'SpaceBeforeBrace', $data);
233 |
234 | if ($fix === true)
235 | {
236 | $indent = str_repeat("\t", $expected);
237 |
238 | if ($spaces === 0)
239 | {
240 | $phpcsFile->fixer->addContentBefore($openBrace, $indent);
241 | }
242 | else
243 | {
244 | $phpcsFile->fixer->replaceToken(($openBrace - 1), $indent);
245 | }
246 | }
247 | }
248 | }
249 |
250 | // A single newline after opening brace (i.e. brace in on a line by itself), remove extra newlines.
251 | if (isset($tokens[$stackPtr]['scope_opener']) === true)
252 | {
253 | $opener = $tokens[$stackPtr]['scope_opener'];
254 |
255 | for ($next = ($opener + 1); $next < $phpcsFile->numTokens; $next++)
256 | {
257 | $code = $tokens[$next]['code'];
258 |
259 | if ($code === T_WHITESPACE)
260 | {
261 | continue;
262 | }
263 |
264 | // Skip all empty tokens on the same line as the opener.
265 | if ($tokens[$next]['line'] === $tokens[$opener]['line']
266 | && (isset(PHP_CodeSniffer_Tokens::$emptyTokens[$code]) === true
267 | || $code === T_CLOSE_TAG)
268 | )
269 | {
270 | continue;
271 | }
272 |
273 | // We found the first bit of a code, or a comment on the following line.
274 | break;
275 | }
276 |
277 | $found = ($tokens[$next]['line'] - $tokens[$opener]['line']);
278 |
279 | if ($found > 1)
280 | {
281 | $error = 'Expected 1 newline after opening brace; %s found';
282 | $data = array($found);
283 | $fix = $phpcsFile->addFixableError($error, $opener, 'ExtraNewlineAfterOpenBrace', $data);
284 |
285 | if ($fix === true)
286 | {
287 | $phpcsFile->fixer->beginChangeset();
288 |
289 | for ($i = ($opener + 1); $i < $next; $i++)
290 | {
291 | if ($found > 0 && $tokens[$i]['line'] === $tokens[$next]['line'])
292 | {
293 | break;
294 | }
295 |
296 | $phpcsFile->fixer->replaceToken($i, '');
297 | }
298 |
299 | $phpcsFile->fixer->addContent($opener, $phpcsFile->eolChar);
300 | $phpcsFile->fixer->endChangeset();
301 | }
302 | }
303 | }
304 | }
305 | }
306 |
--------------------------------------------------------------------------------
/Joomla/Sniffs/ControlStructures/WhiteSpaceBeforeSniff.php:
--------------------------------------------------------------------------------
1 | getTokens();
90 |
91 | if (isset($tokens[$stackPtr]['scope_opener']) === false && $tokens[$stackPtr]['code'] !== T_RETURN)
92 | {
93 | return;
94 | }
95 |
96 | $prev = $phpcsFile->findPrevious(array(T_SEMICOLON, T_CLOSE_CURLY_BRACKET), ($stackPtr - 1), null, false);
97 |
98 | if ($tokens[$stackPtr]['line'] - 1 === $tokens[$prev]['line'])
99 | {
100 | $error = 'Please consider an empty line before the %s statement;';
101 | $data = array($tokens[$stackPtr]['content']);
102 | $fix = $phpcsFile->addFixableError($error, $stackPtr, 'SpaceBefore', $data);
103 |
104 | if ($fix === true)
105 | {
106 | $phpcsFile->fixer->addNewlineBefore($stackPtr);
107 | }
108 | }
109 | }
110 | }
111 |
--------------------------------------------------------------------------------
/Joomla/Sniffs/Functions/StatementNotFunctionSniff.php:
--------------------------------------------------------------------------------
1 | getTokens();
47 | $nextToken = $phpcsFile->findNext(PHP_CodeSniffer_Tokens::$emptyTokens, ($stackPtr + 1), null, true);
48 |
49 | if ($tokens[$nextToken]['code'] === T_OPEN_PARENTHESIS && $tokens[($stackPtr)]['code'] !== T_ECHO)
50 | {
51 | $error = '"%s" is a statement not a function; no parentheses are required';
52 | $data = array($tokens[$stackPtr]['content']);
53 | $fix = $phpcsFile->addFixableError($error, $stackPtr, 'BracketsNotRequired', $data);
54 |
55 | if ($fix === true)
56 | {
57 | $end = $phpcsFile->findEndOfStatement($nextToken);
58 | $ignore = PHP_CodeSniffer_Tokens::$emptyTokens;
59 | $ignore[] = T_SEMICOLON;
60 | $closer = $phpcsFile->findPrevious($ignore, ($end - 1), null, true);
61 |
62 | $phpcsFile->fixer->beginChangeset();
63 | $phpcsFile->fixer->replaceToken($nextToken, '');
64 |
65 | if ($tokens[($stackPtr + 1)]['code'] === T_WHITESPACE)
66 | {
67 | $phpcsFile->fixer->replaceToken(($stackPtr + 1), '');
68 | }
69 |
70 | if ($tokens[$closer]['code'] === T_CLOSE_PARENTHESIS)
71 | {
72 | $phpcsFile->fixer->replaceToken($closer, '');
73 | }
74 |
75 | $phpcsFile->fixer->addContent($stackPtr, ' ');
76 | $phpcsFile->fixer->endChangeset();
77 | }
78 | }
79 |
80 | if ($tokens[($stackPtr)]['code'] === T_ECHO
81 | && $tokens[$nextToken]['code'] === T_OPEN_PARENTHESIS
82 | && $tokens[($stackPtr + 1)]['code'] !== T_WHITESPACE
83 | )
84 | {
85 | $error = 'There must be one space between the "%s" statement and the opening parenthesis';
86 | $data = array($tokens[$stackPtr]['content']);
87 | $fix = $phpcsFile->addFixableError($error, $stackPtr, 'SpacingAfterEcho', $data);
88 |
89 | if ($fix === true)
90 | {
91 | $this->requiredSpacesBeforeOpen = 1;
92 | $padding = str_repeat(' ', $this->requiredSpacesBeforeOpen);
93 | $phpcsFile->fixer->addContent($stackPtr, $padding);
94 | }
95 | }
96 | }
97 | }
98 |
--------------------------------------------------------------------------------
/Joomla/Sniffs/NamingConventions/ValidFunctionNameSniff.php:
--------------------------------------------------------------------------------
1 | true,
29 | 'destruct' => true,
30 | 'call' => true,
31 | 'callstatic' => true,
32 | 'get' => true,
33 | 'set' => true,
34 | 'isset' => true,
35 | 'unset' => true,
36 | 'sleep' => true,
37 | 'wakeup' => true,
38 | 'serialize' => true,
39 | 'unserialize' => true,
40 | 'tostring' => true,
41 | 'invoke' => true,
42 | 'set_state' => true,
43 | 'clone' => true,
44 | 'debuginfo' => true,
45 | );
46 |
47 | /**
48 | * Processes the tokens within the scope.
49 | *
50 | * Extends PEAR.NamingConventions.ValidFunctionName.processTokenWithinScope to remove the requirement for leading underscores on
51 | * private method names.
52 | *
53 | * @param PHP_CodeSniffer_File $phpcsFile The file being processed.
54 | * @param integer $stackPtr The position where this token was found.
55 | * @param integer $currScope The position of the current scope.
56 | *
57 | * @return void
58 | */
59 | protected function processTokenWithinScope(PHP_CodeSniffer_File $phpcsFile, $stackPtr, $currScope)
60 | {
61 | $methodName = $phpcsFile->getDeclarationName($stackPtr);
62 |
63 | if ($methodName === null)
64 | {
65 | // Ignore closures.
66 | return;
67 | }
68 |
69 | $className = $phpcsFile->getDeclarationName($currScope);
70 | $errorData = array($className . '::' . $methodName);
71 |
72 | // Is this a magic method. i.e., is prefixed with "__" ?
73 | if (preg_match('|^__[^_]|', $methodName) !== 0)
74 | {
75 | $magicPart = strtolower(substr($methodName, 2));
76 |
77 | if (isset($this->magicMethods[$magicPart]) === false)
78 | {
79 | $error = 'Method name "%s" is invalid; only PHP magic methods should be prefixed with a double underscore';
80 | $phpcsFile->addError($error, $stackPtr, 'MethodDoubleUnderscore', $errorData);
81 | }
82 |
83 | return;
84 | }
85 |
86 | // PHP4 constructors are allowed to break our rules.
87 | if ($methodName === $className)
88 | {
89 | return;
90 | }
91 |
92 | // PHP4 destructors are allowed to break our rules.
93 | if ($methodName === '_' . $className)
94 | {
95 | return;
96 | }
97 |
98 | $methodProps = $phpcsFile->getMethodProperties($stackPtr);
99 | $scope = $methodProps['scope'];
100 | $scopeSpecified = $methodProps['scope_specified'];
101 |
102 | if ($methodProps['scope'] === 'private')
103 | {
104 | $isPublic = false;
105 | }
106 | else
107 | {
108 | $isPublic = true;
109 | }
110 |
111 | // Joomla change: Methods must not have an underscore on the front.
112 | if ($scopeSpecified === true && $methodName[0] === '_')
113 | {
114 | $error = '%s method name "%s" must not be prefixed with an underscore';
115 | $data = array(
116 | ucfirst($scope),
117 | $errorData[0],
118 | );
119 |
120 | $phpcsFile->addError($error, $stackPtr, 'MethodUnderscore', $data);
121 | $phpcsFile->recordMetric($stackPtr, 'Method prefixed with underscore', 'yes');
122 |
123 | return;
124 | }
125 |
126 | /*
127 | * If the scope was specified on the method, then the method must be camel caps
128 | * and an underscore should be checked for. If it wasn't specified, treat it like a public method
129 | * and remove the underscore prefix if there is one because we cant determine if it is private or public.
130 | */
131 | $testMethodName = $methodName;
132 |
133 | if ($scopeSpecified === false && $methodName[0] === '_')
134 | {
135 | $testMethodName = substr($methodName, 1);
136 | }
137 |
138 | if (PHP_CodeSniffer::isCamelCaps($testMethodName, false, true, false) === false)
139 | {
140 | if ($scopeSpecified === true)
141 | {
142 | $error = '%s method name "%s" is not in camel caps format';
143 | $data = array(
144 | ucfirst($scope),
145 | $errorData[0],
146 | );
147 | $phpcsFile->addError($error, $stackPtr, 'ScopeNotCamelCaps', $data);
148 | }
149 | else
150 | {
151 | $error = 'Method name "%s" is not in camel caps format';
152 | $phpcsFile->addError($error, $stackPtr, 'NotCamelCaps', $errorData);
153 | }
154 |
155 | return;
156 | }
157 | }
158 | }
159 |
--------------------------------------------------------------------------------
/Joomla/Sniffs/NamingConventions/ValidVariableNameSniff.php:
--------------------------------------------------------------------------------
1 | getTokens();
36 |
37 | $varName = ltrim($tokens[$stackPtr]['content'], '$');
38 | $memberProps = $phpcsFile->getMemberProperties($stackPtr);
39 |
40 | if (empty($memberProps) === true)
41 | {
42 | // Couldn't get any info about this variable, which generally means it is invalid or possibly has a parse
43 | // error. Any errors will be reported by the core, so we can ignore it.
44 | return;
45 | }
46 |
47 | $errorData = array($varName);
48 |
49 | if (substr($varName, 0, 1) === '_')
50 | {
51 | $error = '%s member variable "%s" must not contain a leading underscore';
52 | $data = array(
53 | ucfirst($memberProps['scope']),
54 | $errorData[0]
55 | );
56 | $phpcsFile->addError($error, $stackPtr, 'ClassVarHasUnderscore', $data);
57 |
58 | return;
59 | }
60 |
61 | if (PHP_CodeSniffer::isCamelCaps($varName, false, true, false) === false)
62 | {
63 | $error = 'Member variable "%s" is not in valid camel caps format';
64 | $phpcsFile->addError($error, $stackPtr, 'MemberNotCamelCaps', $errorData);
65 | }
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/Joomla/Sniffs/Operators/ValidLogicalOperatorsSniff.php:
--------------------------------------------------------------------------------
1 | getTokens();
44 | $operators = array(
45 | 'and' => '&&',
46 | 'or' => '||',
47 | );
48 | $operator = strtolower($tokens[$stackPtr]['content']);
49 |
50 | if (false === isset($operators[$operator]))
51 | {
52 | // We have correct logical operators in use so return
53 | return;
54 | }
55 |
56 | $nextToken = $phpcsFile->findNext(T_WHITESPACE, ($stackPtr + 1), null, true);
57 |
58 | if ($tokens[$nextToken]['code'] === T_EXIT)
59 | {
60 | // This enforces an exception for things like `or die;` and `or exit;`
61 | return;
62 | }
63 |
64 | // Special Joomla! cases.
65 | if ($tokens[$nextToken]['content'] === 'jexit'
66 | || $tokens[$nextToken]['content'] === 'JSession'
67 | || $tokens[$nextToken]['content'] === 'define'
68 | || $tokens[($nextToken + 2)]['content'] === 'sendResponse'
69 | || $tokens[($nextToken + 2)]['content'] === 'sendJsonResponse'
70 | )
71 | {
72 | // Exceptions for things like `or jexit()`, `or JSession`, `or define`, `or sendResponse`, `or sendJsonResponse`
73 | return;
74 | }
75 |
76 | $error = 'Logical operator "%s" not allowed; use "%s" instead';
77 | $data = array(
78 | $operator,
79 | $operators[$operator],
80 | );
81 | $fix = $phpcsFile->addFixableError($error, $stackPtr, 'NotAllowed', $data);
82 |
83 | if (true === $fix)
84 | {
85 | $phpcsFile->fixer->replaceToken($stackPtr, $operators[$operator]);
86 | }
87 | }
88 | }
89 |
--------------------------------------------------------------------------------
/Joomla/Sniffs/WhiteSpace/MemberVarSpacingSniff.php:
--------------------------------------------------------------------------------
1 | getTokens();
33 | $ignore = PHP_CodeSniffer_Tokens::$methodPrefixes;
34 | $ignore[] = T_VAR;
35 | $ignore[] = T_WHITESPACE;
36 | $start = $stackPtr;
37 | $prev = $phpcsFile->findPrevious($ignore, ($stackPtr - 1), null, true);
38 |
39 | if (isset(PHP_CodeSniffer_Tokens::$commentTokens[$tokens[$prev]['code']]) === true)
40 | {
41 | // Assume the comment belongs to the member var if it is on a line by itself.
42 | $prevContent = $phpcsFile->findPrevious(PHP_CodeSniffer_Tokens::$emptyTokens, ($prev - 1), null, true);
43 |
44 | if ($tokens[$prevContent]['line'] !== $tokens[$prev]['line'])
45 | {
46 | // Check the spacing, but then skip it.
47 | $foundLines = ($tokens[$stackPtr]['line'] - $tokens[$prev]['line'] - 1);
48 |
49 | if ($foundLines > 0)
50 | {
51 | $error = 'Expected 0 blank lines after member var comment; %s found';
52 | $data = array($foundLines);
53 | $fix = $phpcsFile->addFixableError($error, $prev, 'AfterComment', $data);
54 |
55 | if ($fix === true)
56 | {
57 | $phpcsFile->fixer->beginChangeset();
58 |
59 | // Inline comments have the newline included in the content but docblock do not.
60 | if ($tokens[$prev]['code'] === T_COMMENT)
61 | {
62 | $phpcsFile->fixer->replaceToken($prev, rtrim($tokens[$prev]['content']));
63 | }
64 |
65 | for ($i = ($prev + 1); $i <= $stackPtr; $i++)
66 | {
67 | if ($tokens[$i]['line'] === $tokens[$stackPtr]['line'])
68 | {
69 | break;
70 | }
71 |
72 | $phpcsFile->fixer->replaceToken($i, '');
73 | }
74 |
75 | $phpcsFile->fixer->addNewline($prev);
76 | $phpcsFile->fixer->endChangeset();
77 | }
78 | }
79 |
80 | $start = $prev;
81 | }
82 | }
83 |
84 | // There needs to be 1 blank line before the var, not counting comments.
85 | if ($start === $stackPtr)
86 | {
87 | // No comment found.
88 | $first = $phpcsFile->findFirstOnLine(PHP_CodeSniffer_Tokens::$emptyTokens, $start, true);
89 |
90 | if ($first === false)
91 | {
92 | $first = $start;
93 | }
94 | }
95 | elseif ($tokens[$start]['code'] === T_DOC_COMMENT_CLOSE_TAG)
96 | {
97 | $first = $tokens[$start]['comment_opener'];
98 | }
99 | else
100 | {
101 | $first = $phpcsFile->findPrevious(PHP_CodeSniffer_Tokens::$emptyTokens, ($start - 1), null, true);
102 | $first = $phpcsFile->findNext(PHP_CodeSniffer_Tokens::$commentTokens, ($first + 1));
103 | }
104 |
105 | $prev = $phpcsFile->findPrevious(PHP_CodeSniffer_Tokens::$emptyTokens, ($first - 1), null, true);
106 | $foundLines = ($tokens[$first]['line'] - $tokens[$prev]['line'] - 1);
107 |
108 | // No blank lines after class opener.
109 | if ($foundLines > 0 && $tokens[$prev]['code'] === T_OPEN_CURLY_BRACKET)
110 | {
111 | $error = 'Expected 0 blank lines before first member var; %s found';
112 | $data = array($foundLines);
113 | $fix = $phpcsFile->addFixableError($error, $stackPtr, 'FirstMember', $data);
114 |
115 | if ($fix === true)
116 | {
117 | $phpcsFile->fixer->beginChangeset();
118 |
119 | for ($i = ($prev + 1); $i < $first; $i++)
120 | {
121 | if ($tokens[$i]['line'] === $tokens[$prev]['line'])
122 | {
123 | continue;
124 | }
125 |
126 | if ($tokens[$i]['line'] === $tokens[$first]['line'])
127 | {
128 | break;
129 | }
130 |
131 | $phpcsFile->fixer->replaceToken($i, '');
132 | }
133 |
134 | $phpcsFile->fixer->endChangeset();
135 | }
136 | }
137 |
138 | if ($foundLines === 1
139 | || $tokens[$prev]['code'] === T_OPEN_CURLY_BRACKET
140 | )
141 | {
142 | return;
143 | }
144 |
145 | $error = 'Expected 1 blank line before member var; %s found';
146 | $data = array($foundLines);
147 | $fix = $phpcsFile->addFixableError($error, $stackPtr, 'Incorrect', $data);
148 |
149 | if ($fix === true)
150 | {
151 | $phpcsFile->fixer->beginChangeset();
152 |
153 | for ($i = ($prev + 1); $i < $first; $i++)
154 | {
155 | if ($tokens[$i]['line'] === $tokens[$prev]['line'])
156 | {
157 | continue;
158 | }
159 |
160 | if ($tokens[$i]['line'] === $tokens[$first]['line'])
161 | {
162 | $phpcsFile->fixer->addNewlineBefore($i);
163 | break;
164 | }
165 |
166 | $phpcsFile->fixer->replaceToken($i, '');
167 | }
168 |
169 | $phpcsFile->fixer->endChangeset();
170 | }
171 | }
172 | }
173 |
--------------------------------------------------------------------------------
/Joomla/ruleset.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | The Joomla 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 | 0
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 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 | Multi-line IF statement not indented correctly; expected %s spaces but found %s. Note: the autofixer will convert spaces to tabs
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 | Multi-line function call not indented correctly; expected %s spaces but found %s. Note: the autofixer will convert spaces to tabs
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 | Multi-line function declaration not indented correctly; expected %s spaces but found %s. Note: the autofixer will convert spaces to tabs
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 | Object operator not indented correctly; expected %s spaces but found %s. Note: the autofixer will convert spaces to tabs
112 |
113 |
114 |
115 |
116 |
117 | error
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 | Do not use global variables. Use static class properties or constants instead of globals.
146 |
147 |
148 |
149 |
150 | No scope modifier specified for function "%s
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 | Closing brace indented incorrectly; expected %s spaces, found %s. Note: the autofixer will convert spaces to tabs
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | GNU GENERAL PUBLIC LICENSE
2 | Version 2, June 1991
3 |
4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
6 | Everyone is permitted to copy and distribute verbatim copies
7 | of this license document, but changing it is not allowed.
8 |
9 | Preamble
10 |
11 | The licenses for most software are designed to take away your
12 | freedom to share and change it. By contrast, the GNU General Public
13 | License is intended to guarantee your freedom to share and change free
14 | software--to make sure the software is free for all its users. This
15 | General Public License applies to most of the Free Software
16 | Foundation's software and to any other program whose authors commit to
17 | using it. (Some other Free Software Foundation software is covered by
18 | the GNU Lesser General Public License instead.) You can apply it to
19 | your programs, too.
20 |
21 | When we speak of free software, we are referring to freedom, not
22 | price. Our General Public Licenses are designed to make sure that you
23 | have the freedom to distribute copies of free software (and charge for
24 | this service if you wish), that you receive source code or can get it
25 | if you want it, that you can change the software or use pieces of it
26 | in new free programs; and that you know you can do these things.
27 |
28 | To protect your rights, we need to make restrictions that forbid
29 | anyone to deny you these rights or to ask you to surrender the rights.
30 | These restrictions translate to certain responsibilities for you if you
31 | distribute copies of the software, or if you modify it.
32 |
33 | For example, if you distribute copies of such a program, whether
34 | gratis or for a fee, you must give the recipients all the rights that
35 | you have. You must make sure that they, too, receive or can get the
36 | source code. And you must show them these terms so they know their
37 | rights.
38 |
39 | We protect your rights with two steps: (1) copyright the software, and
40 | (2) offer you this license which gives you legal permission to copy,
41 | distribute and/or modify the software.
42 |
43 | Also, for each author's protection and ours, we want to make certain
44 | that everyone understands that there is no warranty for this free
45 | software. If the software is modified by someone else and passed on, we
46 | want its recipients to know that what they have is not the original, so
47 | that any problems introduced by others will not reflect on the original
48 | authors' reputations.
49 |
50 | Finally, any free program is threatened constantly by software
51 | patents. We wish to avoid the danger that redistributors of a free
52 | program will individually obtain patent licenses, in effect making the
53 | program proprietary. To prevent this, we have made it clear that any
54 | patent must be licensed for everyone's free use or not licensed at all.
55 |
56 | The precise terms and conditions for copying, distribution and
57 | modification follow.
58 |
59 | GNU GENERAL PUBLIC LICENSE
60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
61 |
62 | 0. This License applies to any program or other work which contains
63 | a notice placed by the copyright holder saying it may be distributed
64 | under the terms of this General Public License. The "Program", below,
65 | refers to any such program or work, and a "work based on the Program"
66 | means either the Program or any derivative work under copyright law:
67 | that is to say, a work containing the Program or a portion of it,
68 | either verbatim or with modifications and/or translated into another
69 | language. (Hereinafter, translation is included without limitation in
70 | the term "modification".) Each licensee is addressed as "you".
71 |
72 | Activities other than copying, distribution and modification are not
73 | covered by this License; they are outside its scope. The act of
74 | running the Program is not restricted, and the output from the Program
75 | is covered only if its contents constitute a work based on the
76 | Program (independent of having been made by running the Program).
77 | Whether that is true depends on what the Program does.
78 |
79 | 1. You may copy and distribute verbatim copies of the Program's
80 | source code as you receive it, in any medium, provided that you
81 | conspicuously and appropriately publish on each copy an appropriate
82 | copyright notice and disclaimer of warranty; keep intact all the
83 | notices that refer to this License and to the absence of any warranty;
84 | and give any other recipients of the Program a copy of this License
85 | along with the Program.
86 |
87 | You may charge a fee for the physical act of transferring a copy, and
88 | you may at your option offer warranty protection in exchange for a fee.
89 |
90 | 2. You may modify your copy or copies of the Program or any portion
91 | of it, thus forming a work based on the Program, and copy and
92 | distribute such modifications or work under the terms of Section 1
93 | above, provided that you also meet all of these conditions:
94 |
95 | a) You must cause the modified files to carry prominent notices
96 | stating that you changed the files and the date of any change.
97 |
98 | b) You must cause any work that you distribute or publish, that in
99 | whole or in part contains or is derived from the Program or any
100 | part thereof, to be licensed as a whole at no charge to all third
101 | parties under the terms of this License.
102 |
103 | c) If the modified program normally reads commands interactively
104 | when run, you must cause it, when started running for such
105 | interactive use in the most ordinary way, to print or display an
106 | announcement including an appropriate copyright notice and a
107 | notice that there is no warranty (or else, saying that you provide
108 | a warranty) and that users may redistribute the program under
109 | these conditions, and telling the user how to view a copy of this
110 | License. (Exception: if the Program itself is interactive but
111 | does not normally print such an announcement, your work based on
112 | the Program is not required to print an announcement.)
113 |
114 | These requirements apply to the modified work as a whole. If
115 | identifiable sections of that work are not derived from the Program,
116 | and can be reasonably considered independent and separate works in
117 | themselves, then this License, and its terms, do not apply to those
118 | sections when you distribute them as separate works. But when you
119 | distribute the same sections as part of a whole which is a work based
120 | on the Program, the distribution of the whole must be on the terms of
121 | this License, whose permissions for other licensees extend to the
122 | entire whole, and thus to each and every part regardless of who wrote it.
123 |
124 | Thus, it is not the intent of this section to claim rights or contest
125 | your rights to work written entirely by you; rather, the intent is to
126 | exercise the right to control the distribution of derivative or
127 | collective works based on the Program.
128 |
129 | In addition, mere aggregation of another work not based on the Program
130 | with the Program (or with a work based on the Program) on a volume of
131 | a storage or distribution medium does not bring the other work under
132 | the scope of this License.
133 |
134 | 3. You may copy and distribute the Program (or a work based on it,
135 | under Section 2) in object code or executable form under the terms of
136 | Sections 1 and 2 above provided that you also do one of the following:
137 |
138 | a) Accompany it with the complete corresponding machine-readable
139 | source code, which must be distributed under the terms of Sections
140 | 1 and 2 above on a medium customarily used for software interchange; or,
141 |
142 | b) Accompany it with a written offer, valid for at least three
143 | years, to give any third party, for a charge no more than your
144 | cost of physically performing source distribution, a complete
145 | machine-readable copy of the corresponding source code, to be
146 | distributed under the terms of Sections 1 and 2 above on a medium
147 | customarily used for software interchange; or,
148 |
149 | c) Accompany it with the information you received as to the offer
150 | to distribute corresponding source code. (This alternative is
151 | allowed only for noncommercial distribution and only if you
152 | received the program in object code or executable form with such
153 | an offer, in accord with Subsection b above.)
154 |
155 | The source code for a work means the preferred form of the work for
156 | making modifications to it. For an executable work, complete source
157 | code means all the source code for all modules it contains, plus any
158 | associated interface definition files, plus the scripts used to
159 | control compilation and installation of the executable. However, as a
160 | special exception, the source code distributed need not include
161 | anything that is normally distributed (in either source or binary
162 | form) with the major components (compiler, kernel, and so on) of the
163 | operating system on which the executable runs, unless that component
164 | itself accompanies the executable.
165 |
166 | If distribution of executable or object code is made by offering
167 | access to copy from a designated place, then offering equivalent
168 | access to copy the source code from the same place counts as
169 | distribution of the source code, even though third parties are not
170 | compelled to copy the source along with the object code.
171 |
172 | 4. You may not copy, modify, sublicense, or distribute the Program
173 | except as expressly provided under this License. Any attempt
174 | otherwise to copy, modify, sublicense or distribute the Program is
175 | void, and will automatically terminate your rights under this License.
176 | However, parties who have received copies, or rights, from you under
177 | this License will not have their licenses terminated so long as such
178 | parties remain in full compliance.
179 |
180 | 5. You are not required to accept this License, since you have not
181 | signed it. However, nothing else grants you permission to modify or
182 | distribute the Program or its derivative works. These actions are
183 | prohibited by law if you do not accept this License. Therefore, by
184 | modifying or distributing the Program (or any work based on the
185 | Program), you indicate your acceptance of this License to do so, and
186 | all its terms and conditions for copying, distributing or modifying
187 | the Program or works based on it.
188 |
189 | 6. Each time you redistribute the Program (or any work based on the
190 | Program), the recipient automatically receives a license from the
191 | original licensor to copy, distribute or modify the Program subject to
192 | these terms and conditions. You may not impose any further
193 | restrictions on the recipients' exercise of the rights granted herein.
194 | You are not responsible for enforcing compliance by third parties to
195 | this License.
196 |
197 | 7. If, as a consequence of a court judgment or allegation of patent
198 | infringement or for any other reason (not limited to patent issues),
199 | conditions are imposed on you (whether by court order, agreement or
200 | otherwise) that contradict the conditions of this License, they do not
201 | excuse you from the conditions of this License. If you cannot
202 | distribute so as to satisfy simultaneously your obligations under this
203 | License and any other pertinent obligations, then as a consequence you
204 | may not distribute the Program at all. For example, if a patent
205 | license would not permit royalty-free redistribution of the Program by
206 | all those who receive copies directly or indirectly through you, then
207 | the only way you could satisfy both it and this License would be to
208 | refrain entirely from distribution of the Program.
209 |
210 | If any portion of this section is held invalid or unenforceable under
211 | any particular circumstance, the balance of the section is intended to
212 | apply and the section as a whole is intended to apply in other
213 | circumstances.
214 |
215 | It is not the purpose of this section to induce you to infringe any
216 | patents or other property right claims or to contest validity of any
217 | such claims; this section has the sole purpose of protecting the
218 | integrity of the free software distribution system, which is
219 | implemented by public license practices. Many people have made
220 | generous contributions to the wide range of software distributed
221 | through that system in reliance on consistent application of that
222 | system; it is up to the author/donor to decide if he or she is willing
223 | to distribute software through any other system and a licensee cannot
224 | impose that choice.
225 |
226 | This section is intended to make thoroughly clear what is believed to
227 | be a consequence of the rest of this License.
228 |
229 | 8. If the distribution and/or use of the Program is restricted in
230 | certain countries either by patents or by copyrighted interfaces, the
231 | original copyright holder who places the Program under this License
232 | may add an explicit geographical distribution limitation excluding
233 | those countries, so that distribution is permitted only in or among
234 | countries not thus excluded. In such case, this License incorporates
235 | the limitation as if written in the body of this License.
236 |
237 | 9. The Free Software Foundation may publish revised and/or new versions
238 | of the General Public License from time to time. Such new versions will
239 | be similar in spirit to the present version, but may differ in detail to
240 | address new problems or concerns.
241 |
242 | Each version is given a distinguishing version number. If the Program
243 | specifies a version number of this License which applies to it and "any
244 | later version", you have the option of following the terms and conditions
245 | either of that version or of any later version published by the Free
246 | Software Foundation. If the Program does not specify a version number of
247 | this License, you may choose any version ever published by the Free Software
248 | Foundation.
249 |
250 | 10. If you wish to incorporate parts of the Program into other free
251 | programs whose distribution conditions are different, write to the author
252 | to ask for permission. For software which is copyrighted by the Free
253 | Software Foundation, write to the Free Software Foundation; we sometimes
254 | make exceptions for this. Our decision will be guided by the two goals
255 | of preserving the free status of all derivatives of our free software and
256 | of promoting the sharing and reuse of software generally.
257 |
258 | NO WARRANTY
259 |
260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
268 | REPAIR OR CORRECTION.
269 |
270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
278 | POSSIBILITY OF SUCH DAMAGES.
279 |
280 | END OF TERMS AND CONDITIONS
281 |
282 | How to Apply These Terms to Your New Programs
283 |
284 | If you develop a new program, and you want it to be of the greatest
285 | possible use to the public, the best way to achieve this is to make it
286 | free software which everyone can redistribute and change under these terms.
287 |
288 | To do so, attach the following notices to the program. It is safest
289 | to attach them to the start of each source file to most effectively
290 | convey the exclusion of warranty; and each file should have at least
291 | the "copyright" line and a pointer to where the full notice is found.
292 |
293 |
294 | Copyright (C)
295 |
296 | This program is free software; you can redistribute it and/or modify
297 | it under the terms of the GNU General Public License as published by
298 | the Free Software Foundation; either version 2 of the License, or
299 | (at your option) any later version.
300 |
301 | This program is distributed in the hope that it will be useful,
302 | but WITHOUT ANY WARRANTY; without even the implied warranty of
303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
304 | GNU General Public License for more details.
305 |
306 | You should have received a copy of the GNU General Public License along
307 | with this program; if not, write to the Free Software Foundation, Inc.,
308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
309 |
310 | Also add information on how to contact you by electronic and paper mail.
311 |
312 | If the program is interactive, make it output a short notice like this
313 | when it starts in an interactive mode:
314 |
315 | Gnomovision version 69, Copyright (C) year name of author
316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
317 | This is free software, and you are welcome to redistribute it
318 | under certain conditions; type `show c' for details.
319 |
320 | The hypothetical commands `show w' and `show c' should show the appropriate
321 | parts of the General Public License. Of course, the commands you use may
322 | be called something other than `show w' and `show c'; they could even be
323 | mouse-clicks or menu items--whatever suits your program.
324 |
325 | You should also get your employer (if you work as a programmer) or your
326 | school, if any, to sign a "copyright disclaimer" for the program, if
327 | necessary. Here is a sample; alter the names:
328 |
329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program
330 | `Gnomovision' (which makes passes at compilers) written by James Hacker.
331 |
332 | , 1 April 1989
333 | Ty Coon, President of Vice
334 |
335 | This General Public License does not permit incorporating your program into
336 | proprietary programs. If your program is a subroutine library, you may
337 | consider it more useful to permit linking proprietary applications with the
338 | library. If this is what you want to do, use the GNU Lesser General
339 | Public License instead of this License.
340 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | **Since Joomla version 4.2, Joomla uses the PSR-12 coding standard.**
2 |
3 | **We will update this soon to reflect this change**
4 |
5 | **All not php coding standards are still valid**
6 |
7 | ---
8 |
9 | Joomla Coding Standards [](https://travis-ci.org/joomla/coding-standards)
10 | =======================
11 |
12 | [](https://packagist.org/packages/joomla/coding-standards) [](https://packagist.org/packages/joomla/coding-standards) [](https://packagist.org/packages/joomla/coding-standards)
13 |
14 | This repository includes the [Joomla](https://developer.joomla.org) coding standard definition for [PHP Codesniffer](https://github.com/squizlabs/PHP_CodeSniffer) along with a few other helpful resources. The PHP_CodeSniffer standard will never be 100% accurate, but should be viewed as a strong set of guidelines while writing software for Joomla.
15 |
16 | See Joomla coding standards documentation at [https://developer.joomla.org/coding-standards.html](https://developer.joomla.org/coding-standards.html)
17 |
18 | If you want to contribute and improve this documentation, you can find the source files in the manual section of the master branch [https://github.com/joomla/coding-standards/tree/master/manual](https://github.com/joomla/coding-standards/tree/master/manual)
19 |
20 | ## Requirements
21 |
22 | * PHP 5.3+
23 | * [PHP Codesniffer](https://github.com/squizlabs/PHP_CodeSniffer) 2.8+
24 |
25 | **Important note**: currently the latest PHPCS is the 3.x series. There is [a development branch](https://github.com/joomla/coding-standards/tree/3.x-dev) for the Joomla custom sniffs Which is compatible with the PHPCS 3.x series. Although PEAR and composer give you the option to install PHPCS 3.x by default the Joomla custom sniffs releases are currently only compatible with PHPCS 2.x and will not work, so we remind you to always install the PHPCS 2.x series if you are using the Joomla custom sniffs.
26 | If you want to test the [Joomla Code Standard development branch for PHPCS 3.x](https://github.com/joomla/coding-standards/tree/3.x-dev), please manually install the 3.x branch.
27 |
28 | ## Installation via Composer
29 |
30 | Add `"joomla/coding-standards": "~2.0"` to the require-dev block in your composer.json and then run `composer install`.
31 |
32 | ```json
33 | {
34 | "require-dev": {
35 | "joomla/coding-standards": "~2.0"
36 | }
37 | }
38 | ```
39 |
40 | Alternatively, you can simply run the following from the command line:
41 |
42 | ```sh
43 | composer global require squizlabs/php_codesniffer "~2.8"
44 | composer require joomla/coding-standards "~2.0"
45 | ```
46 |
47 | As stability of joomla/coding-standards 2.0.0 is currently alpha, make sure you allow usage of alpha software in Composer:
48 | In Composer json
49 | ```json
50 | {
51 | "require-dev": {
52 | "joomla/coding-standards": "~2.0@alpha"
53 | }
54 | }
55 | ```
56 | or on the command line
57 | ```bash
58 | composer config minimum-stability "alpha"
59 | ```
60 |
61 | If you want to install the coding-standards globally, edit your Composer global configuration by running:
62 |
63 | ```bash
64 | composer global config -e
65 | ```
66 |
67 | and add the following: `"minimum-stability": "alpha"`
68 |
69 | Once you have the coding standard files you can tell PHPCS where the standard folder is (i.e. install them in PHPCS)
70 | ```sh
71 | phpcs --config-set installed_paths /path/to/joomla-coding-standards
72 | ```
73 | Note: the composer scripts will run when the standard is installed globally, but not when it's a dependency. As such, you may want to run PHPCS config-set. When you run PHPCS config-set it will always overwrite the previous values. Use `--config-show` to check previous values before using `--config-set`
74 | So instead of overwriting the existing paths you should copy the existing paths revealed with `--config-show` and add each one separated by a comma:
75 | `phpcs --config-set installed_paths [path_1],[path_2],[/path/to/joomla-coding-standards]`
76 |
77 | ## Running
78 |
79 | You can use the installed Joomla standard like:
80 |
81 | phpcs --standard=Joomla path/to/code
82 |
83 | Alternatively if it isn't installed you can still reference it by path like:
84 |
85 | phpcs --standard=path/to/joomla/coding-standards path/to/code
86 |
87 | ### Selectively Applying Rules
88 |
89 | For consuming packages there are some items that will typically result in creating their own project ruleset.xml, rather than just directly using the Joomla ruleset.xml. A project ruleset.xml allows the coding standard to be selectively applied for excluding 3rd party libraries, for consideration of backwards compatibility in existing projects, or for adjustments necessary for projects that do not need PHP 5.3 compatibility (which will be removed in a future version of the Joomla Coding Standard in connection of the end of PHP 5.3 support in all active Joomla Projects).
90 |
91 | For information on [selectively applying rules read details in the PHP CodeSniffer wiki](https://github.com/squizlabs/PHP_CodeSniffer/wiki/Annotated-ruleset.xml#selectively-applying-rules)
92 |
93 | #### Common Rule Set Adjustments
94 |
95 | The most common adjustment is to exclude folders with 3rd party libraries, or where the code has yet to have coding standards applied.
96 |
97 | ```xml
98 |
99 | build/*
100 | tests/*
101 |
102 |
103 | libraries/*
104 | vendor/*
105 | ```
106 |
107 | Another common adjustment is to exclude the [camelCase format requirement](https://developer.joomla.org/coding-standards/php-code.html) for "Classes, Functions, Methods, Regular Variables and Class Properties" the essentially allows for B/C with snake_case variables which were only allowed in the context of interacting with the database.
108 |
109 | ```xml
110 |
111 |
112 |
113 |
114 |
115 |
116 | ```
117 |
118 | Old Protected method names were at one time prefixed with an underscore. These Protected method names with underscores are deprecated in Joomla projects but for B/C reasons are still in the projects. As such, excluding the MethodUnderscore sniff is a common ruleset adjustment
119 |
120 | ```xml
121 |
122 |
123 |
124 |
125 | ```
126 |
127 | The last most common adjustment is removing PHP 5.3 specific rules which prevent short array syntax, and allowing short array syntax for method parameters.
128 |
129 | ```xml
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 | ```
140 | ## Using example rulesets that Selectively Applying Rule
141 | You have to tell you can tell PHPCS where the example ruleset folder is (i.e. install them in PHPCS)
142 | ```sh
143 | phpcs --config-set installed_paths /path/to/joomla/coding-standards/Example-Rulesets
144 | ```
145 | Note: the composer scripts will run when the standard is installed globally, but not when it's a dependency. As such, you may want to run PHPCS config-set. When you run PHPCS config-set it will always overwrite the previous values. Use `--config-show` to check previous values before using `--config-set`
146 | So instead of overwriting the existing paths you should copy the existing paths revealed with `--config-show` and add each one separated by a comma:
147 | `phpcs --config-set installed_paths [path_1],[path_2],[/path/to/joomla-coding-standards],[/path/to/joomla/coding-standards/Example-Rulesets]`
148 |
149 | ## IDE autoformatters
150 |
151 | There is further information on how to set up IDE auto formatters here:
152 |
153 | [https://github.com/joomla/coding-standards/tree/master/Joomla/IDE](https://github.com/joomla/coding-standards/tree/master/Joomla/IDE)
154 |
155 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "joomla/coding-standards",
3 | "type": "phpcodesniffer-standard",
4 | "description": "Joomla Coding Standards",
5 | "keywords": ["joomla", "coding standards", "phpcs", "php codesniffer"],
6 | "homepage": "https://github.com/joomla/coding-standards",
7 | "license": "GPL-2.0-or-later",
8 | "authors": [
9 | {
10 | "name": "Joomla Coding Standards Contributors",
11 | "homepage": "https://github.com/joomla/coding-standards/graphs/contributors"
12 | }
13 | ],
14 | "require": {
15 | "php": ">=5.3.10",
16 | "squizlabs/php_codesniffer": "^2.8.0"
17 | },
18 | "require-dev": {
19 | "phpunit/phpunit": "^4.8.7"
20 | },
21 | "extra": {
22 | "branch-alias": {
23 | "dev-master": "2.x-dev"
24 | }
25 | },
26 | "scripts": {
27 | "post-install-cmd": "\"vendor/bin/phpcs\" --config-set installed_paths ../../..",
28 | "post-update-cmd" : "\"vendor/bin/phpcs\" --config-set installed_paths ../../.."
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/manual/README.md:
--------------------------------------------------------------------------------
1 | # Joomla Coding Standards Manual
2 | This manual documents the Joomla Coding Standards
3 |
4 | ## Meta Information
5 | The documentation in this repository is optimised for display in the [coding standards section](https://developer.joomla.org/coding-standards.html) of the Joomla! Developer Network. When formatting and proposing changes to this documentation, please keep the following in mind:
6 |
7 | - Heading levels should start at `
`
8 | - The document title does NOT need to be included in the document, these are displayed as the page heading based on the Joomla component configuration and would result in duplicated titles if included
9 | - Because the GitHub Markdown parser interprets line breaks as ` ` tags, arbitrary line breaks to keep lines from becoming too long should not be used
10 | - Links to documents in this manual should be formatted for use on the Joomla! Developer Network, such as `[a link to the Basic Guidelines page](/coding-standards/basic-guidelines.html)`
11 |
--------------------------------------------------------------------------------
/manual/appendices/analysis.md:
--------------------------------------------------------------------------------
1 | For new contributions we are going to be enforcing coding standards to ensure that the coding style in the source code is consistent. Ensuring that your code meets these standards will make the process of code contribution smoother.
2 |
3 | ### Configuring Code Analysis Tools
4 |
5 | In order to improve the consistency and readability of the source code, the Joomla project runs a coding style analysis tool, PHP_CodeSniffer, everytime changes are pushed to a Joomla project's repository.
6 |
7 | #### Running PHP_CodeSniffer
8 |
9 | The Joomla Coding Standards sniffer rules are written to be used with a tool called PHP CodeSniffer. Please see the [PHP_CodeSniffer PEAR Page](http://pear.php.net/package/PHP_CodeSniffer) for information on installing PHP_CodeSniffer on your system.
10 |
11 | You can run the CodeSniffer by going to the CMS, Framework, or Issue Tracker's root directory and executing
12 |
13 | ```
14 | phpcs --report=checkstyle --report-file=build/logs/checkstyle.xml --standard=/path/to//build/phpcs/Joomla /path/to/
15 | ```
16 |
17 | Alternatively, if you have Ant installed on your system, you may run the CodeSniffer by going to the `` of the Joomla project's code you want to test and executing
18 |
19 | ```
20 | ant phpcs
21 | ```
22 |
23 | ### Other Tools
24 |
25 | Here are some other tools available to developers who are planning to submit source code to the project.
26 |
27 | #### Set up PHP_CodeSniffer
28 |
29 | See in the documentation https://docs.joomla.org/Joomla_CodeSniffer#3._IDE_Integration
30 |
--------------------------------------------------------------------------------
/manual/appendices/examples.md:
--------------------------------------------------------------------------------
1 | Please contribute to this documentation page.
2 |
--------------------------------------------------------------------------------
/manual/basic-guidelines.md:
--------------------------------------------------------------------------------
1 | This chapter outlines the basic guidelines covering files contributed to the Joomla project. The most important rule to remember when coding for the Joomla project, **if in doubt, please ask**.
2 |
3 | ### File Format
4 |
5 | All files contributed to Joomla must be:
6 |
7 | * Stored as ASCII text
8 | Exceptions: languages locales and some test files containing non-ASCII characters
9 | * Use UTF-8 character encoding
10 | * Be Unix formatted following these rules.
11 | 1. Lines must end only with a line feed (LF).
12 | 2. Line feeds are represented as ordinal 10, octal 012 and hex 0A.
13 | 3. Do not use carriage returns (CR) like Macintosh computers do or the carriage return/line feed combination (CRLF) like Windows computers do.
14 |
15 | ### Spelling
16 |
17 | The spelling of words and terms used in code comments and in the naming of class, functions, variables and constant should generally be in accordance with British English rules (en\_GB). Some exceptions are permitted, for example where common programming names are used that align with the PHP API or other established conventions such as for `color` where is it common practice to maintain US English spelling.
18 |
19 | ### Indenting
20 |
21 | Tabs are used for indenting code (not spaces as required by the PEAR standard). Source code editors or Integrated Development Environments (IDE’s) such as Eclipse must have the tab-stops for indenting measuring four (4) spaces in length.
22 |
23 | ### Line Length
24 |
25 | There is no maximum limit for line lengths in files, however, a notional value of about 150 characters is recommended to achieve a good level of readability without horizontal scrolling. Longer lines are permitted if the nature of the code for individual lines requires it and line breaks would have an adverse affect on the final output (such as for mixed PHP/HTML layout files).
26 |
--------------------------------------------------------------------------------
/manual/css.md:
--------------------------------------------------------------------------------
1 | These guidelines have been assembled following an examination of emerging practices, ideas and existing styleguides, namely:
2 |
3 | 1. [OOCSS Code Standards](https://github.com/stubbornella/oocss-code-standards)
4 | 2. [Oneweb Style Guide](https://github.com/nternetinspired/OneWeb/blob/master/STYLEGUIDE.md)
5 | 3. [Idiomatic CSS](https://github.com/necolas/idiomatic-css)
6 |
7 | ### Commenting
8 |
9 | #### Major sections
10 | Major code sections should be named in caps and within a full comment block, eg:
11 |
12 | ```css
13 | /* ==========================================================================
14 | PRIMARY NAVIGATION
15 | ========================================================================== */
16 | ```
17 |
18 | #### Sub sections
19 | Subsections should be normally cased and within an open comment block.
20 |
21 | ```css
22 | /* Mobile navigation
23 | ========================================================================== */
24 | ```
25 |
26 | #### Verbose comments
27 |
28 | ```css
29 | /**
30 | * Short description using Doxygen-style comment format
31 | *
32 | * The first sentence of the long description starts here and continues on this
33 | * line for a while finally concluding here at the end of this paragraph.
34 | *
35 | * The long description is ideal for more detailed explanations and
36 | * documentation. It can include example HTML, URLs, or any other information
37 | * that is deemed necessary or useful.
38 | *
39 | * @tag This is a tag named 'tag'
40 | *
41 | * TODO: This is a todo statement that describes an atomic task to be completed
42 | * at a later date. It wraps after 80 characters and following lines are
43 | * indented by 2 spaces.
44 | */
45 | ```
46 |
47 | #### Basic comments
48 |
49 | ```css
50 | /* Basic comment */
51 | ```
52 |
53 | #### Uncompiled LESS/Scss comments
54 |
55 | ```css
56 | // These are stripped on compile.
57 | ```
58 |
59 | ### CSS selectors
60 | Only use classes for CSS selectors, *never IDs* as they introduce unwanted specificity to the cascade. Using an ID as a CSS selector is like firing the first nuke; you begin a specifity war that can only escalate, with terrible consequence.
61 |
62 | To put it another way; Don't use a Sith Lord when just two Storm Troopers will suffice: [CSS Specificity Wars](http://www.stuffandnonsense.co.uk/archives/css_specificity_wars.html)
63 |
64 | #### Class naming convention
65 | Use dashes to create compound class names:
66 |
67 | ```css
68 | /* Good - use dashes */
69 | .compound-class-name {…}
70 |
71 | /* Good - uses camelCase */
72 | .compoundClassName {…}
73 |
74 | /* Bad - uses underscores */
75 | .compound_class_name {…}
76 |
77 | /* Bad - does not use seperators */
78 | .compoundclassname {…}
79 | ```
80 |
81 | #### Indentation
82 | Rules should be indented one tab (equal to 4 spaces):
83 |
84 | ```css
85 | /* Good */
86 | .example {
87 | color: #000;
88 | visibility: hidden;
89 | }
90 |
91 | /* Bad - all on one line */
92 | .example {color: #000; visibility: hidden;}
93 | ```
94 |
95 | #### Alignment
96 | The opening brace must be on the same line as the last selector and preceded by a space. The closing brace must be on its own line after the last property and be indented to the same level as the opening brace.
97 |
98 | ```css
99 | /* Good */
100 | .example {
101 | color: #fff;
102 | }
103 |
104 | /* Bad - closing brace is in the wrong place */
105 | .example {
106 | color: #fff;
107 | }
108 |
109 | /* Bad - opening brace missing space */
110 | .example{
111 | color: #fff;
112 | }
113 | ```
114 |
115 | #### Property Format
116 | Each property must be on its own line and indented one level. There should be no space before the colon and one space after. All properties must end with a semicolon.
117 |
118 | ```css
119 | /* Good */
120 | .example {
121 | background: black;
122 | color: #fff;
123 | }
124 |
125 | /* Bad - missing spaces after colons */
126 | .example {
127 | background:black;
128 | color:#fff;
129 | }
130 |
131 | /* Bad - missing last semicolon */
132 | .example {
133 | background: black;
134 | color: #fff
135 | }
136 | ```
137 |
138 | #### HEX values
139 | HEX values must be declared in lowercase and shorthand:
140 |
141 | ```css
142 | /* Good */
143 | .example {
144 | color: #eee;
145 | }
146 |
147 | /* Bad */
148 | .example {
149 | color: #EEEEEE;
150 | }
151 | ```
152 |
153 | #### Attribute selectors
154 | Always use double quotes around attribute selectors.
155 |
156 | ```css
157 | /* Good */
158 | input[type="button"] {
159 | ...
160 | }
161 |
162 | /* Bad - missing quotes */
163 | input[type=button] {
164 | ...
165 | }
166 |
167 | /* Bad - using single quote */
168 | input[type='button'] {
169 | ...
170 | }
171 | ```
172 |
173 | #### Zero value units
174 | Zero values should not carry units.
175 |
176 | ```css
177 | /* Good */
178 | .example {
179 | padding: 0;
180 | }
181 |
182 | /* Bad - uses units */
183 | .example {
184 | padding: 0px;
185 | }
186 | ```
187 |
--------------------------------------------------------------------------------
/manual/docblocks.md:
--------------------------------------------------------------------------------
1 | Documentation headers for PHP code in: files, classes, class properties, methods and functions, called the docblocks, follow a convention similar to JavaDoc or phpDOC.
2 |
3 | These "DocBlocks" borrow from the PEAR standard but have some variations specific for Joomla and the Joomla projects.
4 |
5 | Whereas normal code indenting uses real tabs, all whitespace in a Docblock uses real spaces. This provides better readability in source code browsers. The minimum whitespace between any text elements, such as tags, variable types, variable names and tag descriptions, is two real spaces. Variable types and tag descriptions should be aligned according to the longest Docblock tag and type-plus-variable respectively.
6 |
7 | Code contributed to the Joomla project that will become the copyright of the project is not allowed to include @author tags. Joomla's philosophy is that the code is written "all together" and there is no notion of any one person "owning" any section of code. The @author tags are permitted in third-party libraries that are included in the core libraries.
8 |
9 | Files included from third party sources must leave DocBlocks intact. Layout files use the same DocBlocks as other PHP files.
10 |
11 | ### File DocBlock Headers
12 | The file header DocBlock consists of the following required and optional elements in the following order:
13 | Short description (optional unless the file contains more than two classes or functions), followed by a blank line). Long description (optional, followed by a blank line).
14 |
15 | * @version (optional and must be first)
16 | * @category (optional and rarely used)
17 | * @package (generally optional but required when files contain only procedural code. Always optional in namespaced code)
18 | * @subpackage (optional)
19 | * @author (optional but only permitted in non-Joomla source files)
20 | * @copyright (required)
21 | * @license (required and must be compatible with the Joomla license)
22 | * @link (optional)
23 | * @see (optional)
24 | * @since (generally optional but required when files contain only procedural code)
25 | * @deprecated (optional)
26 |
27 | Example of a DocBlock Header:
28 |
29 | ```php
30 | /**
31 | * @package Joomla.Installation
32 | * @subpackage Controller
33 | *
34 | * @copyright Copyright (C) 2005 - 2014 Open Source Matters, Inc. All rights reserved.
35 | * @license GNU General Public License version 2 or later; see LICENSE.txt
36 | */
37 | ```
38 |
39 | ### Class Definitions
40 | Class definitions start on a new line and the opening and closing braces are also placed on new lines. Class methods must follow the guidelines for Function Definitions. Properties and methods must follow OOP standards and be declared appropriately (using public, protected, private and static as applicable). Class definitions, properties and methods must each be provided with a DocBlock in accordance with the following sections.
41 |
42 | #### Class DocBlock Headers
43 | The class Docblock consists of the following required and optional elements in the following order.
44 | Short description (required, unless the file contains more than two classes or functions), followed by a blank line). Long description (optional, followed by a blank line).
45 |
46 | * @category (optional and rarely used)
47 | * @package (optional)
48 | * @subpackage (optional)
49 | * @author (optional but only permitted in non-Joomla source files)
50 | * @copyright (optional unless different from the file Docblock)
51 | * @license (optional unless different from the file Docblock)
52 | * @link (optional)
53 | * @see (optional)
54 | * @since (required, being the version of the software the class was introduced)
55 | * @deprecated (optional)
56 |
57 | Example of a Class file DocBlock header:
58 | ```php
59 | /**
60 | * Controller class to initialise the database for the Joomla Installer.
61 | *
62 | * @package Joomla.Installation
63 | * @subpackage Controller
64 | * @since 3.1
65 | */
66 | ```
67 |
68 | #### Class Property DocBlocks
69 | The class property Docblock consists of the following required and optional elements in the following order.
70 | Short description (required, followed by a blank line)
71 |
72 | * @var (required, followed by the property type)
73 | * @since (required)
74 | * @deprecated (optional)
75 |
76 | Example of Class property DocBlock:
77 |
78 | ```php
79 | /**
80 | * The generated user ID
81 | *
82 | * @var integer
83 | * @since 3.1
84 | */
85 | protected static $userId = 0;
86 | ```
87 |
88 | #### Class Method DocBlocks and Functions DocBlocks
89 | Function definitions start on a new line and the opening and closing braces are also placed on new lines. An empty line should precede lines specifying the return value.
90 |
91 | Function definitions must include a documentation comment in accordance with the Commenting section of this document.
92 |
93 | * Short description (required, followed by a blank line)
94 | * Long description (optional, followed by a blank line)
95 | * @param (required if there are method or function arguments, the last @param tag is followed by a blank line)
96 | * @return (required, followed by a blank line)
97 | * @since (required, followed by a blank line if there are additional tags)
98 | * @throws (required if method or function arguments throws a specific type of exception)
99 | * All other tags in alphabetical order.
100 |
101 | **Note:**
102 | Commonly a line after the tag @param consists of the following three parts in order of appearance:
103 | * variable type (There must be 3 spaces before variable type.)
104 | * variable name (There must be 2 spaces after the longest type.)
105 | * variable description (There must be 2 spaces after the longest variable name.)
106 |
107 | If there are more than one @param the type, names and description have to be aligned.
108 |
109 | Example of Method DocBlock:
110 | ```php
111 | /**
112 | * Set a controller class suffix for a given HTTP method.
113 | *
114 | * @param string $method The HTTP method for which to set the class suffix.
115 | * @param string $suffix The class suffix to use when fetching the controller name for a given request.
116 | *
117 | * @return JApplicationWebRouter This object for method chaining.
118 | *
119 | * @since 12.2
120 | *
121 | * @throws InvalidArgumentException Thrown if the provided arguments is not of type string.
122 | * @throws \UnexpectedValueException May be thrown if the container has not been set.
123 | */
124 | public function setHttpMethodSuffix($method, $suffix)
125 | ```
126 |
127 | If a function definition goes over multiple lines, all lines must be indented with one tab and the closing bracket must go on the same line as the last parameter.
128 |
129 | ```php
130 | function fooBar($param1, $param2,
131 | $param3, $param4)
132 | {
133 | // Body of method.
134 | }
135 | ```
136 |
--------------------------------------------------------------------------------
/manual/html.md:
--------------------------------------------------------------------------------
1 | These guidelines have been assembled following an examination of emerging practices, ideas and existing styleguides, and include items from:
2 |
3 | 1. [Google's HTML styleguide](https://google.github.io/styleguide/htmlcssguide.html)
4 | 2. [jQuery's HTML Styleguide](http://contribute.jquery.org/style-guide/html/)
5 | 3. [Nicolas Ghallager's "Principles of writing consistent, idiomatic HTML"](https://github.com/necolas/idiomatic-html)
6 | 4. [Harry Robert's "My HTML/CSS coding style"](http://csswizardry.com/2012/04/my-html-css-coding-style/)
7 | 4. [The BBC's Media Standards and Guidelines](http://www.bbc.co.uk/guidelines/futuremedia/technical/semantic_markup.shtml)
8 |
9 | ### Doctype
10 |
11 | Always use the minimal, versionless doctype.
12 |
13 | ```html
14 |
15 | ```
16 |
17 | ### Language
18 |
19 | Always define which language the page is written in.
20 |
21 | ```html
22 |
23 | ```
24 |
25 | ### Encoding
26 |
27 | Always define the character encoding. The encoding should be defined as early as possible. Make sure your editor uses UTF-8 as character encoding, without a byte order mark (UTF-8, no BOM). Do not specify the encoding of style sheets as these assume UTF-8.
28 |
29 | ```html
30 |
31 | ```
32 |
33 | More on encodings and when and how to specify them can be found in [Handling character encodings in HTML and CSS](http://www.w3.org/International/tutorials/tutorial-char-enc/)
34 |
35 | ### Capitalisation
36 | All HTML should be lowercase; element names, attributes, attribute values (unless text/CDATA), CSS selectors, properties, and property values (with the exception of strings). Additionally, there is no need to use CDATA to escape inline JavaScript, formerly a requirement to meet XML strictness in XHTML.
37 |
38 | ```html
39 |
40 |
41 |
42 |
43 | Home
44 | ```
45 |
46 | ```html
47 |
48 | a {
49 | color: #a3a3a3;
50 | }
51 |
52 |
53 | a {
54 | color: #A3A3A3;
55 | }
56 | ```
57 |
58 | ### Protocol
59 |
60 | Omit the protocol portion (http:, https:) from URLs pointing to images and other media files, style sheets, and scripts unless they are not available over both protocols.
61 |
62 | This prevents mixed content issues and results in minor file size savings.
63 |
64 | ```html
65 |
66 |
67 |
68 |
69 |
70 | ```
71 |
72 | ### Elements and Attributes
73 |
74 | Always include ``, ``, and `` tags.
75 |
76 | ### Type attributes
77 |
78 | Do not use type or attributes for style sheets (unless not using CSS) and scripts (unless not using JavaScript).
79 |
80 | ```html
81 |
82 |
83 |
84 |
85 |
86 | ```
87 |
88 | ### Language attributes
89 |
90 | Do not use language attributes on script tags.
91 | ```html
92 |
93 |
106 |
107 |
108 |
109 | ```
110 |
111 | Use attribute/value pairs for boolean attributes
112 |
113 | ```html
114 |
115 |
116 |
117 |
118 |
119 | ```
120 |
121 | HTML attributes should be listed in an order that reflects the fact that class names are the primary interface through which CSS and JavaScript select elements.
122 |
123 | 1. class
124 | 2. id
125 | 3. data-*
126 | 4. Everything else
127 |
128 | ```html
129 |
130 | Text
131 |
132 |
133 | Text
134 | ```
135 |
136 | Elements with multiple attributes can have attributes arranged across multiple lines in an effort to improve readability and produce more useful diffs:
137 |
138 | ```html
139 |
143 | Text
144 |
145 | ```
146 |
147 | ### Elements
148 |
149 | Optional closing tags may not be omitted.
150 |
151 | ```html
152 |
153 |
The quick brown fox jumps over the lazy dog.
154 |
155 |
156 |
The quick brown fox jumps over the lazy dog.
157 | ```
158 |
159 | Self-closing (void) elements should not be closed. Trailing forward slashes and spaces should be omitted.
160 |
161 | ```html
162 |
163 |
164 |
165 |
166 |
167 | ```
168 |
169 | ### Formatting
170 |
171 | Use a new line for every block, list, or table element, and indent every such child element.
172 |
173 | ```html
174 |
175 |
176 |
177 |
Home
178 |
Blog
179 |
180 |
181 |
182 |
183 |
184 |
Home
185 |
Blog
186 |
187 | ```
188 |
189 | We prefer readability over file-size savings when it comes to maintaining existing files. Plenty of whitespace is encouraged. Use whitespace to visually separate groups of related markup and to improve the readability and maintainability of your HTML. Use two empty lines between larger blocks, and use a single empty line between child blocks of larger blocks. Be consistent. (If you are worried about your document's size, spaces (as well as repeated use of the same strings - for instance class names) are excellent candidates for compression. Also, you may use a markup minifier to decrease your document's file size.)
190 |
191 | Keep line-length to a sensible maximum, e.g., 80 columns.
192 |
193 | Tip: configure your editor to "show invisibles". This will allow you to eliminate end of line whitespace, eliminate unintended blank line whitespace, and avoid polluting commits.
194 |
195 | ```html
196 |
252 |
253 |
254 |
255 | ```
256 |
257 | ### Trailing Whitespace
258 |
259 | Remove trailing white spaces. Trailing white spaces are unnecessary and can complicate diffs.
260 |
261 | ```html
262 |
263 |
Yes please.
264 |
265 |
266 |
No, thank you.
267 | ```
268 |
269 | ### Entity References
270 |
271 | Do not use entity references. There is no need to use entity references like —, ”, or ☺, assuming the same encoding (UTF-8) is used for files and editors as well as among teams.
272 |
273 | The only exceptions apply to characters with special meaning in HTML (like < and &) as well as control or “invisible” characters (like no-break spaces).
274 |
275 | ```html
276 |
277 |
The currency symbol for the Euro is “€”.
278 |
279 |
280 |
The currency symbol for the Euro is “&eur;”.
281 | ```
282 |
283 | ### Inline CSS
284 |
285 | Inline CSS must be avoided. When altering states using JavaScript, use CSS to define your states, and only use unobtrusive JavaScript to alter class names whenever possible.
286 |
287 | ```html
288 |
289 | Home
290 |
291 |
292 | Home
293 | ```
294 |
295 | @todo more meaningful example.
296 |
297 | ### Style Attributes
298 |
299 | You should not use border, align, valign, or clear attributes. Avoid use of style attributes, except where using syndicated content or internal syndicating systems.
300 |
301 | ### Semantics
302 |
303 | Use HTML according to its purpose. For example, use heading elements for headings, `
313 | ```
314 |
315 | ### Markup
316 |
317 | #### Image Tags
318 |
319 | Image elements (``) must have an alt attribute. Height and width attributes are optional and may be omitted.
320 |
321 | @todo add examples from here http://www.bbc.co.uk/guidelines/futuremedia/technical/semantic_markup.shtml
322 |
323 | ### Comments
324 |
325 | @todo: comment styles in JS, CSS, HTML
326 |
327 | For more complex blocks of HTML, it may be useful to add a comment to the closing tag:
328 |
329 | ```html
330 |
331 |
332 |
333 |
334 |
335 |
336 | ```
337 |
338 | ### Mark todos
339 | Highlight todos by using the keyword TODO, eg:
340 |
341 | ```html
342 |
343 |
344 |
Home
345 |
Blog
346 |
347 | ```
348 |
349 | ### Adding line breaks
350 |
351 | Always use ` ` instead of ` ` and ` ` eg:
352 |
353 | ```html
354 | This text contains a line break.
355 | ```
356 |
357 | ### Markup validation tools
358 |
359 | @todo: list various testing tools:
360 |
361 | * http://validator.w3.org/nu/
362 | * http://csslint.net/
363 |
--------------------------------------------------------------------------------
/manual/ini.md:
--------------------------------------------------------------------------------
1 | .ini Language Files Format
2 |
3 | An .ini file is composed of strings and comments. See [Specification of language files](https://docs.joomla.org/Specification_of_language_files).
4 |
5 | ### Formatting
6 |
7 | #### Comments
8 | There are 2 types of comments:
9 | - Comments used as sections, to clarify the use of a group of strings.
10 | - Comments used to inform translators of some characteristics of the string(s) just below. These should not be preceded by a blank line.
11 |
12 | #### Strings
13 | - All language strings are in British English (en-GB). See [Joomla! en-GB User Interface Text Guidelines](https://developer.joomla.org/en-gb-user-interface-text-guidelines/introduction.html)
14 | - The lines commented should start with a semi-colon.
15 | - The strings should be alphabetically ordered using the "Standard Alphabetical Order" and not the "ASCII order". This mostly means here that the underscore is sorted BEFORE the letters.
16 |
17 | Example:
18 | ```ini
19 | COM_ABCD_FORMAT_WHATEVER
20 | ```
21 | comes before
22 | ```ini
23 | COM_ABCD_FORMATTING_WHATEVER
24 | ```
25 |
26 | Some specific text editors only sort by "ASCII order" and should not be used.
27 |
28 | ### Plugins
29 | Some IDEs have specific plugins to sort the lines by "Standard Alphabetical Order".
30 |
31 | Examples:
32 | - Atom [Sort selected elements](https://github.com/BlueSilverCat/sort-selected-elements)
33 | - Eclipse [Sortit](https://github.com/channingwalton/eclipse-sortit/tree/master/com.teaminabox.eclipse.sortit)
34 | - NetBeans [Sort line tools](http://plugins.netbeans.org/plugin/45925/sort-line-tools)
35 | - PhpStorm [String Manipulation](https://plugins.jetbrains.com/plugin/2162-string-manipulation)
36 |
37 | It may be necessary to set the sorting to "Case Insensitive Sort" to obtain the correct results.
38 |
39 | ### Online tools
40 | There is also an online tool which lets order this way (among other goodies): https://wordcounter.net/alphabetize
41 |
42 | ### Notes
43 | When the file includes commented sections, the strings should be alphabetically ordered in each section.
44 | Warning: when the comments concern specific strings and sorting has modified the order, the comments should be moved to the right place.
--------------------------------------------------------------------------------
/manual/inline-comments.md:
--------------------------------------------------------------------------------
1 | This chapter covers inline code commenting in more detail. Inline comments are all comments not included in doc blocs. The goal of in line commenting is to explain code in context. Such explanation may take many different forms.
2 |
3 | Comments that are written in a readable and narrative style, especially when explaining a complex process, are encouraged. In general they should be placed close to the code explained rather than before the entire block of code.
4 |
5 | Comments should be as sentence like as possible, which is to say that they should be complete and readable, not in short hand.
6 |
7 | Comments are not a replacement for detailed doc blocks. Comments serve to explain the logic and structure of code itself rather than the use of code.
8 |
9 | ### Formatting of Comments
10 |
11 | Comment blocks that introduce large sections of code and are more than 2 lines long should use `/* */` (C) style and should use `*` on each line with the same space/tab rules as doc blocks. If you need a large introduction consider whether this block should be separated into a method to reduce complexity and therefore providing a full docblock.
12 |
13 | Comments should precede the code they refer to. As a corollary, comments should not be on the same line as the code to which they refer (which puts them after the code they reference). They should be on their own lines.
14 |
15 | Don’t use a blank line between comments and the code they refer to (no space underneath a comment block).
16 |
17 | Always have a single blank line before a comment or block of comments unless the comment (or block) is at the beginning of a code structure. ( You should not have a blank line after a '{' line )
18 |
19 | For example in the following case there is no new line before the first comment (because it follows a '{' line) but we do want a new line before the second comment:
20 |
21 | ```php
22 | while (!$done)
23 | {
24 | // We don't want an infinite loop here.
25 | $done = true;
26 | }
27 |
28 | // Now let's do something interesting.
29 | $result = somethingInteresting();
30 | ```
31 |
32 | Comments should align with the code they refer to, using the same indenting as the line that follows the comment.
33 |
34 | Comments should be indented with tabs (like code, not like doc blocks).
35 |
36 | ### Content of comments
37 |
38 | Comments should use en-GB
39 |
40 | Always have a space between // and the start of comment text.
41 |
42 | New lines should always start with an upper case letter unless:
43 | * The line is a continuation of a complete sentence.
44 | * The term is code and is case sensitive.
45 |
46 | Code that is included specifically to assure compatibility with other software (for example specific browsers or a specific version of the CMS or for backward compatibility reasons) should be clearly marked as such. If there is the intention to remove specific code at a future point, state that but do not use a deprecation tag or specify a release (this can be hard to predict).
47 |
48 | Check spelling and grammar on all comments (see below and [the en-GB guidelines](https://developer.joomla.org/en-gb-user-interface-text-guidelines.html)).
49 |
50 | Only end a line with a period if it is a full sentence.
51 |
52 | Rather than use docblock tags use See:, Link: and Note: for comments if appropriate.
53 |
54 | Do not use HTML in comments unless specifically related to the comment content.
55 |
56 | Do not leave commented code unless there is a clearly explained reason for doing so. In such a case, a comment saying "Code intentionally commented" will prevent accidental removal.
57 |
58 | Comments may include forward looking statements of how something will be extended or modified in the future, but not todos indicating that code is not complete or ready to use.
59 |
60 | Remember that humor and sarcasm are difficult to translate.
61 |
62 | ### Acronyms
63 |
64 | Capitalise all letters of acronyms such as HTML, XML, SQL, GMT, and UTC.
65 |
66 | ### Common spelling and grammar errors for which to check.
67 |
68 | Joomla contributors include many non-native speakers of en-GB which makes it understandable that there are sometimes spelling and grammar errors. At the same time, some people reading comments also are non native speakers and may even use automated translation to understand comments. This makes it very important that comments should follow proper en-GB spelling and grammar rules. Unfortunately, these can be tricky.
69 |
70 | #### S vs Z
71 |
72 | en-GB most commonly uses `ise` where en-US would use `ize`, such as `normalise` instead of `normalize`. (Note that there are some exceptions to this rule.)
73 |
74 | Use of apostrophes is one of the trickier parts of English.
75 |
76 | #### Lets versus let’s
77 |
78 | Lets means permits or allows to:
79 |
80 | ```php
81 | // This lets the user enter data
82 | ```
83 |
84 | Let’s is a contraction for let us and means we are going to do this now:
85 |
86 | ```php
87 | // Let's validate the field
88 | ```
89 |
90 | #### Its versus it’s
91 |
92 | Its is the possessive form of it:
93 |
94 | ```php
95 | // Get its ID
96 | ```
97 |
98 | It’s is a contraction of it is
99 |
100 | ```php
101 | // It's time to save
102 | ```
103 |
104 | #### The correct Joomla spelling of some commonly used words.
105 |
106 | - dependant
107 | - deprecated
108 |
--------------------------------------------------------------------------------
/manual/introduction.md:
--------------------------------------------------------------------------------
1 | Good coding standards are important in any software development project. These standards are even more important when a large, diverse and worldwide community of developers are contributing to a project. One of the things that sets good software apart from great software is not only the features or the actual function the software performs, but the quality of its source code.
2 |
3 | In order to perform in the highly competitive Open Source and proprietary software industries, source code not only needs to be beautifully designed, it also needs to be beautiful and elegant to look at. The Joomla Coding Standards Manual is to help ensure our code is the highest quality which will make it easy to read, debug, and maintain.
4 |
5 | ### Guiding Principles
6 |
7 | Since readable code is more maintainable, the compass that guides us in achieving that goal is a set of well thought out coding standards for the different software languages that are employed in the Joomla software project. Joomla has a solid heritage of striving to support a great looking product with great looking code.
8 |
9 | This manual compiles the collective wisdom of past and present contributors to the project to form the definitive standard for coding in Joomla, whether that is for the core Joomla Framework or an extension that forms part of the stack of the Joomla CMS. This manual also serves as a lighthouse to the Joomla developer community, to safely guide developers around the pitfalls of becoming lackadaisical with respect to writing clean, beautiful code.
10 |
11 | The Joomla Coding Standards borrows heavily from the PEAR coding standard for PHP files, augmenting and diverging where it is deemed sensible to do so.
12 |
13 | There are [tools available](/coding-standards/analysis.html) to help your code conform to our standards.
14 |
15 | ### Contributing to this manual
16 |
17 | If you want to contribute and improve this manual, you can find the source files at [https://github.com/joomla/coding-standards/tree/master/manual](https://github.com/joomla/coding-standards/tree/master/manual).
18 |
--------------------------------------------------------------------------------
/manual/javascript-j3.md:
--------------------------------------------------------------------------------
1 | ### Contents
2 |
3 | 1. [Naming Conventions](#naming-conventions)
4 | - [Variables](#naming-conventions-variables)
5 | - [Functions](#naming-conventions-functions)
6 | - [Reserved Words](#naming-conventions-reserved)
7 | 2. [Syntax Style](#syntax-style)
8 | - [Indentation](#syntax-indentation)
9 | - [Spacing](#syntax-spacing)
10 | - [Commas](#syntax-commas)
11 | - [Semicolons](#syntax-semicolons)
12 | - [Quotes](#syntax-quotes)
13 | 3. [Types](#types)
14 | 4. [Functions](#functions)
15 | 5. [Conditional Statements](#conditional-statements)
16 | 6. [Blocks & Multi-line Statements](#blocks)
17 | 7. [Comments](#comments)
18 |
19 |
20 | ### Naming Conventions
21 |
22 | Use descriptive words or terse phrases for names.
23 |
24 | Variables and Functions should be camel case, starting with a lowercase letter: `likeThis`
25 |
26 |
27 | #### Variables
28 |
29 | **Use names that describe what the variable is:**
30 |
31 | `var element = document.getElementById('elementId');`
32 |
33 | **Iterators are the exception**
34 |
35 | Use i for index in a loop (and subsequent letters when necessary for nested iteration).
36 |
37 |
38 | #### Functions
39 |
40 | **Use names that describe what the function does:**
41 |
42 | ```js
43 | function getSomeData() {
44 | // statements
45 | }
46 | ```
47 |
48 |
49 | #### Reserved Words
50 |
51 | Do not use reserved words for anything other than their intended use. The list of: [Reserved Words](http://es5.github.io/#x7.6.1)
52 |
53 | ---
54 |
55 |
56 | ### Syntax Style
57 |
58 |
59 | #### Indentation
60 | - Don't mix tabs and spaces.
61 | - Tabs, 4 spaces
62 |
63 |
64 | #### Spacing
65 | - No whitespace at the end of line or on blank lines.
66 | - Unary special-character operators (e.g., !, ++) must not have space next to their operand.
67 | - Any , and ; must not have preceding space.
68 | - Any ; used as a statement terminator must be at the end of the line.
69 | - Any : after a property name in an object definition must not have preceding space.
70 | - The ? and : in a ternary conditional must have space on both sides.
71 | - No filler spaces in empty constructs (e.g., {}, [], fn())
72 | - New line at the end of each file.
73 |
74 | **Array:**
75 |
76 | ```js
77 | var array = [ 'foo', 'bar' ];
78 | ```
79 |
80 | **Function call:**
81 |
82 | ```js
83 | foo( arg );
84 | ```
85 |
86 | **Function call with multiple arguments:**
87 |
88 | ```js
89 | foo( 'string', object );
90 | ```
91 |
92 | **Conditional Statements**
93 |
94 | ```js
95 | if ( condition ) {
96 | // statements
97 | } else {
98 | // statements
99 | }
100 | ```
101 |
102 | ```js
103 | while ( condition ) {
104 | // statements
105 | }
106 | ```
107 |
108 | ```js
109 | for ( prop in object ) {
110 | // statements
111 | }
112 | ```
113 |
114 |
115 | ##### Exceptions
116 |
117 | **First or only argument is an object, array or callback function.**
118 |
119 | **No space before the first argument:**
120 |
121 | ```js
122 | foo({
123 | a: 'bar',
124 | b: 'baz'
125 | });
126 | ```
127 |
128 | ```js
129 | foo(function() {
130 | // statements
131 | }, options ); // space after options argument
132 | ```
133 |
134 | **Function with a callback, object, or array as the last argument:**
135 |
136 | No space after the last argument.
137 |
138 | ```js
139 | foo( data, function() {
140 | // statements
141 | });
142 | ```
143 |
144 |
145 | #### Commas
146 |
147 | **Place commas after:**
148 |
149 | - variable declarations
150 | - key/value pairs
151 |
152 | #### Arrays
153 |
154 | Do not include a trailing comma, this will add 1 to your array's length.
155 |
156 | **No:**
157 |
158 | ```js
159 | array = [ 'foo', 'bar', ];
160 | ```
161 |
162 | **Yes:**
163 |
164 | ```js
165 | array = [ 'foo', 'bar' ];
166 | ```
167 |
168 |
169 | #### Semicolons
170 |
171 | Use them where expected.
172 |
173 | Semicolons should be included at the end of function expressions, but not at the end of function declarations.
174 |
175 | **Function Expression:**
176 |
177 | ```js
178 | var foo = function() {
179 | return true;
180 | };
181 | ```
182 |
183 | **Function Declaration:**
184 |
185 | ```js
186 | function foo() {
187 | return true;
188 | }
189 | ```
190 |
191 |
192 | #### Quotes
193 |
194 | Use ' instead of "
195 |
196 |
197 | ---
198 |
199 |
200 | ### Variables
201 |
202 | ### Avoid Global Variables
203 |
204 | **No:**
205 |
206 | ```js
207 | foo = 'bar';
208 | ```
209 |
210 | **No: implied global**
211 |
212 | ```js
213 | function() {
214 | foo = 'bar';
215 | }
216 | ```
217 |
218 | **Yes:**
219 |
220 | ```js
221 | var foo = 'bar';
222 | ```
223 |
224 | #### Multiple Variable Declarations
225 |
226 | Use one `var` declaration and separate each variable on a newline ending with a comma.
227 |
228 | **No:**
229 |
230 | ```js
231 | var foo = 'bar';
232 | var bar = 'baz';
233 | var baz = 'qux';
234 | ```
235 |
236 | **Yes:**
237 |
238 | ```js
239 | var foo = 'bar',
240 | bar = 'baz',
241 | baz = 'qux';
242 | ```
243 |
244 |
245 | ---
246 |
247 |
248 | ### Types
249 |
250 | #### String
251 |
252 | - Concatenate long strings.
253 | - Place space before closing quote at the end of each string.
254 | - Concatenation operator at the end of each subsequent string.
255 |
256 | ```js
257 | var longString = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. ' +
258 | 'Sed placerat, tellus eget egestas tincidunt, lectus dui ' +
259 | 'sagittis massa, id mollis est tortor a enim. In hac ' +
260 | 'habitasse platea dictumst. Duis erat justo, tincidunt ac ' +
261 | 'enim iaculis, malesuada condimentum mauris. Vestibulum vel ' +
262 | 'cursus mauris.';
263 | ```
264 |
265 | #### Number
266 |
267 | Use `parseInt()` or `parseFloat()` instead of unary plus, for readability.
268 |
269 | **No:**
270 |
271 | ```js
272 | var count = +document.getElementById('inputId').value;
273 | ```
274 |
275 | **Yes:**
276 |
277 | ```js
278 | var count = parseInt(document.getElementById('inputId').value);
279 | ```
280 |
281 | #### Type Checks
282 |
283 | - String: `typeof object === 'string'`
284 | - Number: `typeof object === 'number'`
285 | - Boolean: `typeof object === 'boolean'`
286 | - Object: `typeof object === 'object'`
287 | - Plain Object: `jQuery.isPlainObject( object )`
288 | - Function: `jQuery.isFunction( object )`
289 | - Array: `jQuery.isArray( object )`
290 | - Element: `object.nodeType`
291 | - null: `object === null`
292 | - null or undefined: `object == null`
293 |
294 | **Undefined:**
295 |
296 | - Global Variables: `typeof variable === 'undefined'`
297 | - Local Variables: `variable === undefined`
298 | - Properties: `object.prop === undefined`
299 |
300 | #### Objects
301 |
302 | Use the literal, not constructor, syntax.
303 |
304 | **No:**
305 |
306 | ```js
307 | var myObj = new Object();
308 | ```
309 |
310 | **Yes:**
311 |
312 | ```js
313 | var myObj = {};
314 | ```
315 |
316 | If an object contains more than one key/value pair or an array as a value, each key/value pair should be on its own line.
317 |
318 | ```js
319 | var myObj = {
320 | foo: 'bar',
321 | bar: 'baz',
322 | baz: 'qux'
323 | };
324 | ```
325 |
326 | #### Arrays
327 |
328 | Use the literal, not constructor, syntax
329 |
330 | **No:**
331 |
332 | ```js
333 | var myArr = new Array();
334 | ```
335 |
336 | **Yes:**
337 |
338 | ```js
339 | var myArr = [];
340 | ```
341 |
342 | If you don't know array length use push method. This will replace the current array.
343 |
344 | ```js
345 | var myArr = [];
346 | myArr.push('foo');
347 | ```
348 |
349 |
350 | ---
351 |
352 |
353 | ### Functions
354 |
355 | #### Chaining Method Calls
356 |
357 | ```js
358 | $('.someElement')
359 | .hide()
360 | .delay(1000)
361 | .fadeIn();
362 | ```
363 |
364 |
365 | ---
366 |
367 |
368 | ### Conditional Statements
369 |
370 | Use ternary syntax if:
371 |
372 | - One condition
373 | - Result of either evaluation is one operation.
374 |
375 | ```js
376 | joomlaRocks ? 'This is true' : 'else it is false';
377 | ```
378 |
379 | Otherwise, use standard syntax:
380 |
381 | ```js
382 | if ( condition ) {
383 | // statements
384 | } else {
385 | // statements
386 | }
387 | ```
388 |
389 | **Cache length in variable for performance:**
390 |
391 | ```js
392 | var i,
393 | j = myArr.length;
394 |
395 | for ( i = 0; i < j; i++ ) {
396 | // statements
397 | }
398 | ```
399 |
400 | **With more than one condition:**
401 |
402 | ```js
403 | if ( condition &&
404 | condition2 &&
405 | condition3 ) {
406 | // statements
407 | } else {
408 | // statements
409 | }
410 | ```
411 |
412 | #### Equality
413 |
414 | Use strict equality operator === so that type is considered in comparison. Using == can produce false positives.
415 |
416 |
417 | ```js
418 | // evaluates true
419 | 1 == "1"
420 | ```
421 |
422 | ```js
423 | // evaluates false
424 | 1 === "1"
425 | ```
426 |
427 |
428 | ---
429 |
430 |
431 | ### Blocks & Multi-line Statements
432 |
433 | Use curly braces on blocks that have more than one statement.
434 |
435 | **Block with one statement:**
436 |
437 | ```js
438 | if ( test ) return false;
439 | ```
440 |
441 | **Block with more than one statement:**
442 |
443 | ```js
444 | if ( test ) {
445 | var foo = 'some string';
446 | return foo;
447 | }
448 | ```
449 |
450 |
451 | ---
452 |
453 |
454 | ### Comments
455 |
456 | **Single Line**
457 |
458 | - Place above the code it refers to.
459 | - A space between double forward slashes and comment text.
460 |
461 | ```js
462 | // I am a single line comment.
463 | ```
464 |
465 |
466 | **Multiline**
467 |
468 | - Place above the code it refers to.
469 | - Opening token placed on the line above first comment line, closing placed below last comment line.
470 | - Each comment line begins with two astericks followed by a space.
471 |
472 | ```js
473 | /*
474 | ** I am a multiline comment.
475 | ** Line two
476 | ** Line three
477 | */
478 | ```
479 |
480 | ---
481 |
482 | ### TODO
483 |
484 | - Switch Statements vs other methods like Objects
485 | - Add jQuery examples
486 | - Double check accuracy of all examples
487 |
488 | **With help from:**
489 |
490 | - [jQuery JS Style Guide](https://contribute.jquery.org/style-guide/js)
491 | - [Idiomatic JS](https://github.com/rwaldron/idiomatic.js)
492 |
--------------------------------------------------------------------------------
/manual/javascript-j4.md:
--------------------------------------------------------------------------------
1 | ### Javascript in Joomla 4
2 |
3 | Joomla 4 uses ES6 syntax where possible. As part of this change we decided to use an industry standard codestyle rules for our JavaScript - the AirBNB coding standards. These can be found [on their GitHub page](https://github.com/airbnb/javascript#table-of-contents).
4 |
5 | We have four modifications to the defaults:
6 |
7 | 1. We allow parameter reassignment of function parameters to allow easier setting of defaults (for examples please see the ESLint rules [here](https://eslint.org/docs/rules/no-param-reassign))
8 |
9 | 2. We only allow the imports of dependencies from NPM in our build directory (`build/`) (rather than in all files)
10 |
11 | 3. We currently allow browser alerts using the `alert()` function (the long term intention is to disable this as we move to our custom element alerts)
12 |
13 | 4. We always enable JavaScript strict mode as we aren't using JavaScript modules at this time
14 |
15 | We also use ESLint to enforce these rules. If you are familiar with JavaScript from other projects you've worked on you can find our ESLint rules [on GitHub](https://github.com/joomla/joomla-cms/blob/4.0-dev/.eslintrc)
16 |
--------------------------------------------------------------------------------
/manual/license.md:
--------------------------------------------------------------------------------
1 | The contents of the Joomla! en-GB User Interface Text Guidelines are subject to copyright law and are made available under the [Joomla! Electronic Documentation License (JEDL)](https://docs.joomla.org/JEDL) unless otherwise stated.
2 |
3 | You may find the [JEDL Frequently Asked Questions](https://docs.joomla.org/JEDL/FAQ) useful in determining if your proposed use of this material is allowed.
4 |
5 | If you have any questions regarding licensing of this material please contact legal@opensourcematters.org.
6 |
7 | If you wish to report a possible violation of the license terms for the material on this site then please contact legal@opensourcematters.org.
8 |
--------------------------------------------------------------------------------
/manual/php.md:
--------------------------------------------------------------------------------
1 | > **Note**
2 | >
3 | > The Joomla! CMS switched in Version 4.2.0 from its own coding standard to the PSR-12 (and later to PER Coding Style) coding standard.
4 | > This document applies to Joomla! < 4.2.0 and parts of it still applies to 4.2.0 and later.
5 | >
6 | > This document will be updated to reflect the PSR-12 coding standard soon.
7 |
8 | ### Language Constructs
9 |
10 | #### PHP Code Tags
11 |
12 | Always use the full `` to delimit PHP code, not the ` ... ?>` shorthand. This is the most portable way to include PHP code on differing operating systems and setups.
13 |
14 | For files that contain only PHP code, the closing tag (`?>`) should not be included. It is not required by PHP. Leaving this out prevents trailing white space from being accidentally injected into the output that can introduce errors in the Joomla session (see the PHP manual on [Instruction separation](https://secure.php.net/basic-syntax.instruction-separation)).
15 |
16 | Files should always end with a blank new line.
17 |
18 | #### General
19 |
20 | Pursuant to PSR-2 [Keywords and True/False/Null][]
21 |
22 | > PHP [keywords][] MUST be in lower case.
23 | > The PHP constants `true`, `false`, and `null` MUST be in lower case.
24 |
25 | [Keywords and True/False/Null]: https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md#25-keywords-and-truefalsenull
26 | [keywords]: https://secure.php.net/manual/en/reserved.keywords.php
27 |
28 | #### Including Code
29 |
30 | Anywhere you are unconditionally including a file, use `require_once`. Anywhere you are conditionally including a file (for example, factory methods), use `include_once`. Either of these will ensure that files are included only once. They share the same file list, so you don't need to worry about mixing them. A file included with `require_once` will not be included again by `include_once`.
31 |
32 | > **Note**
33 | >
34 | > `include_once` and `require_once` are PHP language statements, not functions. The correct formatting is:
35 | >
36 | >
37 | > `require_once JPATH_COMPONENT . '/helpers/helper.php';`
38 |
39 | You should not enclose the filename in parentheses.
40 |
41 | #### E_STRICT Compatible PHP Code
42 |
43 | As of Joomla version 1.6 and for all versions of the Joomla Platform, adhering to object oriented programming practice as supported by PHP 5.3+ is required. Joomla is committed to progressively making the source code E_STRICT.
44 |
45 | ### Global Variables
46 |
47 | Global variables should not be used. Use static class properties or constants instead of globals, following OOP and factory patterns.
48 |
49 | ### Error Surpression
50 |
51 | The use of the `@` for Error Surpression should be avoided and limited to use when no other approach or workaround is available.
52 |
53 | ### Control Structures (General Code)
54 |
55 | For all control structures there is a space between the keyword and an opening parenthesis, then no space either after the opening parenthesis or before the closing bracket. This is done to distinguish control keywords from function names. All control structures must contain their logic within braces.
56 |
57 | For all all control structures, such as `if`, `else`, `do`, `for`, `foreach`, `try`, `catch`, `switch` and `while`, both the keyword starts a newline and the opening and closing braces are each put on a new line.
58 |
59 | Exclamation mark `!`, the logical operator `not` used in a condition, should not have spaces before or after the exclamation mark as shown in the examples.
60 |
61 | #### An _if-else_ Example
62 |
63 | ```php
64 | if ($test)
65 | {
66 | echo 'True';
67 | }
68 |
69 | // Comments can go here.
70 | // Note that "elseif" as one word is used.
71 | elseif ($test === false)
72 | {
73 | echo 'Really false';
74 | }
75 | elseif (!$condition)
76 | {
77 | echo 'Not Condition';
78 | }
79 | else
80 | {
81 | echo 'A white lie';
82 | }
83 | ```
84 |
85 | If a control structure goes over multiple lines, all lines must be indented with one tab and the closing brace must go on the same line as the last parameter.
86 |
87 | ```php
88 | if ($test1
89 | && $test2)
90 | {
91 | echo 'True';
92 | }
93 | ```
94 |
95 | #### A _do-while_ Example
96 |
97 | ```php
98 | do
99 | {
100 | $i++;
101 | }
102 | while ($i < 10);
103 | ```
104 |
105 | #### A _for_ Example
106 |
107 | ```php
108 | for ($i = 0; $i < $n; $i++)
109 | {
110 | echo 'Increment = ' . $i;
111 | }
112 | ```
113 |
114 | #### A _foreach_ Example
115 |
116 | ```php
117 | foreach ($rows as $index => $row)
118 | {
119 | echo 'Index = ' . $index . ', Value = ' . $row;
120 | }
121 | ```
122 |
123 | #### A _while_ Example
124 |
125 | ```php
126 | while (!$done)
127 | {
128 | $done = true;
129 | }
130 | ```
131 |
132 | #### A _switch_ example
133 |
134 | When using a `switch` statement, the `case` keywords are indented. The `break` statement starts on a newline assuming the indent of the code within the case.
135 |
136 | ```php
137 | switch ($value)
138 | {
139 | case 'a':
140 | echo 'A';
141 | break;
142 |
143 | default:
144 | echo 'I give up';
145 | break;
146 | }
147 | ```
148 |
149 | #### A _try catch_ example
150 | ```php
151 | try
152 | {
153 | $table->bind($data);
154 | }
155 | catch (RuntimeException $e)
156 | {
157 | throw new Exception($e->getMessage(), 500, $e);
158 | }
159 | ```
160 |
161 | ### Mixed language usage (e.g. at the layout files)
162 |
163 | For layout files and all files where we use a mix of PHP and HTML (all PHP files in the `view/tmpl` and `layout` folder) we additionally wrap every line into a `` block and use the alternative syntax for control structures. This should make the code easier to read and make it easier to move blocks around without creating fatal errors due to missing `` tags.
164 |
165 | #### Example Control Structures
166 |
167 | ##### An _if-else_ Example
168 |
169 | ```php
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 | ```
178 |
179 | ### References
180 |
181 | When using references, there should be a space before the reference operator and no space between it and the function or variable name.
182 |
183 | For example:
184 |
185 | ```php
186 | $ref1 = &$this->sql;
187 | ```
188 |
189 | > **Note**
190 | >
191 | > In PHP 5, reference operators are not required for objects. All objects are handled by reference.
192 |
193 |
194 | ### Concatenation Spacing
195 | There should always be a space before and after the concatenation operator ('.'). For example:
196 |
197 | ```php
198 | $id = 1;
199 | echo JRoute::_('index.php?option=com_foo&task=foo.edit&id=' . (int) $id);
200 | ```
201 |
202 | If the concatenation operator is the first or last character on a line, both spaces are not required. For example:
203 |
204 | ```php
205 | $id = 1
206 | echo JRoute::_(
207 | 'index.php?option=com_foo&task=foo.edit&id=' . (int) $id
208 | . '&layout=special'
209 | );
210 | ```
211 |
212 | ### Arrays
213 |
214 | Assignments (the `=>` operator) in arrays may be aligned with spaces. When splitting array definitions onto several lines, the last value should also have a trailing comma. This is valid PHP syntax and helps to keep code diffs minimal. Joomla 3 prefers `array()` to be backward compatible to 5.3.10 and Joomla 4.0.0 onwards should use the short array syntax `[]` by default. (Short array syntax was introduced in PHP 5.4.)
215 |
216 | For example:
217 |
218 | ```php
219 | $options = [
220 | 'foo' => 'foo',
221 | 'spam' => 'spam',
222 | ];
223 |
224 | ```
225 |
226 | ### Code Commenting
227 |
228 | Inline comments to explain code follow the convention for C (`/* … */`) and C++ single line (`// ...`) comments. C-style blocks are generally restricted to documentation headers for files, classes and functions. The C++ style is generally used for making code notes. Code notes are strongly encouraged to help other people, including your future-self, follow the purpose of the code. Always provide notes where the code is performing particularly complex operations.
229 |
230 | Perl/shell style comments (`#`) are not permitted in PHP files.
231 |
232 | Blocks of code may, of course, be commented out for debugging purposes using any appropriate format, but should be removed before submitting patches for contribution back to the core code.
233 |
234 | For example, do not include feature submissions like:
235 |
236 | ```php
237 | // Must fix this code up one day.
238 | //$code = broken($fixme);
239 | ```
240 |
241 | More details on inline code comments can be found in the chapter on [Inline Code Comments](/coding-standards/inline-code-comments.html).
242 |
243 | #### Comment Docblocks
244 |
245 | Documentation headers for PHP and Javascript code in files, classes, class properties, methods and functions, called the docblocks, follow a convention similar to JavaDoc or phpDOC.
246 |
247 | These "DocBlocks" borrow from the PEAR standard but have some variations specific for Joomla and the Joomla Platform.
248 |
249 | More details on DocBlocks comments can be found in the chapter on [DocBlocks Comments](/coding-standards/docblocks.html).
250 |
251 | ### Function Calls
252 |
253 | Functions should be called with no spaces between the function name and the opening parenthesis, and no space between this and the first parameter; a space after the comma between each parameter (if they are present), and no space between the last parameter and the closing parenthesis. There should be space before and exactly one space after the equals sign. Tab alignment over multiple lines is permitted.
254 |
255 | ```php
256 | // An isolated function call.
257 | $foo = bar($var1, $var2);
258 |
259 | // Multiple aligned function calls.
260 | $short = bar('short');
261 | $medium = bar('medium');
262 | $long = bar('long');
263 | ```
264 |
265 | ### Function Definitions
266 |
267 | Function definitions start on a new line with no spaces between the function name and the opening parenthesis. Additionally, the opening and closing braces are also placed on new lines. An empty line should precede lines specifying the return value.
268 |
269 | Function definitions must include a documentation comment in accordance with the Commenting section of this document. More details on DocBlocks Function comments can be found in the chapter on [DocBlocks Comments](/coding-standards/docblocks.html).
270 |
271 | ```php
272 | /**
273 | * A utility function.
274 | *
275 | * @param string $path The library path in dot notation.
276 | *
277 | * @return void
278 | *
279 | * @since 1.6
280 | */
281 | function jimport($path)
282 | {
283 | // Body of method.
284 | }
285 | ```
286 |
287 | If a function definition goes over multiple lines, all lines must be indented with one tab and the closing brace must go on the same line as the last parameter.
288 |
289 | ```php
290 | function fooBar($param1, $param2,
291 | $param3, $param4)
292 | {
293 | // Body of method.
294 | }
295 | ```
296 |
297 | ### Closures / Anonymous functions
298 | Closures/Anonymous functions should have a space between the Closure's/Anonymous function's name and the opening parenthesis. Method signatures don't have the space.
299 |
300 | ```php
301 | $fieldIds = array_map(
302 | function ($f)
303 | {
304 | return $f->id;
305 | },
306 | $fields
307 | );
308 | ```
309 |
310 | ### Class Definitions
311 |
312 | Class definitions start on a new line and the opening and closing braces are also placed on new lines. Class methods must follow the guidelines for Function Definitions. Properties and methods must follow OOP standards and be declared appropriately (using public, protected, private and static as applicable).
313 |
314 | Class definitions, properties and methods must each be provided with a DocBlock in accordance with the following sections.
315 |
316 | More details on DocBlocks Class comments can be found in the chapter on [DocBlocks Comments](/coding-standards/docblocks.html).
317 |
318 | #### Class Property DocBlocks
319 |
320 | More details on Class Property DocBlocks can be found in the chapter on [DocBlocks Comments](docblocks.md).
321 |
322 | #### Class Method DocBlocks
323 |
324 | The DocBlock for class methods follows the same convention as for PHP functions.
325 |
326 | More details on DocBlocks Class Method comments can be found in the chapter on [DocBlocks Comments](docblocks.md).
327 |
328 | ### Class Definition Example
329 | ```php
330 | /**
331 | * A utility class.
332 | *
333 | * @package Joomla.Platform
334 | * @subpackage XBase
335 | * @since 1.6
336 | */
337 | class JClass extends JObject
338 | {
339 | /**
340 | * Human readable name
341 | *
342 | * @var string
343 | * @since 1.6
344 | */
345 | public $name;
346 |
347 | /**
348 | * Method to get the name of the class.
349 | *
350 | * @param string $case Optionally return in upper/lower case.
351 | *
352 | * @return boolean True if successfully loaded, false otherwise.
353 | *
354 | * @since 1.6
355 | */
356 | public function getName($case = null)
357 | {
358 | // Body of method.
359 | return $this->name;
360 | }
361 | }
362 | ```
363 |
364 | ### Naming Conventions
365 |
366 | #### Classes
367 |
368 | Classes should be given descriptive names. Avoid using abbreviations where possible. Class names should always begin with an uppercase letter and be written in CamelCase even if using traditionally uppercase acronyms (such as XML, HTML). One exception is for Joomla Platform classes which must begin with an uppercase 'J' with the next letter also being uppercase.
369 |
370 | For example:
371 |
372 | - JHtmlHelper
373 | - JXmlParser
374 | - JModel
375 |
376 | #### Functions and Methods
377 |
378 | Functions and methods should be named using the "studly caps" style (also referred to as "bumpy case" or "camel caps"). The initial letter of the name is lowercase, and each letter that starts a new "word" is capitalized. Function in the Joomla framework must begin with a lowercase 'j'.
379 |
380 | For example:
381 |
382 | - connect();
383 | - getData();
384 | - buildSomeWidget();
385 | - jImport();
386 | - jDoSomething();
387 |
388 | Private class members (meaning class members that are intended to be used only from within the same class in which they are declared) are preceded by a single underscore. Properties are to be written in underscore format (that is, logical words separated by underscores) and should be all lowercase.
389 |
390 | For example:
391 |
392 | ```php
393 | class JFooHelper
394 | {
395 | protected $field_name = null;
396 |
397 | private $_status = null;
398 |
399 | protected function sort()
400 | {
401 | // Code goes here
402 | }
403 | }
404 | ```
405 |
406 | #### Namespaces
407 |
408 | Namespaces are formatted according to this flow. First there is the file docblock followed by the namespace the file lives in. When required, the namespace is followed by the `defined` check. Lastly, the imported classes using the `use` keyword. All namespace imports must be alphabetically ordered.
409 |
410 | ```php
411 | /**
412 | * @package Joomla.Administrator
413 | * @subpackage mod_quickicon
414 | *
415 | * @copyright Copyright (C) 2005 - 2018 Open Source Matters, Inc. All rights reserved.
416 | * @license GNU General Public License version 2 or later; see LICENSE.txt
417 | */
418 |
419 | namespace Joomla\Module\Quickicon\Administrator\Helper;
420 |
421 | defined('_JEXEC') or die;
422 |
423 | use Joomla\CMS\Factory;
424 | use Joomla\CMS\Language\Text;
425 | use Joomla\CMS\Plugin\PluginHelper;
426 | use Joomla\CMS\Router\Route;
427 | use Joomla\Module\Quickicon\Administrator\Event\QuickIconsEvent;
428 | ```
429 |
430 | #### Constants
431 |
432 | Constants should always be all-uppercase, with underscores to separate words. Prefix constant names with the uppercase name of the class/package they are used in. For example, the constants used by the `JError` class all begin with `JERROR_`.
433 |
434 | #### Regular Variables and Class Properties
435 |
436 | Regular variables, follow the same conventions as function.
437 |
438 | Class variables should be set to null or some other appropriate default value.
439 |
440 | ### Exception Handling
441 |
442 | Exceptions should be used for error handling.
443 |
444 | The following sections outline how to semantically use [SPL exceptions](https://secure.php.net/manual/en/spl.exceptions.php).
445 |
446 | #### Logic Exceptions
447 |
448 | The LogicException is thrown when there is an explicit problem with the way the API is being used. For example, if a dependency has failed (you try to operate on an object that has not been loaded yet).
449 |
450 | The following child classes can also be used in appropriate situations:
451 |
452 | ##### BadFunctionCallException
453 |
454 | This exception can be thrown if a callback refers to an undefined function or if some arguments are missing. For example if `is_callable()`, or similar, fails on a function.
455 |
456 | ##### BadMethodCallException
457 |
458 | This exception can be thrown if a callback refers to an undefined method or if some arguments are missing. For example `is_callable()`, or similar, fails on a class method. Another example might be if arguments passed to a magic call method are missing.
459 |
460 | ##### InvalidArgumentException
461 |
462 | This exception can be thrown if there is invalid input.
463 |
464 | ##### DomainException
465 |
466 | This exception is similar to the InvalidArgumentException but can be thrown if a value does not adhere to a defined valid data domain. For example trying to load a database driver of type "mongodb" but that driver is not available in the API.
467 |
468 | ##### LengthException
469 |
470 | This exception can be thrown is a length check on an argument fails. For example a file signature was not a specific number of characters.
471 |
472 | ##### OutOfRangeException
473 |
474 | This exception has few practical applications but can be thrown when an illegal index was requested.
475 |
476 | #### Runtime Exceptions
477 |
478 | The RuntimeException is thrown when some sort of external entity or environment causes a problem that is beyond your control providing the input is valid. This exception is the default case for when the cause of an error can't explicitly be determined. For example you tried to connect to a database but the database was not available (server down, etc). Another example might be if an SQL query failed.
479 |
480 | ##### UnexpectedValueException
481 |
482 | This type of exception should be used when an unexpected result is encountered. For example a function call returned a string when a boolean was expected.
483 |
484 | ##### OutOfBoundsException
485 |
486 | This exception has few practical applications but may be thrown if a value is not a valid key.
487 |
488 | ##### OverflowException
489 |
490 | This exception has few practical applications but may be thrown when you add an element into a full container.
491 |
492 | ##### RangeException
493 |
494 | This exception has few practical applications but may be thrown to indicate range errors during program execution. Normally this means there was an arithmetic error other than under/overflow. This is the runtime version of DomainException.
495 |
496 | ##### UnderflowException
497 |
498 | This exception has few practical applications but may thrown when you try to remove an element of an empty container.
499 |
500 | #### Documenting exceptions
501 |
502 | Each function or method must annotate the type of exception that it throws using an @throws tag and any downstream exceptions types that are thrown. Each type of exception need only be annotated once. No description is necessary.
503 |
504 | ### SQL Queries
505 |
506 | SQL keywords are to be written in uppercase, while all other identifiers (with the exception of quoted text obviously) is to be in lowercase.
507 |
508 | All table names should use the `#__` prefix to access Joomla content and allow for the user defined database prefix to be applied. Queries should also use the JDatabaseQuery API. Tables should never have a static prefix such as `jos_`.
509 |
510 | To query our data source we can call a number of JDatabaseQuery methods; these methods encapsulate the data source's query language (in most cases SQL), hiding query-specific syntax from the developer and increasing the portability of the developer's source code.
511 |
512 | Use Query chaining to connect a number of query methods, one after the other, with each method returning an object that can support the next method, This improves readability and simplifies the resulting code. Since the Joomla Framework was introduced "query chaining" is now the recommended method for building database queries.
513 |
514 | Table names and table column names should always be enclosed in the `quoteName()` method to escape the table name and table columns.
515 | Field values checked in a query should always be enclosed in the `quote()` method to escape the value before passing it to the database. Integer field values checked in a query should also be type cast to `(int)`.
516 |
517 | ```php
518 | // Get the database connector.
519 | $db = JFactory::getDbo();
520 |
521 | // Get the query from the database connector.
522 | $query = $db->getQuery(true);
523 |
524 | // Build the query programatically (example with chaining)
525 | // Note: You can use the qn alias for the quoteName method.
526 | $query->select($db->qn('u.*'))
527 | ->from($db->qn('#__users', 'u'));
528 |
529 | // Tell the database connector what query to run.
530 | $db->setQuery($query);
531 |
532 | // Invoke the query or data retrieval helper.
533 | $users = $db->loadObjectList();
534 | ```
535 |
536 | #### Longer Chaining Example
537 | ```php
538 | // Using chaining when possible.
539 | $query->select($db->quoteName(array('user_id', 'profile_key', 'profile_value', 'ordering')))
540 | ->from($db->quoteName('#__user_profiles'))
541 | ->where($db->quoteName('profile_key') . ' LIKE '. $db->quote('\'custom.%\''))
542 | ->order('ordering ASC');
543 | ```
544 |
545 | #### Chaining With Select Array And Type Casting Of Integer Field Value Example
546 | ```php
547 | $query = $db->getQuery(true)
548 | ->select(array(
549 | $db->quoteName('profile_key'),
550 | $db->quoteName('profile_value'),
551 | ))
552 | ->from($db->quoteName('#__user_profiles'))
553 | ->where($db->quoteName('user_id') . ' = ' . (int) $userId)
554 | ->order($db->quoteName('ordering'));
555 | ```
556 |
--------------------------------------------------------------------------------
/manual/scss.md:
--------------------------------------------------------------------------------
1 | These guidelines have been assembled following an examination of emerging practices, ideas and existing styleguides, namely:
2 |
3 | 1. [Code Guide](http://codeguide.co) (by @mdo)
4 |
5 | ### Commenting
6 |
7 | #### Major sections
8 | Major code sections should be named in caps and within a full comment block, eg:
9 |
10 | ```scss
11 | // Major comment
12 | //
13 | // Major comment description goes here
14 | // and continues here
15 | ```
16 |
17 | #### Sub sections
18 | Subsections should be normally cased and within an open comment block.
19 | ```scss
20 | //
21 | // Sub section comment
22 | //
23 | ```
24 |
25 | #### Basic comments
26 | ```scss
27 | // Basic comment
28 | ```
29 |
30 | ### Class naming
31 | Use dashes to create compound class names:
32 |
33 | ```scss
34 | // Good - use dashes
35 | .compound-class-name {…}
36 |
37 | // Good - uses camelCase
38 | .compoundClassName {…}
39 |
40 | // Bad - uses underscores
41 | .compound_class_name {…}
42 |
43 | // Bad - does not use seperators
44 | .compoundclassname {…}
45 | ```
46 |
47 | ### Indentation
48 | Rules should be indented with 2 spaces:
49 |
50 | ```scss
51 | // Good
52 | .example {
53 | color: #000;
54 | visibility: hidden;
55 | }
56 |
57 | // Bad - using tabs or 4 spaces
58 | .example {
59 | color: #000;
60 | visibility: hidden;
61 | }
62 | ```
63 |
64 | SCSS should also be nested, with child selectors and rules indented again. Nested rules should also be spaced by one line:
65 |
66 | ```scss
67 | // Good
68 | .example {
69 |
70 | > li {
71 | float: none;
72 |
73 | + li {
74 | margin-top: 2px;
75 | margin-left: 0;
76 | }
77 |
78 | }
79 |
80 | }
81 |
82 | // Bad - nested rules indented with tab or 4 spaces
83 | .example {
84 |
85 | > li {
86 | float: none;
87 |
88 | + li {
89 | margin-top: 2px;
90 | margin-left: 0;
91 | }
92 |
93 | }
94 |
95 | }
96 | ```
97 |
98 | ### Alignment
99 | The opening brace must be on the same line as the last selector and preceded by a space. The closing brace must be on its own line after the last property and be indented to the same level as the opening brace.
100 |
101 | ```scss
102 | // Good
103 | .example {
104 | color: #fff;
105 | }
106 |
107 | // Bad - closing brace is in the wrong place
108 | .example {
109 | color: #fff;
110 | }
111 |
112 | // Bad - opening brace missing space
113 | .example{
114 | color: #fff;
115 | }
116 | ```
117 |
118 | ### Declaration order
119 | Related property declarations should be grouped together following the order:
120 |
121 | 1. Positioning
122 | 2. Box model
123 | 3. Typographic
124 | 4. Visual
125 |
126 | ```scss
127 | // Good
128 | .example {
129 | // Positioning
130 | position: absolute;
131 | top: 0;
132 | right: 0;
133 | bottom: 0;
134 | left: 0;
135 | z-index: 100;
136 |
137 | // Box-model
138 | display: block;
139 | float: right;
140 | width: 100px;
141 | height: 100px;
142 |
143 | // Typography
144 | font-family: Arial, sans-serif;
145 | font-size: 14px;
146 | line-height: 1.2;
147 | color: #333;
148 | text-align: center;
149 |
150 | // Visual
151 | background-color: #f5f5f5;
152 | border: 1px solid #e5e5e5;
153 | border-radius: 3px;
154 |
155 | // Misc
156 | opacity: 1;
157 | }
158 | ```
159 |
160 | Within each group, you'll also need to order the properties. If any mistakes are made, the compiler will notify you and provide the correct order
161 |
162 | ### Property Format
163 | Each property must be on its own line and indented one level. There should be no space before the colon and one space after. All properties must end with a semicolon.
164 |
165 | ```scss
166 | // Good
167 | .example {
168 | background: black;
169 | color: #fff;
170 | }
171 |
172 | // Bad - missing spaces after colons
173 | .example {
174 | background:black;
175 | color:#fff;
176 | }
177 |
178 | // Bad - missing last semicolon
179 | .example {
180 | background: black;
181 | color: #fff
182 | }
183 | ```
184 |
185 | ### HEX values
186 | HEX values must be declared in lowercase and shorthand:
187 |
188 | ```scss
189 | // Good
190 | .example {
191 | color: #eee;
192 | }
193 |
194 | // Bad
195 | .example {
196 | color: #EEEEEE;
197 | }
198 | ```
199 |
200 | ### Attribute selectors
201 | Always use double quotes around attribute selectors.
202 |
203 | ```scss
204 | // Good
205 | input[type="button"] {
206 | ...
207 | }
208 |
209 | // Bad - missing quotes
210 | input[type=button] {
211 | ...
212 | }
213 |
214 | // Bad - using single quote
215 | input[type='button'] {
216 | ...
217 | }
218 | ```
219 |
220 | ### Zero value units
221 | Zero values should not carry units.
222 |
223 | ```scss
224 | // Good
225 | .example {
226 | padding: 0;
227 | }
228 |
229 | // Bad - uses units
230 | .example {
231 | padding: 0px;
232 | }
233 | ```
234 |
235 | ### Prefixing properties
236 | There is no need to prefix properties, as this will be automatically taken care of when compiling your code
237 |
238 | ```scss
239 | // Good
240 | .example {
241 | transform: rotate(30px);
242 | }
243 |
244 | // Bad - uses prefix
245 | .example {
246 | -webkit-transform: rotate(30px);
247 | transform: rotate(30px);
248 | }
249 | ```
250 |
251 | ### End of file
252 | The end of the SCSS file should always have a blank line
253 |
254 | ```scss
255 | .example {
256 | padding: 0;
257 | }
258 | <<< Leave empty line here
259 | ```
260 |
--------------------------------------------------------------------------------
/manual/source-code-management.md:
--------------------------------------------------------------------------------
1 | Before we start talking about what Joomla! code should look like, it is appropriate to look at how and where the source code is stored. All serious software projects, whether driven by an Open Source community or developed within a company for proprietary purposes will manage the source code is some sort of source or version management system. The Joomla! project uses a Distributed Version Control System (DVCS) called Git hosted at [GitHub](https://github.com).
2 |
3 | ### The Joomla! Framework
4 |
5 | The [Joomla! Framework](https://github.com/joomla-framework) is a PHP framework that is designed to serve as a foundation for not only web applications (like a CMS) but other types of software such as command line applications. The files that form the Joomla! Framework are stored in a Distributed Version Control System (DVCS) called Git hosted at [GitHub](https://github.com).
6 |
7 | You can learn about how to get the Joomla Framework source code from the GitHub organisation, https://github.com/joomla-framework.
8 |
9 | Because Git treats the concepts of file revision numbers differently than Subversion, the repository revision number is not required in files (that is, the `@version` tag is not necessary).
10 |
11 | ### The Joomla! CMS
12 |
13 | The [Joomla! CMS](https://github.com/joomla/joomla-cms) is a Content Management System (CMS) which enables you to build Web sites and powerful online applications. It's a free and OpenSource software, distributed under the GNU General Public License version 2 or later. The files that form the Joomla! CMS are stored in a Distributed Version Control System (DVCS) called Git hosted at [GitHub](https://github.com).
14 |
15 | You can learn about how to get the Joomla CMS source code from the Git repository, https://github.com/joomla/joomla-cms.
16 |
17 | Because Git treats the concepts of file revision numbers differently than Subversion, the repository revision number is not required in files (that is, the `@version` tag is not necessary).
18 |
19 | ### Compliance Tool
20 |
21 | The standards in this manual have been adopted across the Joomla project, including the [Joomla! Framework](https://github.com/joomla-framework), the [Joomla! CMS](https://github.com/joomla/joomla-cms) and any other applications or extensions maintained by the project. These standards apply to source code, tests and (where applicable) documentation.
22 |
23 | A custom Joomla sniff standard for PHP files is maintained by the Joomla! project and available from the [coding standards](https://github.com/joomla/coding-standards) repository. The Sniff is based on the standard outlined in this document. For more information about how code standards are enforced see the analysis appendix of the manual. For information on using the Sniff see the documentation stored in its repository.
24 |
--------------------------------------------------------------------------------
/manual/version.md:
--------------------------------------------------------------------------------
1 | Version 1.0
--------------------------------------------------------------------------------
/manual/xml.md:
--------------------------------------------------------------------------------
1 | ### Attributes
2 |
3 | * Each attribute is on its own line.
4 | * The four attributes `name`, `type`, `label` and `description` should be written in this order and at the top of the element definition.
5 |
6 | ### Closing Elements
7 |
8 | Elements should be closed with the closing tag on a new line.
9 |
10 | #### Exception
11 |
12 | When the element only has few attributes, then the whole element can stay on the same line. A max line length of 100 characters is recommended for good reading.
13 |
14 | ### Examples
15 |
16 | #### Element is **empty**:
17 | ```xml
18 |
24 | ```
25 |
26 | #### Element is **not empty**:
27 | ```xml
28 |
34 |
35 |
36 |
37 |
38 |
44 |
50 |
53 |
54 | ```
55 |
56 | #### Element with only a few attributes
57 |
58 | ```xml
59 |
60 | ```
61 |
--------------------------------------------------------------------------------
/notes.txt:
--------------------------------------------------------------------------------
1 | ==========
2 | The Joomla coding-standards for PHP_CodeSniffer has been derived from the Generic, PEAR, Squiz, PSR2, and Zend standards.
3 | Differences are noted below.
4 | ==========
5 |
6 | ruleset.xml
7 | - Increased notional limit to 150 chars.
8 | - Include/exclude additional sniffs from various standards (see file for specifics)
9 |
10 | Classes/InstantiateNewClassesSniff.php
11 | Classes/MemberVarScopeSniff.php
12 | Classes/MethodScopeSniff.php
13 | Classes/StaticThisUsageSniff.php
14 |
15 | Commenting/ClassCommentSniff.php
16 | - Added tags to check (copyright, etc not required in classes).
17 | - @package tag optional.
18 | Commenting/FileCommentSniff.php
19 | - If not short description is provided then the blank line check is not done.
20 | - Removed check on subpackage name in processSubpackage
21 | - Removed space checking after @ tags in processTags
22 | - Allowed any characters to appear before the copyright year in processCopyrights
23 | - @package tag optional.
24 | Commenting/FunctionCommentSniff.php
25 | - Remove check for one space before var type.
26 | - Remove check for 1 space after the longest type.
27 | - Remove check for 1 space after the variable name.
28 | - Remove check for variable name alignment.
29 | - Remove check for variable comment alignment.
30 | Commenting/SingleCommentSniff.php
31 |
32 | ControlStructures/ControlSignatureSniff.php
33 | ControlStructures/ElseIfDeclarationSniff.php
34 | - based on PSR2.ControlStructures.ElseIfDeclaration
35 | - Changed from WARNING to ERROR
36 | ControlStructures/InlineControlStructureSniff.php
37 | - Changed from WARNING to ERROR
38 | - Added exception if the file is a layout (ie, under a /tmpl/ folder).
39 | ControlStructures/MultiLineConditionSniff.php
40 | ControlStructures/WhiteSpaceBeforeSniff.php
41 |
42 | Functions/FunctionCallSignatureSniff.php
43 | Functions/FunctionDeclarationSniff.php
44 | Functions/StatementNotFunctionSniff.php
45 |
46 | NamingConventions/ValidFunctionNameSniff.php
47 | NamingConventions/ValidVariableNameSniff.php
48 |
49 | PHP/LowerCaseConstantSniff.php
50 | - Based on Generic.PHP.LowerCaseConstantSniff
51 |
52 | WhiteSpace/CastSpacingSniff.php
53 | - Squiz.WhiteSpace.CastSpacing
54 | WhiteSpace/ConcatenationSpacingSniff.php
55 | WhiteSpace/ControlStructureSpacingSniff.php
56 | WhiteSpace/DisallowSpaceIndentSniff.php
57 | - Based on Generic.WhiteSpace.DisallowSpaceIndent
58 | WhiteSpace/MemberVarSpacingSniff.php
59 | - Based on Squiz.WhiteSpace.MemberVarSpacing
60 | WhiteSpace/ObjectOperatorIndentSniff.php
61 | - Based on PEAR.WhiteSpace.ObjectOperatorIndent
62 | WhiteSpace/OperatorSpacingSniff.php
63 | WhiteSpace/SemicolonSpacingSniff.php
64 | - Based on Squiz.WhiteSpace.SemicolonSpacing
65 | WhiteSpace/SpaceAfterCastSniff.php
66 | WhiteSpace/SuperfluousWhitespaceSniff.php
67 |
--------------------------------------------------------------------------------