Giter VIP home page Giter VIP logo

phpstan-magento's Introduction

bitexpert/phpstan-magento

This package provides some additional features for PHPStan to make it work for Magento 2 projects. You can use this PHPStan extension for both Magento module projects and Magento application projects.

Build Status Coverage Status installs on Packagist Mastodon Follow

Requirements

PHP: PHP 7.2 or higher

Magento: Magento 2.3.0 or higher

PHPStan: PHPStan 1.10

If you are using a Magento version that requires an older version of PHPStan (e.g. 0.12.77), you need to manually upgrade it before installing this extension. in your composer.json Change the PHPStan version to ~1.10 and run:

composer update phpstan/phpstan --with-all-dependencies

This PHPStan extension needs to be registered with PHPStan so that the extension gets loaded properly. The easiest way to do this is to install the phpstan/extension-installer package as follows:

composer.phar require --dev phpstan/extension-installer
Composer Allow-Plugins configuration

If you're using Composer >= 2.2.0 you have to allow the execution of composer plugins (see allow-plugins section) as follows:

  - Installing phpstan/extension-installer (1.1.0): Extracting archive
phpstan/extension-installer contains a Composer plugin which is currently not in your allow-plugins config. See https://getcomposer.org/allow-plugins
Do you trust "phpstan/extension-installer" to execute code and wish to enable it now? (writes "allow-plugins" to composer.json) [y,n,d,?] y

Installation

The preferred way of installing bitexpert/phpstan-magento is through Composer. You can add bitexpert/phpstan-magento as a dev dependency, as follows:

composer.phar require --dev bitexpert/phpstan-magento

Want a full walk-through of the installation & configuration process? Read the blog post at M.academy about Static Analysis in Magento with PHPStan.

PHPStan configuration

If you have not already a PHPStan configuration file phpstan.neon in your project, create a new empty file next to your composer.json file.

See here what options PHPStan allows you to configure.

Feature overview

This PHPStan extension works for both Magento module projects and Magento application projects.

  • Class generator for factory & proxy classes
  • Mocked classes autoloader
  • TestFramework autoloader
  • Type hints
    • TestFramework ObjectManager type hints
    • ObjectManager type hints
  • Magic method calls
  • Extension attributes
  • PHPStan rules
    • Service contracts
    • Resource Models should be used directly
    • Collections should be used directly via factory
    • Do not use setTemplate in Block classes

For a detailed overview, check the feature documentation here.

Contribute

Please feel free to fork and extend existing or add new features and send a pull request with your changes! To establish a consistent code quality, please provide unit tests for all your changes and adapt the documentation.

Want To Contribute?

If you feel that you have something to share, then we’d love to have you. Check out the contributing guide to find out how, as well as what we expect from you.

License

PHPStan Magento Extension is released under the MIT License.

phpstan-magento's People

Contributors

brentrobert avatar dependabot-preview[bot] avatar dependabot[bot] avatar hostep avatar jbrada avatar kanduvisla avatar markshust avatar mattwellss avatar shochdoerfer avatar sprankhub avatar szepeviktor avatar torhoehn avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

phpstan-magento's Issues

Issue when installing latest version

When trying to install version 0.11.0 found issues with already existing installation requirements from Magento packages ( Magento OpenSource 2.4.3 )

> composer require --dev  bitexpert/phpstan-magento
Using version ^0.11.0 for bitexpert/phpstan-magento
./composer.json has been updated
Gathering patches for root package.
Loading composer repositories with package information
Warning from https://repo.packagist.org: Support for Composer 1 is deprecated and some packages will not be available. You should upgrade to Composer 2. See https://blog.packagist.com/deprecating-composer-1-support/
Updating dependencies (including require-dev)
Your requirements could not be resolved to an installable set of packages.

  Problem 1
    - Installation request for bitexpert/phpstan-magento ^0.11.0 -> satisfiable by bitexpert/phpstan-magento[v0.11.0].
    - bitexpert/phpstan-magento v0.11.0 requires phpstan/phpstan ^1.1.0 -> satisfiable by phpstan/phpstan[1.1.0, 1.1.1, 1.1.2, 1.2.0, 1.3.x-dev] but these conflict with your requirements or minimum-stability.


Installation failed, reverting ./composer.json to its original content.

Installing version 0.10.* works.

Error in Proxy generator?

Hi,

I stumbled on a similar error message as reported in #11 and I had to make the following fix to prevent an invalid error from being reported.

class MyClass
{
    /** @var \Magento\Customer\Model\Session\Proxy */
    protected $customerSession;

    public function __construct(
        \Magento\Customer\Model\Session\Proxy $customerSession
    ) {
        $this->customerSession = $customerSession;
    }
}

Without the patch:

 ------ -------------------------------------------------------------------------------- 
  Line   MyClass.php                                                          
 ------ -------------------------------------------------------------------------------- 
  xx     Class Magento\Customer\Model\Session\Magento\Customer\Model\Session not found.  
         πŸ’‘ Learn more at https://phpstan.org/user-guide/discovering-symbols              
 ------ -------------------------------------------------------------------------------- 

The patch:

--- /src/bitExpert/PHPStan/Magento/Autoload/ProxyAutoloader.php	(date 1606495178613)
+++ /src/bitExpert/PHPStan/Magento/Autoload/ProxyAutoloader.php	(date 1606495178613)
@@ -105,7 +105,7 @@
                     $returnType . " {}\n\n";
             }
         } else {
-            $proxyBaseClass = ' extends ' . $originalClassname;
+            $proxyBaseClass = ' extends \\' . $originalClassname;
         }
 
         $template = "<?php\n";

Do you think it's really a fix or it could lead to some unexpected behavior in some cases?

Current release version not updated

In d3dbb8d, the requirements for phpstan were updated to "phpstan/phpstan": "~1.8.2", however, in the package version, the old requirements are still present.

A fix would be to release a new version so that the requirements are updated.

Replace custom autoloaders with Magento's implementation

To investigate: Could we use the Magento\Framework\TestFramework\Unit\Autoloader implementations to generate the code and autoload it instead of our own custom logic? Or maybe reimplement Magento\Framework\Code\Generator\Autoloader to get rid of the ObjectManager magic.

DateTimeFactory Issue;

Hi Bit Expert team,

I believe there is an issue with PHP Stan regarding DateTimeFactory.

We believe the analyzer thinks the DateTimeFactory is a generated one, and therefore should accept a single array arg, when in fact Magento\Framework\Intl\DateTimeFactory is an actual class shipped with the Magento framework.

Am i correct in this assumption or is there another solution opposed to ignoring the Error?

See below ignore / Error message:

...  

use Magento\Framework\Intl\DateTimeFactory;

...

      /**
        * Method Magento\Framework\Intl\DateTimeFactory::create() invoked
        * with 2 parameters, 0-1 required.
        *
        * @phpstan-ignore-next-line
        */
       $currentDate = $this->dateTimeFactory->create('now', new \DateTimeZone('UTC'));
...

Feature Request: Add rule for "resource models should be used directly"

Add a PHPStan rule to detect calls for getResource() in Model classes. Calling getResource() is marked as deprecated since it's not considered a good practice any more, see this thread on StackOverflow.

In the Magento source code, you'll find a few deprecated notices like "@deprecated 102.0.6 because resource models should be used directly". Those could be used to find out how to properly implement this rule.

Improve extension attribute handling for standalone modules

As discussed in #162, I've tested extension attributes in a standalone module: lacrossefootwear/magento2-force-login#1

The issue with standalone modules is here:

$enabledModuleDirs = array_filter(
$this->componentRegistrar->getPaths(ComponentRegistrar::MODULE),
function ($moduleName) {
return $this->moduleList->has($moduleName);
},
ARRAY_FILTER_USE_KEY
);

I did this to limit the list of extension attributes under consideration to only enabled modules, but the concept of enabled modules only exists when running a Magento app, not when developing a standalone module.

For standalone modules, I propose that we ignore whether a module is enabled or not, and grab extension_attributes.xml files from all registered modules (which work great regardless of application or standalone).

In my testing, standalone modules work great with the extension attribute autoloader once this issue is resolved.

Feature request: Add objectManager type hints for Unit tests

Hi!
You already have the nice feature with the ObjectManager type hints.
But magento also provides another ObjectManager for unit tests. The problem is that the class ObjectManagerDynamicReturnTypeExtension just provides support for the default magento objectmanager as seen here.

So now when assigning the return value of the getObject() function to an class property with phpDoc the following phpstan error occurs: Property Oneserv\TestFramework\Test\Unit\Test::$testClass (Oneserv\TestFramework\Test\Unit\TestClass) does not accept object as the return type of the function is just object.

Here is a minium example:

<?php

declare(strict_types=1);

namespace Oneserv\TestFramework\Test\Unit;

/**
 * Class Test
 */
class Test extends AbstractTestCase
{
    /** @var TestClass */
    protected $testClass;

    /**
     * @inheritDoc
     */
    protected function setUp(): void
    {
        parent::setUp();

        $this->testClass = $this->objectManager->getObject(TestClass::class);
    }
}

I would love having this feature to avoid ignoring the error!

Compatibility with phpstan 1.7+

I'm running v0.21.0 with phpstan/phpstan 1.7.1. For:

vendor/bin/phpstan analyse -l 2 module-path/file.php -v

I see persistent errors relating to cache folder creation. Example:

 -- --------------------------------------------------------------------------------
     Error
 -- --------------------------------------------------------------------------------
     Internal error: Internal error: Failed to create directory
     "/var/folders/tk/xvp5s1qd77131xvk85lq5snw0000gn/T/phpstan/cache/PHPStan"
     (unknown cause). in file
     /Users/alastairmucklow/Sites/magento-cc-2.4.4/app/code/Dotdigitalgroup/Email/M
     odel/Sync/Subscriber/SubscriberWithSalesExporter.php

     Post the following stack trace to
     https://github.com/phpstan/phpstan/issues/new?template=Bug_report.md:
     #0
     /Users/alastairmucklow/Sites/magento-cc-2.4.4/vendor/bitexpert/phpstan-magento
     /src/bitExpert/PHPStan/Magento/Autoload/Cache/FileCacheStorage.php(61):
     bitExpert\PHPStan\Magento\Autoload\Cache\FileCacheStorage->makeDir('/var/folde
     rs/tk...')
     #1
     phar:///Users/alastairmucklow/Sites/magento-cc-2.4.4/vendor/phpstan/phpstan/ph
     pstan.phar/src/Cache/Cache.php(28):
     bitExpert\PHPStan\Magento\Autoload\Cache\FileCacheStorage->save('Dotdigitalgro
     up...', '', '<?php\nnamespace...')
     #2
     /Users/alastairmucklow/Sites/magento-cc-2.4.4/vendor/bitexpert/phpstan-magento
     /src/bitExpert/PHPStan/Magento/Autoload/FactoryAutoloader.php(42):
     PHPStan\Cache\Cache->save('Dotdigitalgroup...', '', '<?php\nnamespace...')
     #3
     phar:///Users/alastairmucklow/Sites/magento-cc-2.4.4/vendor/phpstan/phpstan/ph
     pstan.phar/src/Reflection/BetterReflection/SourceLocator/AutoloadSourceLocator
     .php(270):
     bitExpert\PHPStan\Magento\Autoload\FactoryAutoloader->autoload('Dotdigitalgrou
     p...')
     #4
     phar:///Users/alastairmucklow/Sites/magento-cc-2.4.4/vendor/phpstan/phpstan/ph
     pstan.phar/src/Reflection/BetterReflection/SourceLocator/FileReadTrapStreamWra
     pper.php(59):
     PHPStan\Reflection\BetterReflection\SourceLocator\AutoloadSourceLocator::PHPSt
     an\Reflection\BetterReflection\SourceLocator\{closure}()
     #5
     phar:///Users/alastairmucklow/Sites/magento-cc-2.4.4/vendor/phpstan/phpstan/ph
     pstan.phar/src/Reflection/BetterReflection/SourceLocator/AutoloadSourceLocator
     .php(282):
     PHPStan\Reflection\BetterReflection\SourceLocator\FileReadTrapStreamWrapper::w
     ithStreamWrapperOverride(Object(Closure))
     #6
     phar:///Users/alastairmucklow/Sites/magento-cc-2.4.4/vendor/phpstan/phpstan/ph
     pstan.phar/src/Reflection/BetterReflection/SourceLocator/AutoloadSourceLocator
     .php(114):
     PHPStan\Reflection\BetterReflection\SourceLocator\AutoloadSourceLocator->locat
     eClassByName('Dotdigitalgroup...')
     #7
     phar:///Users/alastairmucklow/Sites/magento-cc-2.4.4/vendor/phpstan/phpstan/ph
     pstan.phar/vendor/ondrejmirtes/better-reflection/src/SourceLocator/Type/Aggreg
     ateSourceLocator.php(28):
     PHPStan\Reflection\BetterReflection\SourceLocator\AutoloadSourceLocator->locat
     eIdentifier(Object(PHPStan\BetterReflection\Reflector\DefaultReflector),
     Object(PHPStan\BetterReflection\Identifier\Identifier))
     #8
     phar:///Users/alastairmucklow/Sites/magento-cc-2.4.4/vendor/phpstan/phpstan/ph
     pstan.phar/vendor/ondrejmirtes/better-reflection/src/SourceLocator/Type/Memoiz
     ingSourceLocator.php(33):
     PHPStan\BetterReflection\SourceLocator\Type\AggregateSourceLocator->locateIden
     tifier(Object(PHPStan\BetterReflection\Reflector\DefaultReflector),
     Object(PHPStan\BetterReflection\Identifier\Identifier))
     #9
     phar:///Users/alastairmucklow/Sites/magento-cc-2.4.4/vendor/phpstan/phpstan/ph
     pstan.phar/vendor/ondrejmirtes/better-reflection/src/Reflector/DefaultReflecto
     r.php(32):
     PHPStan\BetterReflection\SourceLocator\Type\MemoizingSourceLocator->locateIden
     tifier(Object(PHPStan\BetterReflection\Reflector\DefaultReflector),
     Object(PHPStan\BetterReflection\Identifier\Identifier))
     #10
     phar:///Users/alastairmucklow/Sites/magento-cc-2.4.4/vendor/phpstan/phpstan/ph
     pstan.phar/src/Reflection/BetterReflection/Reflector/MemoizingReflector.php(45
     ):
     PHPStan\BetterReflection\Reflector\DefaultReflector->reflectClass('Dotdigitalg
     roup...')
     #11
     phar:///Users/alastairmucklow/Sites/magento-cc-2.4.4/vendor/phpstan/phpstan/ph
     pstan.phar/src/Reflection/BetterReflection/BetterReflectionProvider.php(151):
     PHPStan\Reflection\BetterReflection\Reflector\MemoizingReflector->reflectClass
     ('Dotdigitalgroup...')
     #12
     phar:///Users/alastairmucklow/Sites/magento-cc-2.4.4/vendor/phpstan/phpstan/ph
     pstan.phar/src/Reflection/ReflectionProvider/MemoizingReflectionProvider.php(3
     4):
     PHPStan\Reflection\BetterReflection\BetterReflectionProvider->hasClass('Dotdig
     italgroup...')
     #13
     phar:///Users/alastairmucklow/Sites/magento-cc-2.4.4/vendor/phpstan/phpstan/ph
     pstan.phar/src/Rules/ClassCaseSensitivityCheck.php(34):
     PHPStan\Reflection\ReflectionProvider\MemoizingReflectionProvider->hasClass('D
     otdigitalgroup...')
     #14
     phar:///Users/alastairmucklow/Sites/magento-cc-2.4.4/vendor/phpstan/phpstan/ph
     pstan.phar/src/Rules/Namespaces/ExistingNamesInUseRule.php(107):
     PHPStan\Rules\ClassCaseSensitivityCheck->checkClassNames(Array)
     #15
     phar:///Users/alastairmucklow/Sites/magento-cc-2.4.4/vendor/phpstan/phpstan/ph
     pstan.phar/src/Rules/Namespaces/ExistingNamesInUseRule.php(61):
     PHPStan\Rules\Namespaces\ExistingNamesInUseRule->checkClasses(Array)
     #16
     phar:///Users/alastairmucklow/Sites/magento-cc-2.4.4/vendor/phpstan/phpstan/ph
     pstan.phar/src/Analyser/FileAnalyser.php(102):
     PHPStan\Rules\Namespaces\ExistingNamesInUseRule->processNode(Object(PhpParser\
     Node\Stmt\Use_), Object(PHPStan\Analyser\MutatingScope))
     #17
     phar:///Users/alastairmucklow/Sites/magento-cc-2.4.4/vendor/phpstan/phpstan/ph
     pstan.phar/src/Analyser/NodeScopeResolver.php(378):
     PHPStan\Analyser\FileAnalyser->PHPStan\Analyser\{closure}(Object(PhpParser\Nod
     e\Stmt\Use_), Object(PHPStan\Analyser\MutatingScope))
     #18
     phar:///Users/alastairmucklow/Sites/magento-cc-2.4.4/vendor/phpstan/phpstan/ph
     pstan.phar/src/Analyser/NodeScopeResolver.php(323):
     PHPStan\Analyser\NodeScopeResolver->processStmtNode(Object(PhpParser\Node\Stmt
     \Use_), Object(PHPStan\Analyser\MutatingScope), Object(Closure))
     #19
     phar:///Users/alastairmucklow/Sites/magento-cc-2.4.4/vendor/phpstan/phpstan/ph
     pstan.phar/src/Analyser/NodeScopeResolver.php(535):
     PHPStan\Analyser\NodeScopeResolver->processStmtNodes(Object(PhpParser\Node\Stm
     t\Namespace_), Array, Object(PHPStan\Analyser\MutatingScope), Object(Closure))
     #20
     phar:///Users/alastairmucklow/Sites/magento-cc-2.4.4/vendor/phpstan/phpstan/ph
     pstan.phar/src/Analyser/NodeScopeResolver.php(294):
     PHPStan\Analyser\NodeScopeResolver->processStmtNode(Object(PhpParser\Node\Stmt
     \Namespace_), Object(PHPStan\Analyser\MutatingScope), Object(Closure))
     #21
     phar:///Users/alastairmucklow/Sites/magento-cc-2.4.4/vendor/phpstan/phpstan/ph
     pstan.phar/src/Analyser/FileAnalyser.php(189):
     PHPStan\Analyser\NodeScopeResolver->processNodes(Array,
     Object(PHPStan\Analyser\MutatingScope), Object(Closure))
     #22
     phar:///Users/alastairmucklow/Sites/magento-cc-2.4.4/vendor/phpstan/phpstan/ph
     pstan.phar/src/Command/WorkerCommand.php(143):
     PHPStan\Analyser\FileAnalyser->analyseFile('/Users/alastair...', Array,
     Object(PHPStan\Rules\Registry), NULL)
     #23
     phar:///Users/alastairmucklow/Sites/magento-cc-2.4.4/vendor/phpstan/phpstan/ph
     pstan.phar/vendor/evenement/evenement/src/Evenement/EventEmitterTrait.php(97):
     PHPStan\Command\WorkerCommand->PHPStan\Command\{closure}(Array)
     #24
     phar:///Users/alastairmucklow/Sites/magento-cc-2.4.4/vendor/phpstan/phpstan/ph
     pstan.phar/vendor/clue/ndjson-react/src/Decoder.php(110):
     _PHPStan_c24aa5a16\Evenement\EventEmitter->emit('data', Array)
     #25
     phar:///Users/alastairmucklow/Sites/magento-cc-2.4.4/vendor/phpstan/phpstan/ph
     pstan.phar/vendor/evenement/evenement/src/Evenement/EventEmitterTrait.php(97):
     _PHPStan_c24aa5a16\Clue\React\NDJson\Decoder->handleData(Array)
     #26
     phar:///Users/alastairmucklow/Sites/magento-cc-2.4.4/vendor/phpstan/phpstan/ph
     pstan.phar/vendor/react/stream/src/Util.php(62):
     _PHPStan_c24aa5a16\Evenement\EventEmitter->emit('data', Array)
     #27
     phar:///Users/alastairmucklow/Sites/magento-cc-2.4.4/vendor/phpstan/phpstan/ph
     pstan.phar/vendor/evenement/evenement/src/Evenement/EventEmitterTrait.php(97):
     _PHPStan_c24aa5a16\React\Stream\Util::_PHPStan_c24aa5a16\React\Stream\{closure
     }('{"action":"anal...')
     #28
     phar:///Users/alastairmucklow/Sites/magento-cc-2.4.4/vendor/phpstan/phpstan/ph
     pstan.phar/vendor/react/stream/src/DuplexResourceStream.php(154):
     _PHPStan_c24aa5a16\Evenement\EventEmitter->emit('data', Array)
     #29
     phar:///Users/alastairmucklow/Sites/magento-cc-2.4.4/vendor/phpstan/phpstan/ph
     pstan.phar/vendor/react/event-loop/src/StreamSelectLoop.php(201):
     _PHPStan_c24aa5a16\React\Stream\DuplexResourceStream->handleData(Resource id
     #4117)
     #30
     phar:///Users/alastairmucklow/Sites/magento-cc-2.4.4/vendor/phpstan/phpstan/ph
     pstan.phar/vendor/react/event-loop/src/StreamSelectLoop.php(173):
     _PHPStan_c24aa5a16\React\EventLoop\StreamSelectLoop->waitForStreamActivity(NUL
     L)
     #31
     phar:///Users/alastairmucklow/Sites/magento-cc-2.4.4/vendor/phpstan/phpstan/ph
     pstan.phar/src/Command/WorkerCommand.php(106):
     _PHPStan_c24aa5a16\React\EventLoop\StreamSelectLoop->run()
     #32
     phar:///Users/alastairmucklow/Sites/magento-cc-2.4.4/vendor/phpstan/phpstan/ph
     pstan.phar/vendor/symfony/console/Command/Command.php(259):
     PHPStan\Command\WorkerCommand->execute(Object(_PHPStan_c24aa5a16\Symfony\Compo
     nent\Console\Input\ArgvInput),
     Object(_PHPStan_c24aa5a16\Symfony\Component\Console\Output\ConsoleOutput))
     #33
     phar:///Users/alastairmucklow/Sites/magento-cc-2.4.4/vendor/phpstan/phpstan/ph
     pstan.phar/vendor/symfony/console/Application.php(856):
     _PHPStan_c24aa5a16\Symfony\Component\Console\Command\Command->run(Object(_PHPS
     tan_c24aa5a16\Symfony\Component\Console\Input\ArgvInput),
     Object(_PHPStan_c24aa5a16\Symfony\Component\Console\Output\ConsoleOutput))
     #34
     phar:///Users/alastairmucklow/Sites/magento-cc-2.4.4/vendor/phpstan/phpstan/ph
     pstan.phar/vendor/symfony/console/Application.php(259):
     _PHPStan_c24aa5a16\Symfony\Component\Console\Application->doRunCommand(Object(
     PHPStan\Command\WorkerCommand),
     Object(_PHPStan_c24aa5a16\Symfony\Component\Console\Input\ArgvInput),
     Object(_PHPStan_c24aa5a16\Symfony\Component\Console\Output\ConsoleOutput))
     #35
     phar:///Users/alastairmucklow/Sites/magento-cc-2.4.4/vendor/phpstan/phpstan/ph
     pstan.phar/vendor/symfony/console/Application.php(157):
     _PHPStan_c24aa5a16\Symfony\Component\Console\Application->doRun(Object(_PHPSta
     n_c24aa5a16\Symfony\Component\Console\Input\ArgvInput),
     Object(_PHPStan_c24aa5a16\Symfony\Component\Console\Output\ConsoleOutput))
     #36
     phar:///Users/alastairmucklow/Sites/magento-cc-2.4.4/vendor/phpstan/phpstan/ph
     pstan.phar/bin/phpstan(96):
     _PHPStan_c24aa5a16\Symfony\Component\Console\Application->run()
     #37
     phar:///Users/alastairmucklow/Sites/magento-cc-2.4.4/vendor/phpstan/phpstan/ph
     pstan.phar/bin/phpstan(97): _PHPStan_c24aa5a16\{closure}()
     #38
     /Users/alastairmucklow/Sites/magento-cc-2.4.4/vendor/phpstan/phpstan/phpstan(8
     ): require('phar:///Users/a...')
     #39 /Users/alastairmucklow/Sites/magento-cc-2.4.4/vendor/bin/phpstan(117):
     include('/Users/alastair...')
     #40 {main}
     Internal error: Internal error: Failed to create directory
     "/var/folders/tk/xvp5s1qd77131xvk85lq5snw0000gn/T/phpstan/cache/PHPStan"
     (unknown cause). in file
     /Users/alastairmucklow/Sites/magento-cc-2.4.4/app/code/Dotdigitalgroup/Email/M
     odel/Sync/Subscriber/SubscriberExporter.php
     Child process error (exit code 1):
 -- --------------------------------------------------------------------------------

Factory Generator Overrides Concrete Factory

Description

The factory generation logic does not check if the factory actually exists as a concrete class before generating it, which causes the concrete factory to be overridden by the generated factory. This results in PHPStan marking the code as having an error stating that the wrong parameters are being passed.

Expected Result

  • No error is shown for code that instantiates factory class

Actual Result

  • Error is shown for code the instantiates factory class

Example output

$ vendor/bin/phpstan analyse
Note: Using configuration file /Volumes/Development/Extensions/PaymentMethod/phpstan.neon.
 78/78 [β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“] 100%

 ------ -------------------------------------------------------------------------------------------------------------------------------------------------
  Line   Model/Payment/Method/Adapter/PaymentMethod.php
 ------ -------------------------------------------------------------------------------------------------------------------------------------------------
  132    Parameter #1 $data of method Magento\Payment\Gateway\Data\PaymentDataObjectFactory::create() expects array, Magento\Payment\Model\InfoInterface
         given.
  167    Parameter #1 $data of method Magento\Payment\Gateway\Data\PaymentDataObjectFactory::create() expects array, Magento\Payment\Model\InfoInterface
         given.
 ------ -------------------------------------------------------------------------------------------------------------------------------------------------



 [ERROR] Found 2 errors

Steps to Reproduce

  1. Write a class that either uses an existing factory (e.g. Magento\Payment\Gateway\Data\PaymentDataObjectFactory) or create your own factory class
  2. Run vendor/bin/phpstan analyse on your code

Project config file at path app/code/Vendor/Module does not exist.

I have installed the phpstan-magento on

composer require phpstan/phpstan ~1.7.2
composer require --dev phpstan/extension-installer

After running the phpstan command to analyze the code

vendor/bin/phpstan analyse -c app/code/Vendor/Module --level 0

is giving error

Project config file at path app/code/Vendor/Module does not exist.

Set magic method for DataObject requires argument `$key` of type `array|string`

Example:

<?php

use Magento\Framework\DataObject;

$myObject = new DataObject();

$myObject->setMyMagic(1);

Generates:

------ -------------------------------------------------------------------------------- 
  Line   test.php                                                                        
 ------ -------------------------------------------------------------------------------- 
  7      Parameter #1 $key of method Magento\Framework\DataObject::setMyMagic() expects  
         array|string, int given.                                                        
 ------ --------------------------------------------------------------------------------

I believe this is cause by this definition:

private function returnSetMagicMethod(ClassReflection $classReflection, string $methodName): MethodReflection
{
$params = [
new DummyParameter(
'key',
new UnionType([new StringType(), new ArrayType(new MixedType(), new MixedType())]),
true,
null,
false,
null
),
new DummyParameter(
'value',
new MixedType(),
true,
null,
false,
null
)
];

Which I believe should be just a single parameter with a mixed type; this seems to describe the signature of DataObject::setData(). I'm not familiar with the inner workings of PHPStan though so I'm not sure about any additional impact of this change.

Add support for laminas/laminas-code 4.5 (which is a dependency of Magento 2.4.4)

Hi!

Thanks again for this module!

I was trying to prepare a module of mine to test it with Magento 2.4.4 (of which I have bèta access), but due to dependency constraint conflicts this currently does not work.

  • bitexpert/phpstan-magento version 0.17.0 relies on: "laminas/laminas-code": "~3.3.0 || ~3.4.1 || ~3.5.1"
  • magento/framework version 103.0.4-beta4 relies on: "laminas/laminas-code": "~4.5.0"

I don't know how easy it would be to expand the version constraints in this module to allow for the same constraint as Magento's? Preferably - if possible - without dropping the older versions to allow this module to be installed on older Magento versions as well.

Thanks!

Wrong directory used as "magentoRoot" when current working direcory is not magento root

Currently the parameter "magento.magentoRoot" is resolved using the variable %currentWorkingDirectory%, which is not necessarily the magento root directory.
(In my case, phpstan is executed by GrumPHP, which runs in completely different directory)

This results in a broken autoloading of classes in some edge cases (e.g. the recently fixed #249):

See bitExpert\PHPStan\Magento\Autoload\DataProvider\ClassLoaderProvider::__construct:

$this->composer = new ClassLoader($magentoRoot . '/vendor'); // this directory does not exist
$autoloadFile = $magentoRoot . '/vendor/composer/autoload_namespaces.php';
if (is_file($autoloadFile)) {                                // this check will also fail
    $map = require $autoloadFile;
    foreach ($map as $namespace => $path) {
        $this->composer->set($namespace, $path);
    }
}

A workaround is to set the parameter "magento.magentoRoot" not based on the current working directory:

parameters:
    magento:
        magentoRoot: %rootDir%/../../../

This resolves to <vendor>/phpstan/phpstan/../../../

Deprecated Config Option autoload_files

When using the current dev-master and using the recommended configuration from the README.md, there is a deprecation warning when running PHPStan:

Note: Using configuration file /var/www/project/phpstan.neon.
⚠️  You're using a deprecated config option autoload_files. ⚠️️

You might not need it anymore - try removing it from your
configuration file and run PHPStan again.

If the analysis fails, there are now two distinct options
to choose from to replace autoload_files:
1) scanFiles - PHPStan will scan those for classes and functions
   definitions. PHPStan will not execute those files.
2) bootstrapFiles - PHPStan will execute these files to prepare
   the PHP runtime environment for the analysis.

Read more about this in PHPStan's documentation:
https://phpstan.org/user-guide/discovering-symbols

Removing the option altogether does not work for me, because I get the error "Call to static method getObjectManager() on an unknown class Magento\TestFramework\Helper\Bootstrap" again in this case.

Allow package to be installed with phpstan 0.12.x

Currently, the version constraint "phpstan/phpstan": "^0.11.6" blocks me to upgrade phpstan to 0.12.3 in one of my projects.

Would it be possible to test this package with phpstan 0.12.x and if everything is working, declare it as compatible with 0.12.x?

Suggestion would be to change the version constraint to:
"phpstan/phpstan": "^0.11.6 || ^0.12.0"

Thanks!

missing check when using factory, di inyection and preference

My current module has a preference over a class set on the di.xml file.

I'm using the factory on the constructor of a overwrite.

When using a method that only exists on the overwrited class that is created through the Factory, PHPStan reports the method as not existent.

di.xml

<preference for="Magento\Framework\View\Result\Page"                 type="ClassA" />
<preference for="Magento\Framework\View\Page\Config\Renderer" type="ClassB" />

Class with factory on constructor:

class ClassA extends Magento\Framework\View\Result\Page  {
public function __construct(
 ....
 classBFactory $pageConfigRendererFactory
) {
 ...
 parent::__construct(.... );
}

public function overwritenFunction( .... ) {
  ....
  $this->pageConfigRenderer->onlyOnThisClassMethod();
  ....
}

Class B:

class ClassB extends \Magento\Framework\View\Page\Config\Renderer 
{
  public function onlyOnThisClassMethod() { .... }
}

This is reported as:
Call to an undefined method Magento\\Framework\\View\\Page\\Config\\RendererInterface::renderExtraFooter()

Complete code has been tested and battle proven on production, so it works as expected.

For now I'm just ignoring the issue reported.

PHPStan Does Not Find \Magento\TestFramework\Helper\Bootstrap

Preconditions

  1. Magento 2.3.4
  2. PHP 7.2
  3. bitexpert/phpstan-magento 0.1.0

Steps to reproduce

  1. Create an example integration test in your module, e.g. \Company\Module\Test\Integration\ExampleTest:

     <?php
     
     declare(strict_types=1);
     
     namespace Company\Module\Test\Integration;
     
     use Magento\TestFramework\Helper\Bootstrap;
     use PHPUnit\Framework\TestCase;
     
     class ExampleTest extends TestCase
     {
         protected function setUp(): void
         {
             Bootstrap::getObjectManager();
         }
     }
    
  2. Run vendor/bin/phpstan analyze --level=8 src/Company/Module/Test/Integration.

Expected result

  1. No issues are found.

Actual result

  1. One issue is found:

     Call to static method getObjectManager() on an unknown class Magento\TestFramework\Helper\Bootstrap
    

Workaround

Ignore the error in your phpstan.neon:

ignoreErrors:
    - '#Call to static method getObjectManager\(\) on an unknown class Magento\\TestFramework\\Helper\\Bootstrap.#'

The same issue occurs when you try to use the alternative \Magento\Framework\App\ObjectManager::getInstance, so this can unfortunately not be used as a workaround.

Idea

Do we need to add another custom autoloader for Magento\TestFramework?

Turn magento/framework into dev dependency

If you want to install PHPStan and this module outside of a Magento project, it is kind of pointless to install the magento/framework dependency. Check how other PHPStan extensions deal with this and adapt.

Releases and Changelog

Thanks for all your work on making this compatible with the latest version of PHPStan! Much appreciated!

Is there any reason why this package does not have proper versioning? It would be nice to have tagged versions and changelogs for them :)

Missing check when using factory constant

Typical missing check

  Line   Controller/Adminhtml/Loadlog/DataAjax.php                                            
 ------ ------------------------------------------------------------------------------------- 
  115    Access to undefined constant Magento\Framework\Controller\ResultFactory::TYPE_JSON.  
...
  357    Method Swissup\CacheWarmer\Model\RequestEntry\Request\CollectionFactory::create() invoked with 2 parameters, 0-1 required. 
....
333 Call to an undefined method Swissup\CacheWarmer\Model\RequestEntry\Request\CollectionFactory::setLimit(). 

133    Method Magento\Framework\View\Layout\BuilderFactory::create() invoked with 2 parameters, 0-1 required. 

Looks like all your code thinks that Factory is already generated class but it's not.
In these cases, Factory classes already exist and have other implementations

Cannot update to version 0.20.0 on Magento 2.4.4

Since Magento 2.4.4 has a version constraint on phpstan/phpstan: ~1.2.0 its not possible to update bitexpert/phpstan-magento to version 0.20.0.

Is it recommended to update the core Magento dependency to ~1.5.7 in order to use the new version of bitexpert/phpstan-magento ?

Support for earlier PHP versions

I recently discovered your module, however I am unable to install due to this error:
image

Steps

  1. Run composer require --dev bitexpert/phpstan-magento

System

  • Ubuntu 20.04
  • PHP v7.1.33

Expected Result

  1. phpstan-magento installed successfully
  2. Entry for phpstan-magento added to composer.json

Actual Result

  1. Install error - see screenshot

Suggestions/comments

  • Please make error message more verbose, perhaps like Magerun2: informing about the minimum version of PHP required to install the module, instead of only that use has incorrect version
  • Will there be support for php7.1 at some point? If not can I potentially install the package with a different php version and after it would work with PHP7.1? (maybe custom phpstan config?)

Add method description check

Hello.
I like your job and thank you.
Just a question, can I extend it adding extra rules? I want to check that method had some description. If yes, where I can do it, which classes can edit?

For example
/**
* Get products views from report_viewed_product_index table
*
* @param null $beginDate
* @return array
*/
It is ok

/**
 * @param null $beginDate
 * @return array
 */

It is not ok because we have only properties information and dont have description.

It can be great if this module will check has methods description or not.

Error in docker

Running on project

docker run --rm -v $PWD:/code domw/phpstan analyze ./ 
Note: Using configuration file /code/phpstan.neon.
  6/35 [β–“β–“β–“β–“β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘]  17%Fatal error: Class bitExpert\PHPStan\Magento\Reflection\MagicMethodReflection contains 7 abstract methods and must therefore be declared abstract or implement the remaining methods (PHPStan\Reflection\MethodReflection::isDeprecated, PHPStan\Reflection\MethodReflection::getDeprecatedDescription, PHPStan\Reflection\MethodReflection::isFinal, ...) in /code/vendor/bitexpert/phpstan-magento/src/bitExpert/PHPStan/Magento/Reflection/MagicMethodReflection.php on line 20

Seeing above error

Only way around it was to make MagicMethodReflection abstract class

abstract class MagicMethodReflection implements MethodReflection

Not sure why hasn't caused others issue

Upgrade to PHPStan 1.0

PHPStan 1.0 got released today: https://phpstan.org/blog/phpstan-1-0-released

Check how "compatible" it is with the 0.x version we use and decide if it is worth upgrading. The downside of upgrading would be that the extension will be incompatible with the current Composer requirements in Magento 2.4 "phpstan/phpstan": "^0.12.77".

extension_attribute type not handled correctly

I passed an array of SalesChannelInterfaces to the setSalesChannelInterface function:
$stockExtensionAttribute->setSalesChannels([$salesChannelInterface]);

So I receive the following error from phpstan:

Parameter #1 $salesChannels of method Magento\InventoryApi\Api\Data\StockExtensionInterface::setSalesChannels() expects Magento\InventorySalesApi\Api\Data\SalesChannelInterface, array<int,
         Magento\InventorySalesApi\Api\Data\SalesChannelInterface> given.

The extension_attribute is defined here:

    <extension_attributes for="Magento\InventoryApi\Api\Data\StockInterface">
        <attribute code="sales_channels" type="Magento\InventorySalesApi\Api\Data\SalesChannelInterface[]" />
    </extension_attributes>

And the interface \Magento\InventoryApi\Api\Data\StockExtensionInterface looks like this:

    /**
     * @param \Magento\InventorySalesApi\Api\Data\SalesChannelInterface[]|null $salesChannels
     * @return void
     */
    public function setSalesChannels(?array $salesChannels): void;

So maybe phpstan handles the type of the extension_attribute not correctly?

Use Magento root for TestFrameworkAutoloader

I have all QA packages in a separate folder installed using composer. This to avoid version problems with the many Magento packages.

/qa/
/magento/

To run, for instance PHP Stan, I do:

cd magento
../qa/vendor/bin/phpstan analyse -c .phpstan.neon

This works fine, but I saw that the autoloader TestFrameworkAutoloader reads the vendor map in QA and not in Magento. I suggest using the $magentoRoot as you do in https://github.com/bitExpert/phpstan-magento/blob/master/src/bitExpert/PHPStan/Magento/Autoload/DataProvider/ClassLoaderProvider.php#L28

Integration tests needed for CI pipeline

The problem in #243 shows that we need integration tests to detect real-world problems with newer PHPStan releases. Since we have some dependencies deeper in PHPStan's core, things can break.

Ideally, we'd have a demo Magento module that covers all the different features the extension offers. This would also simplify my testing as currently, I am running the dev versions against multiple modules.

Store interface gives errors

I'm experiencing the error below when trying to make a commit. I'm using the setup with Grumphp.

Fatal error: Class Magento\Store\Model\Store contains 2 abstract methods and must therefore be declared abstract or implement the remaining methods (Magento\Store\Api\Data\StoreInterface::setIsActive, Magento\Store\Api\Data\StoreInterface::getIsActive) in vendor/magento/module-store/Model/Store.php on line 38

The replacement interface in vendor/bitexpert/phpstan-magento/src/Magento/Store/Api/Data/StoreInterface.php defines methods setIsActive and getIsActive which are not in Magento\Store\Model\Store.

setIsActive is mentioned as a docblock but setIsActive isn't mentioned at all.

I'm working on 2.2.8. Removing the two methods from the replacement interface make the error go away.

Factory generation misnames output class

When working with a class that have "Factory" in its classname, such as Company\Module\Model\FactoryThing, the PHPStan-generated output class for its factory (Company\Module\Model\FactoryThingFactory is Company\Module\Model\Thing.

It's caused by a simple error in factory generation

$originalClassname = str_replace('Factory', '', $factoryClassname);

A more correct transformation:

        $originalClassname = preg_replace('#Factory$#', '', $factoryClassname);

This way, only "Factory" at the end of the classname is removed.

Installation Guide -- Should be .... :)

Thank you for your great work here!
But I think, need to add more information in an installation guide.
For me: I have to install phpstan/extension-installer
Then have to change phpstan.neon:

parameters:
bootstrapFiles:
- vendor/bitexpert/phpstan-magento/autoload.php
includes:
- vendor/phpstan/phpstan-strict-rules/rules.neon
- vendor/bitexpert/phpstan-magento/extension.neon

It works for me. Thank you guys again a lot!

autoloader does not seem to be picked up when using the phpstan shim

I'm trying to run phpstan in an isolated Magento module codebase, so I'm running into the case where factories etc. are not found.

I noticed the fix for this in registration.php for exactly this:

/**
 * Register given function as __autoload() implementation.
 *
 * @param callable $autoload_function
 * @param bool $throw
 * @param bool $prepend
 * @return bool
 */
function spl_autoload_register(callable $autoload_function, bool $throw = true, bool $prepend = false): bool
{
    // goal: convince PHPStan that classes generated by Magento - namely Factory & Proxy classes exists even when
    // they are not generated. When running PHPStan in a Magento application this is not a problem at all as Magento
    // will generate those files. When running PHPStan on a isolated Magento module codebase this is indeed a problem
    // as we don't have the Magento tooling in place to generate those classes.
    return \spl_autoload_register($autoload_function, $throw, $prepend) && Autoloader::register();
}

However, it does not seem to work. The registration.php file gets loaded, but the namespace-bound spl_autoload_register is not executed.

I am using the phpstan shim in my case. Could that be the cause of this problem?

tmpDir should be relative to PHPStan configuration file path

According to PHPStan's documentation, the tmpDir parameter is calculated relative to the configuration file path: https://phpstan.org/config-reference#caching.

It's not 100% clear to me whether the parameter can be specified as an absolute path in addition to a relative path. Regardless, the current process for determining tmpDir uses the current working directory (

$tmpDir = $neonConfig['parameters']['tmpDir'];
), which doesn't line up with PHPStan's docs.

I'd propose the following change (which supports only relative paths):

$tmpDir = sys_get_temp_dir() . '/phpstan';
if (!empty($configFile)) {
    $neonConfig = Neon::decode(file_get_contents($configFile));
    if(is_array($neonConfig) && isset($neonConfig['parameters']) && isset($neonConfig['parameters']['tmpDir'])) {
        $tmpDir = realpath(dirname($configFile) . '/' . $neonConfig['parameters']['tmpDir']);
    }
}

If absolute paths are also allowed, we'll need to first check whether the configured path begins with a / (or golly, a drive letter for Windows?)

private string $magentoRoot; not work in PHP 7.2

Hello!

I've this error on CI:

Parse error: syntax error, unexpected 'string' (T_STRING), expecting function (T_FUNCTION) or const (T_CONST) in /builds/qkSMQzG3/0/applications/integration-magento2/magento2.3-2.4/vendor/bitexpert/phpstan-magento/src/bitExpert/PHPStan/Magento/Autoload/TestFrameworkAutoloader.php on line 21

Typed properties have been introduced in PHP 7.4 I think but this package is marked as compatible from PHP 7.2.

Thanks in advance :)

Add support to generate proxies for interfaces

The following message will be shown by phpstan while analyzing.

Class Magento\Catalog\Api\ProductRepositoryInterface\Magento\Catalog\Api\ProductRepositoryInterface not found and could not be autoloaded.

The file that was analyzed by phpstan had this a constructor.

/**
 * @param ProductRepositoryInterface\Proxy $productRepository
*/
public function __construct(
    \Magento\Catalog\Api\ProductRepositoryInterface\Proxy $productRepository
) {}

This can be fixed by prefixing the extended Classname with a backslash.

$template .= "class {PROXY_CLASSNAME} extends {CLASSNAME} implements {MARKER_INTERFACE}\n";
in ProxyAutoloader.php:34 becomes
$template .= "class {PROXY_CLASSNAME} extends \{CLASSNAME} implements {MARKER_INTERFACE}\n";

After that a fatal error gets thrown because it will try to extend an Interface.
PHP Fatal error: Class Magento\Catalog\Api\ProductRepositoryInterface\Proxy cannot extend from interface Magento\Catalog\Api\ProductRepositoryInterface in /tmp/PSMPnSgzZV on line 6

<?php
namespace Magento\Catalog\Api\ProductRepositoryInterface;
/**
 * Proxy class for @see Magento\Catalog\Api\ProductRepositoryInterface
 */
class Proxy extends \Magento\Catalog\Api\ProductRepositoryInterface implements \Magento\Framework\ObjectManager\NoninterceptableInterface
{
    /**
     * @return array
     */
    public function __sleep() {}
    /**
     * Retrieve ObjectManager from global scope
     */
    public function __wakeup() {}
    /**
     * Clone proxied instance
     */
    public function __clone() {}
}

Feature Request: Add tips for rule errors

Similar to what happens in PHPStan core, add tips to the rule errors we output to provide some more background information on why the rule was triggered and how to fix it. For the depreciation rules, we could additionally link to the Magento Devdocs.

See RuleErrorBuilder::tip().

Certain CI steps run several times without additional result

      - name: Check license
      - name: Run Codesniffer
      - name: Lint Neon files
      - name: Perform static code analysis
      - name: Execute unit tests

I think these should be ran only once

  • Check license
  • Run Codesniffer
  • Lint Neon files

On what PHP version? With what Magento version?

From #256

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.