bitexpert / phpstan-magento Goto Github PK
View Code? Open in Web Editor NEWMagento specific extension for PHPStan
License: MIT License
Magento specific extension for PHPStan
License: MIT License
Extend the CI pipeline to check for
See the discussion here: #112 (comment)
Currently, only the extension attribute interfaces are generated but not the extension attribute classes.
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.
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?
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.
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.
$ 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
Magento\Payment\Gateway\Data\PaymentDataObjectFactory
) or create your own factory classvendor/bin/phpstan analyse
on your codeInstead of forcing the user to manually include the vendor/bitexpert/phpstan-magento/autoload.php
file, this can be done in the extension.neon
configuration automatically as can be seen in the PHPStan extension for Drupal: https://github.com/mglaman/phpstan-drupal/blob/main/extension.neon#L3
Since PHPStan is using require_once
to load those files, we do not need to care that the file might be loaded twice.
See here for all required changes that need to be applied.
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() {}
}
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
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:
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.
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.
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
?
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):
-- --------------------------------------------------------------------------------
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
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!
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!
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/../../../
While browsing this project I've found that stubs live in the same directory as source files.
https://github.com/bitExpert/phpstan-magento/tree/master/src/Magento
Would you welcome a PR that moves stub to stubs/
?
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!
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?
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.
last submission was in April
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.
Check if we can use the phpstan caching layer to store the temp files instead of writing directly to temp dir. Ideally don't regenerate the files over and over again.
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.
Since in the docs the installation of phpstan/extension-installer
is mentioned, we should cover the additional steps needed for Composer 2.2.0 which changes how Composer plugins are registered. See here for details: https://getcomposer.org/doc/06-config.md#allow-plugins
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'));
...
I recently discovered your module, however I am unable to install due to this error:
composer require --dev bitexpert/phpstan-magento
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?
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:
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.
Come up with a plan to make the PHPStan extension aware of defined extension attributes.
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!
- 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
On what PHP version? With what Magento version?
From #256
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.
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.
It is not possible to update to magento 2.4.0 community edition because your module requires phpstan/phpstan: ^0.12.24, while magento requires phpstan/phpstan: >=0.12.3 <=0.12.23 (https://packagist.org/packages/magento/community-edition).
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.
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.
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.
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 :)
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
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 :)
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().
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"
.
bitexpert/phpstan-magento
0.1.0Create 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();
}
}
Run vendor/bin/phpstan analyze --level=8 src/Company/Module/Test/Integration
.
One issue is found:
Call to static method getObjectManager() on an unknown class Magento\TestFramework\Helper\Bootstrap
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.
Do we need to add another custom autoloader for Magento\TestFramework
?
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 (
Line 49 in 7ee91de
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?)
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
A more correct transformation:
$originalClassname = preg_replace('#Factory$#', '', $factoryClassname);
This way, only "Factory" at the end of the classname is removed.
Build a GitHub Action to let phpstan-magento run in GitHub build pipelines automatically. Check what the extdn people have done for their actions and adapt https://github.com/extdn/github-actions-m2
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.