├── .gitignore ├── .travis.yml ├── .travis └── deploy_rsa_encrypted ├── Extdn ├── Samples │ ├── Blocks │ │ ├── DeprecatedFormContainerParent.php │ │ ├── DeprecatedFormGenericParent.php │ │ └── SetTemplateInBlock.php │ ├── Classes │ │ └── StrictTypes.php │ └── Templates │ │ └── objectmanager.phtml ├── Sniffs │ ├── Blocks │ │ ├── DeprecatedParentsSniff.md │ │ ├── DeprecatedParentsSniff.php │ │ ├── SetTemplateInBlockSniff.md │ │ └── SetTemplateInBlockSniff.php │ ├── Classes │ │ ├── StrictTypesSniff.md │ │ └── StrictTypesSniff.php │ └── Templates │ │ ├── TemplateObjectManagerSniff.md │ │ └── TemplateObjectManagerSniff.php ├── Tests │ ├── Blocks │ │ ├── SetTemplateInBlockUnitTest.inc │ │ └── SetTemplateInBlockUnitTest.php │ ├── Classes │ │ ├── StrictTypesUnitTest.1.inc │ │ ├── StrictTypesUnitTest.2.inc │ │ ├── StrictTypesUnitTest.3.inc │ │ └── StrictTypesUnitTest.php │ └── Templates │ │ ├── TemplateObjectManagerUnitTest.1.phtml │ │ ├── TemplateObjectManagerUnitTest.2.phtml │ │ └── TemplateObjectManagerUnitTest.php ├── Utils │ ├── Reflection.php │ └── TestPattern.php └── ruleset.xml ├── ISSUE_TEMPLATE.md ├── MEQP2 └── Sniffs │ └── Templates │ └── ThisInTemplateSniff.md ├── PULL_REQUEST_TEMPLATE.md ├── README.md ├── composer.json ├── docs └── rule-documentation-template.md ├── grumphp.yml ├── phpcs.xml.dist ├── phpunit-vendor.xml └── phpunit.xml.dist /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | .php_cs.cache 3 | /phpunit.xml 4 | /vendor 5 | /composer.lock 6 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: php 2 | php: 3 | - 7.0 4 | - 7.1 5 | - 7.2 6 | env: 7 | matrix: 8 | - COMPOSER_PREF="--prefer-lowest" 9 | - COMPOSER_PREF="" 10 | before_install: 11 | - ssh-keygen -N "" -f ~/.ssh/id_rsa 12 | # - openssl aes-256-cbc -K $encrypted_2b7e0505597a_key -iv $encrypted_2b7e0505597a_iv -in .travis/deploy_rsa_encrypted -out ~/.ssh/id_rsa -d 13 | - chmod 600 ~/.ssh/id_rsa 14 | install: composer update --no-interaction --prefer-source $COMPOSER_PREF 15 | script: 16 | - vendor/bin/phpunit 17 | -------------------------------------------------------------------------------- /.travis/deploy_rsa_encrypted: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/extdn/extdn-phpcs/f5209244131d82be9b6b7621bf89aa95039d408b/.travis/deploy_rsa_encrypted -------------------------------------------------------------------------------- /Extdn/Samples/Blocks/DeprecatedFormContainerParent.php: -------------------------------------------------------------------------------- 1 | setTemplate('foobar.phtml'); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /Extdn/Samples/Classes/StrictTypes.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /Extdn/Sniffs/Blocks/DeprecatedParentsSniff.md: -------------------------------------------------------------------------------- 1 | # Rule: Do not extend from deprecated block parents 2 | ## Background 3 | Some parent classes have been deprecated in Magento 2.2 and should therefore no longer be used in code: 4 | - `Magento\Backend\Block\Widget\Form\Generic` 5 | - `Magento\Backend\Block\Widget\Grid\Container` 6 | 7 | ## Reasoning 8 | Once a Block class is extending upon one of these deprecated parents, they should be refactored into something else instead. Ideally, this is a uiComponent. 9 | The main reason why a uiComponent is preferred over a regular Block-driven output, is that a uiComponent is much more extensible than Blocks. 10 | 11 | ## How it works 12 | This rule uses PHP Reflection to determine the class its parent and then checks whether the parent matches a deprecated parent. 13 | 14 | ## How to fix 15 | The Block class should ideally be removed. Instead, a uiComponent should be created instead, consisting of an XML file in the `ui_component` folder plus PHP sources. 16 | -------------------------------------------------------------------------------- /Extdn/Sniffs/Blocks/DeprecatedParentsSniff.php: -------------------------------------------------------------------------------- 1 | getFilename()); 48 | } 49 | 50 | $class = Reflection::getClass($className); 51 | $parentClass = $class->getParentClass(); 52 | 53 | if (!$parentClass) { 54 | return; 55 | } 56 | 57 | foreach ($this->getDeprecatedClasses() as $deprecatedClass) { 58 | if ($parentClass->getName() !== $deprecatedClass['class']) { 59 | continue; 60 | } 61 | 62 | $warning = sprintf('Block parent "%s" is deprecated. %s', $deprecatedClass['class'], $deprecatedClass['advice']); 63 | $phpcsFile->addWarning($warning, null, 'deprecated-parent'); 64 | } 65 | } 66 | 67 | /** 68 | * @return array 69 | */ 70 | private function getDeprecatedClasses(): array 71 | { 72 | $url = 'https://github.com/extdn/extdn-phpcs/blob/master/Extdn/Sniffs/Blocks/DeprecatedParentsSniff.md'; 73 | 74 | return [ 75 | [ 76 | 'class' => 'Magento\Backend\Block\Widget\Form\Generic', 77 | 'advice' => 'See '.$url 78 | ], 79 | [ 80 | 'class' => 'Magento\Backend\Block\Widget\Grid\Container', 81 | 'advice' => 'See '.$url 82 | ] 83 | ]; 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /Extdn/Sniffs/Blocks/SetTemplateInBlockSniff.md: -------------------------------------------------------------------------------- 1 | # Rule: Do not use setTemplate in Block classes 2 | ## Background 3 | When creating a Block class, a Block class could set its PHTML template in multiple ways: Through XML layout, through a 4 | call to `$this->setTemplate()` and through a variable `$_template`. The new design of Block classes is to configure them 5 | at constructor time, meaning that configuration options (like the template) are added using constructor arguments. This 6 | allows for the XML layout to change the template. The template in the Block class is then only defined as a default value, 7 | if the XML layout is not overriding the template: This default value is best defined via a protected variable 8 | `$_template`. 9 | 10 | ## Reasoning 11 | 12 | If `$this->setTemplate()` is used instead, this could lead to potential issues: First of all, setters are deprecated in 13 | Block classes (because constructor arguments should be preferred instead). Second, if `$this->setTemplate()` is added to 14 | the constructor *after* calling upon the parent constructor, it would undo the configuration via XML layout. Simply put: 15 | It is outdated and leads to issues quickly. 16 | 17 | ## How it works 18 | This rule checks whether a Block class uses `$this->setTemplate()`. 19 | 20 | ## How to fix 21 | 22 | If there is a match, the preferred way of optimizing your code would be as follows: 23 | 24 | class MyBlock extends Template 25 | { 26 | protected $_template = 'foobar.phtml'; 27 | } 28 | 29 | -------------------------------------------------------------------------------- /Extdn/Sniffs/Blocks/SetTemplateInBlockSniff.php: -------------------------------------------------------------------------------- 1 | setTemplate() in Block classes.'; 23 | 24 | /** 25 | * @var array 26 | */ 27 | public $supportedTokenizers = ['PHP']; 28 | 29 | /** 30 | * @return array|int[] 31 | */ 32 | public function register() 33 | { 34 | return [T_CLASS]; 35 | } 36 | 37 | /** 38 | * @param File $phpcsFile 39 | * @param int $stackPtr 40 | * @return int|void 41 | */ 42 | public function process(File $phpcsFile, $stackPtr) 43 | { 44 | $tokens = $phpcsFile->getTokens(); 45 | 46 | foreach ($tokens as $line => $token) { 47 | if ($this->hasTokenMatch($token) === false) { 48 | continue; 49 | } 50 | 51 | $error = $this->message . ' Found: %s'; 52 | $phpcsFile->addWarning($error, $line, 'Found', $token); 53 | } 54 | } 55 | 56 | private function hasTokenMatch(array $token): bool 57 | { 58 | if ($token['content'] !== 'setTemplate') { 59 | return false; 60 | } 61 | 62 | return true; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /Extdn/Sniffs/Classes/StrictTypesSniff.md: -------------------------------------------------------------------------------- 1 | # Rule: Add `declare(strict_types=1)` to your PHP files 2 | ## Background 3 | With PHP 7, it is possible to add type hinting to your code. However, this doesn't mean that types are actually enforced, unless strict typing is 4 | enabled by adding `declare(strict_types=1)` to the top of each PHP file. 5 | 6 | ## Reasoning 7 | PHP code becomes more robust when type hinting (argument types, return types) are added. With the `declare(strict_types=1)` added, there is less 8 | chance for bugs that related to type casting. 9 | 10 | ## How it works 11 | This rule scans the source code to see whether a line `declare(strict_type=1)` occurs or not. 12 | 13 | ## How to fix 14 | Simply add a statement `declare(strict_types=1)` to the top of your files: 15 | 16 | getTokens(); 45 | $hasDeclareStrictTypes = false; 46 | 47 | $declarePosition = $phpcsFile->findNext([T_DECLARE], 0); 48 | if ($declarePosition !== false) { 49 | $lineEnd = $phpcsFile->findNext([T_SEMICOLON], $declarePosition); 50 | 51 | // extract all tokens between declare and line end 52 | $tokens = \array_slice($tokens, $declarePosition, $lineEnd - 1); 53 | $hasDeclareStrictTypes = $this->hasDeclareStrictTypes($tokens); 54 | } 55 | 56 | if ($hasDeclareStrictTypes === false) { 57 | $error = $this->message . ' Not Found'; 58 | $phpcsFile->addWarning($error, null, 'NotFound'); 59 | } 60 | } 61 | 62 | /** 63 | * Checks has the File with strict_types=1 64 | * 65 | * @param array $tokens 66 | * @param $start 67 | * @return bool 68 | */ 69 | private function hasDeclareStrictTypes(array $tokens): bool 70 | { 71 | $containsStrictType = false; 72 | $isEnabled = false; 73 | 74 | foreach ($tokens as $token) { 75 | if ($token['code'] === T_STRING && $token['content'] === 'strict_types') { 76 | $containsStrictType = true; 77 | } 78 | 79 | if ($token['code'] === T_LNUMBER && $token['content'] === '1') { 80 | $isEnabled = true; 81 | } 82 | } 83 | 84 | return $containsStrictType && $isEnabled; 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /Extdn/Sniffs/Templates/TemplateObjectManagerSniff.md: -------------------------------------------------------------------------------- 1 | # Rule: Do not use the object manager in templates 2 | ## Background 3 | The Object Manager is responsible to create concrete objects for a required interface, and to generate code e.g. for adding plugins, factories, proxies. 4 | It is used transparently by requesting a class/interface name as constructor dependency or in layout XML. 5 | 6 | You can use it directly with `ObjectManager::getInstance()->get(SomeInterface::class)` and `ObjectManager::getInstance()->create(SomeInterface::class)`, but this is not encouraged. 7 | 8 | ## Reasoning 9 | Magento offers an extensive system for dependency injection which allows us to access and create objects. It also makes it 10 | very clear, which classes or interfaces are needed by a particular piece of code and forces the developer to re-evaluate 11 | the design if there are too many. 12 | 13 | This dependency injection system uses the object manager, but it is an implementation detail that should stay hidden. 14 | Bypassing this system leads to hidden dependencies and potentially to too many of them. 15 | 16 | Besides, for separation of appearance and logic, a template should contain as little and uncomplex PHP code as possible. 17 | 18 | ## How it works 19 | For all PHTML files, the sniff looks for string tokens "ObjectManager". 20 | 21 | ## How to fix 22 | Given, your template contains code like this: 23 | 24 | ```php 25 | get(\Choo\Choo::class); 27 | ``` 28 | 29 | 1. if the template is accompanied by a custom block, you can add the dependency to the block: 30 | 31 | ```php 32 | choo = $choo; 45 | } 46 | 47 | public function getChoo(): Choo\Choo 48 | { 49 | return $this->choo; 50 | } 51 | 52 | } 53 | ``` 54 | 55 | and change the template to 56 | 57 | ```php 58 | getChoo(); 60 | ``` 61 | 2. Starting with Magento 2.2, **view models** are considered a better alternative to blocks. Add a view model, or use an existing one, 62 | and add the dependency there: 63 | 64 | ```php 65 | choo = $choo; 78 | } 79 | 80 | public function getChoo(): Choo\Choo 81 | { 82 | return $this->choo; 83 | } 84 | 85 | } 86 | ``` 87 | 88 | The view model is added to the block via layout XML: 89 | 90 | ```xml 91 | 92 | 93 | Extdn\Example\TheViewModel 94 | 95 | 96 | ``` 97 | 98 | and can be used in the template like this: 99 | 100 | ```php 101 | getData('the_view_model'); 103 | $choo = $theViewModel->getChoo(); 104 | ``` 105 | -------------------------------------------------------------------------------- /Extdn/Sniffs/Templates/TemplateObjectManagerSniff.php: -------------------------------------------------------------------------------- 1 | getTokens(); 41 | $fileName = $phpcsFile->getFileName(); 42 | $extension = substr($fileName, strrpos($fileName, '.')); 43 | 44 | if (\in_array($extension, $this->templateExtensionList, false) === false) { 45 | return; 46 | } 47 | 48 | foreach ($tokens as $line => $token) { 49 | if ($this->hasTokenMatch($token) === false) { 50 | continue; 51 | } 52 | 53 | $error = $this->message . ' Found: %s'; 54 | $phpcsFile->addError($error, $line, 'Found', $token); 55 | } 56 | } 57 | 58 | 59 | public function hasTokenMatch($token) 60 | { 61 | if ($token['content'] !== 'ObjectManager') { 62 | return false; 63 | } 64 | 65 | return true; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /Extdn/Tests/Blocks/SetTemplateInBlockUnitTest.inc: -------------------------------------------------------------------------------- 1 | setTemplate('foobar.phtml'); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /Extdn/Tests/Blocks/SetTemplateInBlockUnitTest.php: -------------------------------------------------------------------------------- 1 | 1]; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Extdn/Tests/Classes/StrictTypesUnitTest.1.inc: -------------------------------------------------------------------------------- 1 | 1]; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Extdn/Tests/Templates/TemplateObjectManagerUnitTest.1.phtml: -------------------------------------------------------------------------------- 1 |
2 | 5 |
-------------------------------------------------------------------------------- /Extdn/Tests/Templates/TemplateObjectManagerUnitTest.2.phtml: -------------------------------------------------------------------------------- 1 | get(\Magento\Customer\Model\Session::class); -------------------------------------------------------------------------------- /Extdn/Tests/Templates/TemplateObjectManagerUnitTest.php: -------------------------------------------------------------------------------- 1 | 1]; 20 | } 21 | 22 | /** 23 | * @inheritdoc 24 | */ 25 | protected function getWarningList() 26 | { 27 | return []; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Extdn/Utils/Reflection.php: -------------------------------------------------------------------------------- 1 | getConstructor(); 38 | if (empty($constructor)) { 39 | return []; 40 | } 41 | 42 | $parameters = $constructor->getParameters(); 43 | if (empty($parameters)) { 44 | return []; 45 | } 46 | 47 | $dependencyClasses = []; 48 | foreach ($parameters as $parameter) { 49 | $dependencyClass = $parameter->getClass(); 50 | if (empty($dependencyClass)) { 51 | continue; 52 | } 53 | 54 | $dependencyClasses[] = $dependencyClass; 55 | } 56 | 57 | return $dependencyClasses; 58 | 59 | } catch (ReflectionException $reflectionException) { 60 | return []; 61 | } 62 | } 63 | 64 | /** 65 | * @param File $phpcsFile 66 | * 67 | * @return string 68 | */ 69 | static public function findClassName(File $phpcsFile): string 70 | { 71 | $tokens = $phpcsFile->getTokens(); 72 | 73 | $namespaceParts = []; 74 | $namespaceFound = false; 75 | $className = ''; 76 | $classFound = false; 77 | 78 | foreach ($tokens as $token) { 79 | if (!is_array($token)) { 80 | continue; 81 | } 82 | 83 | if ($token['type'] == 'T_NAMESPACE') { 84 | $namespaceFound = true; 85 | continue; 86 | } else if ($namespaceFound && $token['type'] == 'T_STRING') { 87 | $namespaceParts[] = $token['content']; 88 | continue; 89 | } else if ($namespaceFound && $token['type'] == 'T_SEMICOLON') { 90 | $namespaceFound = false; 91 | continue; 92 | } 93 | 94 | if ($token['type'] == 'T_CLASS') { 95 | $classFound = true; 96 | continue; 97 | } else if ($classFound && $token['type'] == 'T_STRING') { 98 | $className = $token['content']; 99 | $classFound = false; 100 | continue; 101 | } 102 | } 103 | 104 | if (!$className) { 105 | return ''; 106 | } 107 | 108 | $className = implode('\\', $namespaceParts) . "\\$className"; 109 | 110 | return $className; 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /Extdn/Utils/TestPattern.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | Magento 2 Additional Rules by ExtDN 4 | 5 | 6 | 7 | *.php 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | ### Rule 5 | 6 | 7 | ### Reason 8 | 9 | 10 | ### Implementation 11 | 12 | -------------------------------------------------------------------------------- /MEQP2/Sniffs/Templates/ThisInTemplateSniff.md: -------------------------------------------------------------------------------- 1 | # Rule: Do not use `$this` in templates 2 | ## Background 3 | In PHTML templates, the current block is available as `$this` and `$block`. The alternative with `$this` has been deprecated and should not be used anymore. 4 | 5 | ## Reasoning 6 | `$this` in templates is a legacy from Magento 1. It still works, however this can change any time, should templates and blocks be further decoupled. That's why for new code you should always use `$block` and restrict it to public methods. 7 | 8 | ## How it works 9 | Any occurence of `$this` in PHTML files (via file pattern in ruleset.xml) raises a warning. 10 | 11 | ## How to fix 12 | 13 | Replace `$this` with `$block`. If you use private or protected methods, make them public. -------------------------------------------------------------------------------- /PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ### Description 2 | 3 | 4 | ### Related issues 5 | 6 | 1. extdn/extdn-phpcs#: Issue title 7 | 2. ... 8 | 9 | 10 | ### Sniff checklist 11 | - [ ] Sniff is accompanied by unit test 12 | - [ ] Sniff is documented using the [documentation template](docs/rule-documentation-template.md) (FooSniff.md next to FooSniff.php) -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ExtDN PHP_CodeSniffer rules for Magento 2 2 | 3 | [![Build Status](https://travis-ci.org/extdn/extdn-phpcs.svg?branch=master)](https://travis-ci.org/extdn/extdn-phpcs) 4 | 5 | ### Introduction 6 | There are already many PHP CodeSniffer rules out there to aid in Magento 2 development: 7 | - Magento core ruleset (in folder `dev/tests/static/framework/Magento`) 8 | - [Magento Extension Quality Program](https://github.com/magento/marketplace-eqp) (in short: MEQP) 9 | - [Magento Expert Consultancy Group](https://github.com/magento-ecg/coding-standard) (in short: ECG) 10 | - PSR-1, PSR-2, possibly PSR-12 11 | 12 | However, some best practices still need to be integrated and/or some rules do need to be improved. This 13 | repository forms an effort to come up with more advanced rulesets than there currently are. Additionally, one of the underlying goals is to create rules that fit Magento core, Magento third party extensions and Magento implements, while they all have different needs. 14 | 15 | ### Usage 16 | To install this package, go to your Magento 2 root and use the following: 17 | 18 | composer require extdn/phpcs:dev-master 19 | 20 | If this fails because the dependency with `magento/marketplace-eqp` fails to load, first add the EQP repo to your configuration and then repeat: 21 | 22 | composer config repositories.magento-marketplace-eqp vcs https://github.com/magento/marketplace-eqp 23 | composer require magento/marketplace-eqp:dev-master 24 | composer require extdn/phpcs:dev-master 25 | 26 | Once installed, you can run PHPCS from the command-line to analyse your code `XYZ`: 27 | 28 | vendor/bin/phpcs --standard=./vendor/extdn/phpcs/Extdn app/code/XYZ 29 | vendor/bin/phpcs --standard=./vendor/extdn/phpcs/Extdn vendor/XYZ 30 | 31 | If you have a Composer Installer Plugin for PHPCS coding standards (such as https://github.com/Dealerdirect/phpcodesniffer-composer-installer) configured in the project, you can refer to this standard simply by its name: 32 | 33 | vendor/bin/phpcs --standard=Extdn app/code/XYZ 34 | vendor/bin/phpcs --standard=Extdn vendor/XYZ 35 | 36 | ## Where to contribute 37 | We need help in the following areas: 38 | - Documentation of existing EQP rules (where each EQP rule could be included in this repository its `ruleset.xml`) 39 | - Creation of new PHPCS rules (see below **How to contribute**) 40 | - Braindumps on where PHPCS lacks and other tools might come in more handy (PhpStan, Phan) 41 | - Discussions on new rules (through periodic hangouts or discussions per GitHub Issue) 42 | 43 | Please note that you are also welcome to contribute to the Magento rulesets directly (core, MEQP, ECG - see links above). Likewise, we will try to get ExtDN rules into Magento rulesets as well, which is part of this ExtDN project. 44 | 45 | ## How to contribute 46 | Any contribution is welcome. However, don't start coding just yet. Make sure first that the work is worth the effort. 47 | 48 | 1) Add a new issue under **Issues** to address new rulesets that are needed or report other issues. 49 | 50 | 2) Once the creation of the new rule has been accepted by adding a label `Accepted` under **Issues**, we're good to go. 51 | 52 | 3) If a similar rule already exists in the core or MEQP or ECG, simply try to include this rule within the ExtDN ruleset. 53 | 54 | 4) If no rule exists yet, let's create it. As an example, you can use the `SetTemplateInBlockSniff` within the folder `Extdn/Sniffs/Blocks`. It can be tested upon a sample file under `Extdn/Samples/Blocks`: 55 | 56 | ```bash 57 | vendor/bin/phpcs --standard=./vendor/extdn/phpcs/Extdn vendor/extdn/phpcs/Extdn/Samples 58 | ``` 59 | 60 | 5) Once this all works, feel free to create a Pull Request (PR) including the addition of this rule to the `ruleset.xml` file. 61 | 62 | 63 | ### Using labels with GitHub issues 64 | Some important labels, used for Github issues: 65 | 66 | - `accepted`: The rule is accepted by extdn. If nobody claimed it yet, you may start working on it 67 | - `experimental`: The rule can be implemented as well, but we will try it out with a low severity first before integrating it into the official ruleset 68 | - `non-PHPCS`: The rule is not feasibly implementable with phpcs, will need additional tools. We keep it for later. 69 | - `organizational`: Non-code related issues 70 | - `on agenda of hangout`: The rule/issue will be discussed in the next community hangout 71 | 72 | ## How to create a Sniffer Rule 73 | We recommend to get started by creating a couple of sniffs for your own. The official [PHPCS wiki](https://github.com/squizlabs/PHP_CodeSniffer/wiki) already gives good information. Likewise, the other sniffs in our repos (and the repos of Magento) will give lots of samples anyway. 74 | 75 | ## Testing 76 | All rules should be accompanied with tests. 77 | 78 | ### Within a Magento installation 79 | To run the sniff unit tests from a main repository, where the rules are installed via `composer`, first configure `phpcs` to find the rules: 80 | 81 | vendor/bin/phpcs --config-set installed_paths vendor/extdn/phpcs/Extdn,vendor/magento/marketplace-eqp/MEQP2 82 | 83 | Then tests can be run like this: 84 | 85 | phpunit -c vendor/extdn/phpcs/phpunit-vendor.xml vendor/extdn/phpcs/Extdn/Tests 86 | 87 | ### In a standalone installation 88 | If you have cloned this GitHub repository on its own for development, use `composer` to install things and run the tests: 89 | 90 | composer install 91 | composer test 92 | 93 | Each `Test.php` class should be accompanied by a `Test.inc` file to allow for unit testing based upon the PHPCS parent class `AbstractSniffUnitTest`. Make sure to include a `Test.md` Markdown description which addresses the issue at hand, explains what the rule check for and then also suggests the improvement to be made. 94 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "extdn/phpcs", 3 | "description": "A set of PHP_CodeSniffer rules and sniffs.", 4 | "homepage": "https://github.com/extdn/extdn-phpcs", 5 | "license": "MIT", 6 | "type": "phpcodesniffer-standard", 7 | "authors": [ 8 | { 9 | "name": "ExtDN", 10 | "homepage": "https://extdn.org/", 11 | "role": "Maintainer" 12 | } 13 | ], 14 | "require": { 15 | "php": ">=7.0.0", 16 | "squizlabs/php_codesniffer": "^3.1.0", 17 | "magento/marketplace-eqp": "dev-master" 18 | }, 19 | "autoload": { 20 | "psr-4": { 21 | "Extdn\\": "Extdn/" 22 | } 23 | }, 24 | "require-dev": { 25 | "phpunit/phpunit": "^6.0", 26 | "phpro/grumphp": "^0.14.0", 27 | "friendsofphp/php-cs-fixer": "^2.11", 28 | "infection/infection": "^0.8.2", 29 | "jakub-onderka/php-parallel-lint": "^1.0", 30 | "phpstan/phpstan": "^0.9.2" 31 | }, 32 | "scripts": { 33 | "post-install-cmd": "\"vendor/bin/phpcs\" --config-set installed_paths ../../..", 34 | "post-update-cmd": "\"vendor/bin/phpcs\" --config-set installed_paths ../../..", 35 | "test": "vendor/bin/phpunit" 36 | }, 37 | "repositories": { 38 | "meqp": { 39 | "type": "git", 40 | "url": "https://github.com/magento/marketplace-eqp.git" 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /docs/rule-documentation-template.md: -------------------------------------------------------------------------------- 1 | # Rule: The headline contains the rule title 2 | ## Background 3 | A paragraph that briefly describes the context of the rule. 4 | 5 | ## Reasoning 6 | Explanation why the rule has been created. The reader should understand the reasons. 7 | 8 | ## How it works 9 | Technical details, what exactly is checked. This may help determine false positives. 10 | 11 | ## How to fix 12 | Description how to resolve a found violation. Should contain example code and explain why it is a better alternative. -------------------------------------------------------------------------------- /grumphp.yml: -------------------------------------------------------------------------------- 1 | parameters: 2 | git_dir: . 3 | bin_dir: vendor/bin 4 | tasks: 5 | # infection: ~ 6 | phpcs: ~ 7 | phplint: ~ 8 | phpstan: 9 | autoload_file: vendor/squizlabs/php_codesniffer/autoload.php 10 | ignore_patterns: [Extdn/Samples] 11 | phpunit: ~ 12 | phpversion: ~ 13 | xmllint: ~ 14 | yamllint: ~ 15 | -------------------------------------------------------------------------------- /phpcs.xml.dist: -------------------------------------------------------------------------------- 1 | 2 | 3 | The coding standard for PHP_CodeSniffer itself. 4 | 5 | Extdn 6 | 7 | */Standards/*/Tests/*\.(inc|css|js) 8 | Extdn/Samples/* 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | error 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /phpunit-vendor.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | ../../../vendor/squizlabs/php_codesniffer/tests/Standards/AllSniffs.php 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /phpunit.xml.dist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | vendor/squizlabs/php_codesniffer/tests/Standards/AllSniffs.php 6 | 7 | 8 | 9 | 10 | 11 | --------------------------------------------------------------------------------