Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Add ability to run PHPStan #365

Closed
akira28 opened this issue Nov 3, 2017 · 18 comments · Fixed by #2035
Closed

Add ability to run PHPStan #365

akira28 opened this issue Nov 3, 2017 · 18 comments · Fixed by #2035

Comments

@akira28
Copy link

akira28 commented Nov 3, 2017

I'm trying to figure out how to run PHPStan on Magento LTS.
After dozens of tries I have a somewhat working instance.
These are the files I had to modify to make it run:

	modified:   app/code/core/Mage/Admin/Model/Acl/Assert/Ip.php
	modified:   app/code/core/Mage/Admin/Model/Acl/Assert/Time.php
	modified:   app/code/core/Mage/Adminhtml/Block/Widget/Grid/Block.php
	modified:   app/code/core/Mage/Adminhtml/Model/Extension.php
	modified:   app/code/core/Mage/Api/Model/Acl/Assert/Ip.php
	modified:   app/code/core/Mage/Api/Model/Acl/Assert/Time.php
	modified:   app/code/core/Mage/Authorizenet/controllers/Adminhtml/Authorizenet/Directpost/PaymentController.php
	modified:   app/code/core/Mage/Bundle/controllers/Adminhtml/Bundle/Product/EditController.php
	modified:   app/code/core/Mage/Bundle/controllers/Product/EditController.php
	modified:   app/code/core/Mage/Bundle/controllers/SelectionController.php
	modified:   app/code/core/Mage/Catalog/Model/Product/Option/Api/V2.php
	modified:   app/code/core/Mage/Centinel/Model/Api/Client.php
	modified:   app/code/core/Mage/Compiler/controllers/ProcessController.php
	modified:   app/code/core/Mage/Core/Model/Mysql4/Design/Theme/Collection.php
	modified:   app/code/core/Mage/Core/Model/Resource/Db/Collection/Abstract.php
	modified:   app/code/core/Mage/Dataflow/Model/Convert/Iterator.php
	modified:   app/code/core/Mage/Dataflow/Model/Convert/Iterator/File/Csv.php
	modified:   app/code/core/Mage/Dataflow/Model/Convert/Iterator/Http.php
	modified:   app/code/core/Mage/Dataflow/Model/Session/Adapter/Http.php
	modified:   app/code/core/Mage/Downloadable/controllers/Adminhtml/Downloadable/Product/EditController.php
	modified:   app/code/core/Mage/Downloadable/controllers/FileController.php
	modified:   app/code/core/Mage/Downloadable/controllers/Product/EditController.php
	modified:   app/code/core/Mage/GoogleBase/controllers/ItemsController.php
	modified:   app/code/core/Mage/GoogleBase/controllers/SelectionController.php
	modified:   app/code/core/Mage/GoogleBase/controllers/TypesController.php
	modified:   app/code/core/Mage/Install/Model/Installer/Pear.php
	modified:   app/code/core/Mage/Payment/Model/Paygate/Request.php
	modified:   app/code/core/Mage/Sales/doc/test.php
	modified:   app/code/core/Mage/Tag/Model/Api/V2.php
	modified:   app/code/core/Mage/XmlConnect/Block/Checkout/Cart/Item/Renderer/Giftcard.php
	modified:   app/code/core/Mage/XmlConnect/Block/Checkout/Payment/Method/Pbridge/Abstract.php
	modified:   app/code/core/Mage/XmlConnect/Block/Customer/Form/Renderer/Date.php
	modified:   app/code/core/Mage/XmlConnect/Block/Customer/Form/Renderer/File.php
	modified:   app/code/core/Mage/XmlConnect/Block/Customer/Form/Renderer/Multiline.php
	modified:   app/code/core/Mage/XmlConnect/Block/Customer/Form/Renderer/Multiselect.php
	modified:   app/code/core/Mage/XmlConnect/Block/Customer/Form/Renderer/Select.php
	modified:   app/code/core/Mage/XmlConnect/Block/Customer/Form/Renderer/Text.php
	modified:   app/code/core/Mage/XmlConnect/Block/Customer/GiftcardCheck.php
	modified:   app/code/core/Mage/XmlConnect/Block/Customer/Order/Item/Renderer/Giftcard.php
	modified:   app/code/core/Mage/XmlConnect/Block/Customer/Order/Totals/Customerbalance.php
	modified:   app/code/core/Mage/XmlConnect/Block/Customer/Order/Totals/Customerbalance/Refunded.php
	modified:   app/code/core/Mage/XmlConnect/Block/Customer/Order/Totals/Giftcards.php
	modified:   composer.json
	modified:   lib/Varien/Db/Exception.php
	modified:   lib/Varien/Db/Tree.php
	modified:   lib/Varien/Db/Tree/Exception.php
	modified:   lib/Varien/Db/Tree/Node.php
	modified:   lib/Varien/Directory/Collection.php
	modified:   lib/Varien/Directory/Factory.php
	modified:   lib/Varien/File/CsvMulty.php
	modified:   lib/Varien/File/Object.php
	modified:   lib/Varien/Io/Sftp.php
	modified:   lib/Varien/Object.php
	modified:   lib/Varien/Pear.php
	modified:   lib/Varien/Pear/Package.php
	deleted:    lib/Zend/Date.php
	deleted:    lib/Zend/Db/Select.php
	deleted:    lib/Zend/Db/Statement.php
	deleted:    lib/Zend/Mime.php
	deleted:    lib/Zend/Serializer/Adapter/PhpCode.php
	deleted:    lib/Zend/Validate/Hostname.php
	deleted:    lib/Zend/Xml/Security.php

This is the configuration used for phpstan:

	autoload_directories:
		- %rootDir%/../../../app/code/community
		- %rootDir%/../../../app/code/core
		- %rootDir%/../../../lib/Varien
		- %rootDir%/../../../lib/Zend
	autoload_files:
		- %rootDir%/../../../lib/Varien/Autoload.php

And this is the command:
vendor/bin/phpstan analyze -vvv -l 0 -c phpstan.neon app/code/
I'm sure I'm doing something wrong with the autoloading, as I get thousands of errors like "Call to static method app() on an unknown class Mage."
But if I use %rootDir%/../../../app/Mage.php instead of %rootDir%/../../../lib/Varien/Autoload.php I get all sorts of other issues with PEAR classes and so on.

Anyone interested in helping me out? Using phpstan would greatly help finding issues on magento, and would be a first step for the upcoming CI environment that's needed for the project.

@Flyingmana
Copy link
Contributor

first yes, you need to load the Mage.php, there is no way around it.
And "autoload_files" does not refer to a file for autoloading, but is a list of single files which you want to be loaded, which are not part of the already loaded directories.
Also you should add the whole /lib/ directory, as all directories in there are loaded, which may solve the PEAR classes issue, or creates very big list of errors, because PEAR classes did already produce php warnings in masses with php 5.

I hope this helps a bit

@akira28
Copy link
Author

akira28 commented Nov 12, 2017

I'm down to 4584 errors, using this configuration:

parameters:
	ignoreErrors:
		- '#Using \$this outside a class#'
		- '#Undefined variable: \$this#'
	autoload_directories:
		- %rootDir%/../../../app/code/community
		- %rootDir%/../../../app/code/core
		- %rootDir%/../../../lib/
	autoload_files:
		#- %rootDir%/../../../lib/Varien/Autoload.php
		- %rootDir%/../../../app/Mage.php
includes:
	- vendor/BudsiesApp/phpstan-magento/extension.neon

and modifying these files:

app/code/core/Mage/Admin/Model/Acl/Assert/Ip.php
app/code/core/Mage/Admin/Model/Acl/Assert/Time.php
app/code/core/Mage/Adminhtml/Block/Widget/Grid/Block.php
app/code/core/Mage/Adminhtml/Model/Extension.php
app/code/core/Mage/Api/Model/Acl/Assert/Ip.php
app/code/core/Mage/Api/Model/Acl/Assert/Time.php
app/code/core/Mage/CurrencySymbol/Model/Observer.php
app/code/core/Mage/Dataflow/Model/Convert/Iterator.php
app/code/core/Mage/Dataflow/Model/Convert/Iterator/File/Csv.php
app/code/core/Mage/Dataflow/Model/Convert/Iterator/Http.php
app/code/core/Mage/Dataflow/Model/Session/Adapter/Http.php
app/code/core/Mage/Install/Model/Installer/Pear.php
app/code/core/Mage/Payment/Model/Paygate/Request.php
app/code/core/Mage/XmlConnect/Block/Checkout/Cart/Item/Renderer/Giftcard.php
app/code/core/Mage/XmlConnect/Block/Checkout/Payment/Method/Pbridge/Abstract.php
app/code/core/Mage/XmlConnect/Block/Customer/Form/Renderer/Date.php
app/code/core/Mage/XmlConnect/Block/Customer/Form/Renderer/File.php
app/code/core/Mage/XmlConnect/Block/Customer/Form/Renderer/Multiline.php
app/code/core/Mage/XmlConnect/Block/Customer/Form/Renderer/Multiselect.php
app/code/core/Mage/XmlConnect/Block/Customer/Form/Renderer/Select.php
app/code/core/Mage/XmlConnect/Block/Customer/Form/Renderer/Text.php
app/code/core/Mage/XmlConnect/Block/Customer/GiftcardCheck.php
app/code/core/Mage/XmlConnect/Block/Customer/Order/Item/Renderer/Giftcard.php
app/code/core/Mage/XmlConnect/Block/Customer/Order/Totals/Customerbalance.php
app/code/core/Mage/XmlConnect/Block/Customer/Order/Totals/Customerbalance/Refunded.php
app/code/core/Mage/XmlConnect/Block/Customer/Order/Totals/Giftcards.php
lib/Mage/Backup/Exception.php.bk
lib/PEAR/PEAR/PEAR.php.bk
lib/Varien/Pear.php.bk
lib/Varien/Pear/Package.php
lib/Varien/Simplexml/Element.php.bk
lib/Zend/Date.php.bk
lib/Zend/Db/Select.php.bk
lib/Zend/Db/Statement.php.bk
lib/Zend/Mime.php.bk
lib/Zend/Serializer/Adapter/PhpCode.php.bk
lib/Zend/Validate/Hostname.php.bk
lib/Zend/Xml/Security.php.bk

Lots of them are like these:

code/core/Mage/Reports/Model/Grouped/Collection.php 
Internal error: Call to a member function getIdFieldName() on boolean

and

code/core/Mage/Reports/Block/Product/Widget/Viewed.php
Error (Call to a member function getIdFieldName() on boolean) thrown while autoloading class parent.

Any suggestion on how to solve these?

@sreichel
Copy link
Contributor

Guess the errors come from magic getter/setter mehtods. Please check this: https://github.com/fooman/phpstan-magento2-magic-methods. May you can add something similiar for M1?

Btw ... i think this projects need some pleanup before PHPSTAN work properbly.

  • remove duplicated classes
  • fix some DOC blocks
  • get lot of autoloader errors for controllers
  • ...

@FredericMartinez
Copy link
Contributor

@sreichel about magic getter/setter methods (Mage::helper(), Mage::getModel(), Mage::getResourceModel(), Mage::getSingleton(), Mage_Core_Model_Layout->helper()), for M1 you can use https://github.com/BudsiesApp/phpstan-magento

@sreichel
Copy link
Contributor

Lots of them are like these:

code/core/Mage/Reports/Model/Grouped/Collection.php 
Internal error: Call to a member function getIdFieldName() on boolean

Seems to come from wrong or not existing annotations ... when these are added phpstan seems to work really fine. I use https://github.com/inviqa/phpstan-magento1

includes:
    - vendor/inviqa/phpstan-magento1/extension.neon
parameters:
    reportUnmatchedIgnoredErrors: false
    autoload_files:
        - %currentWorkingDirectory%/app/Mage.php
    ignoreErrors:
        -
            message: '#Undefined variable: \$this#'
            paths:
                - %currentWorkingDirectory%/app/code/*/*/*/data/*
                - %currentWorkingDirectory%/app/code/*/*/*/sql/*
        -
            message: '#Using \$this outside a class.#'
            paths:
                - %currentWorkingDirectory%/app/code/*/*/*/data/*
                - %currentWorkingDirectory%/app/code/*/*/*/sql/*

You have to exclude controllers too, because autoloading doesnt work. If phpstan stops without error message, add --debug option and check wich files fails.

It should be a call to helper/model with a variable name Mage::helper($someVar). Exclude the file or try @phpstan-ignore-next-line annotation ...

Happy analyzing :P

@kkrieger85
Copy link
Contributor

@sreichel This could also be part of captainhook config ;)

Example action: "action": "php ./vendor/phpstan/phpstan/bin/phpstan analyse -l 7 -c phpstan.neon ./"

@tmotyl
Copy link
Contributor

tmotyl commented Jun 29, 2021

Hi
I've seen a fork of inviqa/phpstan-magento1 from @sreichel https://github.com/sreichel/phpstan-magento1/
and one from ateli-development https://github.com/ateli-development/phpstan-magento1 created by @christophmassmann
The second one looks more up-to-date to the newest phpstan and have more magento related tweks.

It sounds like it would be good to join forces and have one fork which could be used in projects and to analyze OpenMage source code.
Does anybody has experience in running newest phpstan with openmage projects/extensions

@ma4nn
Copy link
Contributor

ma4nn commented Jul 19, 2021

Hi @tmotyl,

thanks for mentioning me. I have created this repository https://github.com/vianetz/phpstan-magento1 as I also recognized that most phpstan forks for Magento 1 have been abandoned or were not updated since a long time.

I'm using this phpstan library for checking all custom code in my Magento 1 projects and it's working fine so far.
Would love to join forces if anyone is interested in.

Best regards,
Christoph

@tmotyl
Copy link
Contributor

tmotyl commented Jul 19, 2021

@christophmassmann great to hear from you.
As a good start I think the following changes would be great:

  1. Replace deprecated excludes_analyse with excludePaths ateli-development/phpstan-magento1#2
  2. Handle case when getResourceModelClassName returns false ateli-development/phpstan-magento1#3
  3. check if https://github.com/inviqa/phpstan-magento1/pull/4/files brings more value, or is already solved maybe @sreichel can also shed some light here

Then:

  1. run phpstan with openmage core (can be with big baseline list of known errors), so we're sure we don't introduce new ones
  2. figure out a way to use phpstan without db connection (this approach would be also useful for unit testing I believe)

@tmotyl
Copy link
Contributor

tmotyl commented Sep 23, 2021

FYI, I managed to run phpstan without db connection, will publish it in near future.

I would also recommend to move the code execution from beginning of the "Mage" file (so there is only class inside), to separate bootstrapping/autoloading logic from class definition.
Also having a way in openmage core to load XML configuration from extensions without having to initialize a db connection would simplify setup of phpstan and all other tools like rector or writing unit tests.

@tmotyl
Copy link
Contributor

tmotyl commented Sep 27, 2021

Here you go:
https://github.com/macopedia/phpstan-magento1
This module can run without db connection. @sreichel I would be happy to chat with you about the changes you did in https://github.com/inviqa/phpstan-magento1/pull/4/files should I incorporate them in my fork too?

@tmotyl
Copy link
Contributor

tmotyl commented Sep 27, 2021

I've made a PR which adds a phpstan configuration file to openMage #1837
Would be nice if somebody could build a github action based on it.

@ma4nn
Copy link
Contributor

ma4nn commented Oct 5, 2021

Here you go: https://github.com/macopedia/phpstan-magento1 This module can run without db connection.

@tmotyl very cool, nice work, thanks for your effort! Sorry that I didn't had the time yet to have a look into this issue myself 😢

While checking your modifications and comparing them with my version I noticed some things:

  • When I execute your version it is significantly slower than my version (about 10 times) - do you have any idea why?
  • What I do not like so much is the duplication of the Magento core config class, although I can understand your reasoning from above
  • A database connection should also not be necessary in my approach if no local.xml file is present (Mage::_isInstalled = false then)

Anyway having the awesome phpstan tool now working with OpenMage/Magento 1 is great!

@tmotyl
Copy link
Contributor

tmotyl commented Oct 5, 2021

@christophmassmann the slowness comes most probably from static reflection - the phpstan ability to analyze class without executing it. But its just a wild guess.

I dont expect magento config to change too much so maintaining the copy doesnt sound as a big issue. But im open to other solutions.

Thanks for the hint about local.xml - does your solution loads extension config (thus class aliases) then too?

@sreichel
Copy link
Contributor

sreichel commented Oct 5, 2021

@tmotyl @christophmassmann great work!

@sreichel I would be happy to chat with you about the changes you did in https://github.com/inviqa/phpstan-magento1/pull/4/files should I incorporate them in my fork too?

I'll test your PR later :)

@ma4nn
Copy link
Contributor

ma4nn commented Oct 6, 2021

the slowness comes most probably from static reflection - the phpstan ability to analyze class without executing it. But its just a wild guess.

but this should be the same in both approaches then, right?

Thanks for the hint about local.xml - does your solution loads extension config (thus class aliases) then too?

Yes.

@tmotyl
Copy link
Contributor

tmotyl commented Oct 6, 2021

but this should be the same in both approaches then, right?

afaik static analysis is somehow autodetected and used for classes which are not autoloaded.

@tmotyl
Copy link
Contributor

tmotyl commented Mar 9, 2022

Little update:
I've released few more updates to https://github.com/macopedia/phpstan-magento1/releases/tag/v1.0.4
-> it nows handles gracefully when variable is passed to a factory e.g. Mage::helper($someVar)
-> it allows both approaches to load Mage class and config "my way" - with static reflection, and the other way which relies on autoloader and executes code of Mage. Worth noticing, that "my way" is now almost as fast as the old way.

I've prepared a PR which makes almost whole openmage code being analyzed:
#2035

I'm closing this issue as it's already resolved:

  • we have a way to run phpstan in openmage core and in projects.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Development

Successfully merging a pull request may close this issue.

7 participants