Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Warning for using include or require #67

Merged
merged 2 commits into from Oct 22, 2016
Merged

Warning for using include or require #67

merged 2 commits into from Oct 22, 2016

Conversation

khacoder
Copy link
Contributor

Issue #66
Check if include(_once) or require(_once) is used, and issue a warning to see if get_template_part() or locate_template() is more appropriate.

if ( 'functions.php' !== $fileName ) {
foreach ( $checks as $check ) {
if ( false !== strpos( $token['content'], $check ) ) {
$phpcsFile->addWarning( 'The theme appears to use include or require. If these are being used to include separate sections of a template from independent files, then <strong>get_template_part()</strong> should be used instead.' , $stackPtr, 'FileIncludeCheck' );
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

'Check that ' . $check . ' is not being used to load template files. <strong>get_template_part()</strong> should be used to load template files.'


$fileName = basename( $phpcsFile->getFileName() );

$checks = array(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be good to rename the variable to make it clearer like $includes

$fileName = basename( $phpcsFile->getFileName() );

$checks = array(
'include"',
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there supposed to be a " at the end?

* @package PHP_CodeSniffer
* @author khacoder
*/
class WordPress_Sniffs_Theme_FileIncludeSniff extends WordPress_AbstractThemeSniff {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this class need to extend the WordPress_AbstractThemeSniff?

@grappler grappler force-pushed the feature/theme-review-sniffs branch 2 times, most recently from 563cd1d to 6671823 Compare September 27, 2016 12:28

$fileName = basename( $phpcsFile->getFileName() );

$checks = array(
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This array can be removed. Just like the foreach/strpos below.

You are sniffing for the correct tokens, so no need to check their content.

);

if ( 'functions.php' !== $fileName ) {
foreach ( $checks as $check ) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need for this foreach nor for the strpos()

* @category PHP
* @package PHP_CodeSniffer
* @link https://make.wordpress.org/core/handbook/best-practices/coding-standards/
*/
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please update the doc block to comply with the current standards.

* @category PHP
* @package PHP_CodeSniffer
* @author khacoder
*/
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please update the doc block to comply with the current standards.

* @category PHP
* @package PHP_CodeSniffer
* @link https://make.wordpress.org/core/handbook/best-practices/coding-standards/
*/
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please update the doc block to comply with the current standards.

* @category PHP
* @package PHP_CodeSniffer
* @author khacoder
*/
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please update the doc block to comply with the current standards.

* should represent the number of errors that should occur on that line.
*
* @return array(int => int)
*/
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please update the doc block to comply with the current standards.

* should represent the number of warnings that should occur on that line.
*
* @return array(int => int)
*/
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please update the doc block to comply with the current standards.

'require_once',
);

if ( 'functions.php' !== $fileName ) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would make functions.php a protected property in the form of an array ( array( 'functions.php' => true, ) ). That way if at some point other files should be excluded, the sniff is already prepared for that.

You can then change this to a ! isset().

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't fully understand what you mean with ! isset().

I would have done

$files = array(
    'functions.php',
);
if ( in_array( $fileName, $files ) ) {

}

Copy link

@jrfnl jrfnl Oct 12, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are two reasons for this comment:

  1. Other similar arrays in WPCS already follow the pattern I described, so it's better to stay in line with that.
  2. The reason WPCS does this is code-technical. isset() is a language construct which is blazing fast. in_array() is a function call. So to leverage ìsset(), the array key needs to be what you are actually looking for, which is why you'd use an array pattern like this:
$class_property = array(
    'functions.php' => true,
);

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you share how the if statement should be?

Copy link

@jrfnl jrfnl Oct 12, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Of course - as in this case we want to show the error if the file is not in the file whitelist:

if ( ! isset( $this->class_property[ $filename ] ) ) {
    // Show error.
}

For the property name, $file_whitelist might be a good one ;-)

*/
public function register() {
return array(
T_REQUIRE,
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One more: you probably should use PHP_CodeSniffer_Tokens::$includeTokens here. You can just straight return it.

@grappler
Copy link
Member

I have made the requested changes.

@jrfnl
Copy link

jrfnl commented Oct 13, 2016

@grappler Nearly there.

$file_blacklist is now still a variable within the function while it does not need to be redefined every time the function is called, it doesn't change between function calls after all, so it should be a class property which is defined only once (if we could use PHP 5.6 we could even make it a class constant, unfortunately arrays can not be used with class constants until then).

Secondly, it is not a blacklist, but a whitelist. If the file name is in the whitelist of files which are logical places/in which a require/include is allowed to exist, no warning will be thrown.

Issue #66
Check for use of include or require and if used issue a warning to check if get_template_part() is more appropriate.
@grappler
Copy link
Member

I hope it is all good now 😄

*
* @var array
*/
public $file_whitelist = array(
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The property should have either protected or private as visibility as any properties which are public in a PHPCS sniff can be changed/overruled from the ruleset.

I can imagine a situation where we would allow people to add more files, but in that case, this would still need to be a protected/private property and we would add a $custom_whitelist property which people could pass via the ruleset and which would then be merged.

*
* @var array
*/
public $supportedTokenizers = array(
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need to change this, but as a general remark - I believe the default in PHPCS is PHP and adding the property is only needed when you want to sniff JS/CSS or a combination of these, though I'd have to double check the default to be sure.
(If it is the default, then there is no need for the property)

$file_name = basename( $phpcsFile->getFileName() );

if ( ! isset( $this->file_whitelist[ $file_name ] ) ) {
$phpcsFile->addWarning( 'Check that ' . $token['content'] . ' is not being used to load template files. <strong>get_template_part()</strong> should be used to load template files.' , $stackPtr, 'FileIncludeFound' );
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Must have missed this earlier. Sorry.
The addWarning()/addError() methods have native sprintf() functionality build in. To use it all you need to do is use the normal %s placeholders in the error message and pass an array of replacements as the fourth parameter to the methods.
Also: as the output is generally command line, using HTML in the error message is confusing.

Like so:

$phpcsFile->addWarning(
     'Check that %s is not being used to load template files. "get_template_part()" should be used to load template files.' ,
    $stackPtr,
    'FileIncludeFound',
    array( $token['content'] )
);

include('/file.ext');
include_once('/file.ext');
require('/file.ext');
require_once('/file.ext');
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

include and require are language constructs and do not need parenthesis, so it might be good to have some examples with more syntax variations:

include dirname( __FILE__ ) . '/myfile.php';
require_once $path_to_file;

@jrfnl
Copy link

jrfnl commented Oct 13, 2016

Nearly there, just dotting the i's now...

@grappler
Copy link
Member

Getting closer minute by minute.

@grappler grappler self-assigned this Oct 17, 2016
*/
public function process( PHP_CodeSniffer_File $phpcsFile, $stackPtr ) {
$tokens = $phpcsFile->getTokens();
$token = $tokens[ $stackPtr ];
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You don't need those two variables until line 55, so they could go into the if instead of always being created.

@jrfnl jrfnl merged commit d660bf8 into WPTT:feature/theme-review-sniffs Oct 22, 2016
@grappler grappler mentioned this pull request Dec 3, 2016
4 tasks
@jrfnl jrfnl added this to the 0.1.0 milestone Aug 20, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants