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

Add sniff for Service Contracts #159

Open
kanduvisla opened this issue Nov 13, 2019 · 1 comment
Open

Add sniff for Service Contracts #159

kanduvisla opened this issue Nov 13, 2019 · 1 comment
Labels
proposal New rule proposal

Comments

@kanduvisla
Copy link

Rule

According to this page there are some very specific rules for service contracts. For example:

  • Valid object types include a fully qualified class name or a fully qualified interface name.
  • Any parameters or return values of type array can be denoted by following any of the previous types by an empty set of square brackets []

Wouldn't it make sense to have a sniff for these things?

Reason

I come across a lot of service contracts that don't include FQCN and/or have an array return type instead of FQCN[]. This goes against the rules set by Magento and might also break future (web api) implementations (due to reflection).

Implementation

Not sure at this moment how to implement this, but it seems to me that this can be done with a new sniff.

@kanduvisla kanduvisla added the proposal New rule proposal label Nov 13, 2019
@kanduvisla
Copy link
Author

kanduvisla commented Nov 13, 2019

This is a small POC for a FQCN in the method signature:

use PHP_CodeSniffer\Files\File;
use PHP_CodeSniffer\Sniffs\Sniff;

class ServiceContractSniff implements Sniff
{
    private const NON_OBJECTS = [
        'int',
        'integer',
        'string',
        'bool',
        'boolean',
        'float',
        'array',
        'object',
        'resource',
    ];

    public function register()
    {
        return [
            T_INTERFACE,
        ];
    }

    public function process(File $phpcsFile, $stackPtr)
    {
        $tokens = $phpcsFile->getTokens();
        if (preg_match('/.*\/Api\/(Data\/)?.*/', $phpcsFile->getFilename()) === 1) {
            foreach ($tokens as $token) {
                if ($token['type'] === 'T_FUNCTION') {
                    for ($index = $token['parenthesis_opener'] + 1; $index < $token['parenthesis_closer']; $index += 1) {
                        if ($tokens[$index]['type'] === 'T_STRING') {
                            $type = $tokens[$index]['content'];
                            if (!in_array($type, self::NON_OBJECTS)) {
                                if (strpos($type, '\\') !== 0 && !class_exists($type)) {
                                    $phpcsFile->addError(
                                        'Parameter "%s" should be referenced as a fully qualified class name',
                                        $stackPtr,
                                        'Found',
                                        $type
                                    );
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}

Disclaimer: this is in conjunction with the SlevomatCodingStandard.Namespaces.FullyQualifiedClassNameInAnnotation sniff restricted to the Api-folder

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
proposal New rule proposal
Projects
None yet
Development

No branches or pull requests

1 participant