Skip to content

Commit

Permalink
Add new extension-mage-autoload.neon to run stan without static refle…
Browse files Browse the repository at this point in the history
…ction

This extension provides 2 configs:
extension-mage-autoload.neon (without static reflection,
Mage is autoloaded and executed)
extension.neon (Mage.php is not executed thanks to the static reflection)
Both modes now run with similar performance, thanks to the config cacheing.
  • Loading branch information
tmotyl committed Mar 7, 2022
1 parent c6b31c1 commit c615c3e
Show file tree
Hide file tree
Showing 6 changed files with 110 additions and 22 deletions.
12 changes: 4 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ It doesn't require db connection to run.

## Usage

Add `phpstan.neon` to your Magento 1 project.
Add `phpstan.neon` to your Magento 1/OpenMage project.

Make sure it has

Expand Down Expand Up @@ -40,10 +40,6 @@ includes:
- vendor/macopedia/phpstan-magento1/extension.neon
parameters:
magentoRootPath: %currentWorkingDirectory%/htdocs
paths:
- %currentWorkingDirectory%/path/to/magento/app/code/local
autoload_files:
- %currentWorkingDirectory%/path/to/magento/app/Mage.php
paths:
#lets start small with just our extensions
- %currentWorkingDirectory%/app/code/local/VendorName/ModuleName
Expand All @@ -56,7 +52,7 @@ parameters:

## Data/SQL scripts can't be tested

Since these scripts use a presumed $this variable due to being included from a setup class, work is needed to:
Since these scripts use a presumed `$this` variable due to being included from a setup class, work is needed to:

* work out the correct setup class
* somehow make phpstan aware of it for the file
Expand All @@ -65,7 +61,7 @@ Since these scripts use a presumed $this variable due to being included from a s

This causes subsequent calls to the class object to assume the scope of the super-class that defined the return type.

This is due to their PHPDoc not using the up to date way of specifying fluency with subclasses using "$this" as the type.
This is due to their PHPDoc not using the up to date way of specifying fluency with subclasses using `$this` as the type.

Options to resolve:

Expand All @@ -74,7 +70,7 @@ Options to resolve:
* Define @method PHPDoc for the called methods in the subclass
* Add the error to the parameters.ignoreErrors phpstan configuration to ignore it - this loses the ability to properly type the subseqent methods of the fluent interface

## Mage_Core_Model_Abstract::load $id is not an integer
## Mage_Core_Model_Abstract::load `$id` is not an integer

This is due to an inadequate PHPDoc of the load method of the Mage_Core_Model_Abstract class. It should have used a "mixed" type to support when a field is specified as the 2nd argument.

Expand Down
53 changes: 53 additions & 0 deletions extension-mage-autoload.neon
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# This configuration file doesn't use static reflection for loading Mage class (so it executes code of Mage file).
# Make sure you DON'T have local.xml file in your project when using this config. Otherwise you'll get errors
# about connecting to db
# this config will also throw warnings "PHP Warning: Constant DS already defined in", this is an issue in phpstan
# https://github.com/phpstan/phpstan/issues/6744#event-6194525980
parametersSchema:
magentoRootPath: string()
parameters:
magentoRootPath: %currentWorkingDirectory%/htdocs
staticReflection: false
excludePaths:
- */app/code/local/*/*/data/*
- */app/code/local/*/*/sql/*
bootstrapFiles:
- %magentoRootPath%/app/Mage.php
- phpstan-bootstrap-mage-autoload.php

typeAliases:
Mage_Catalog_Model_Entity_Product_Collection: 'Mage_Catalog_Model_Resource_Product_Collection'
callback: 'callable'
earlyTerminatingMethodCalls:
Mage:
- throwException

services:
-
class: PHPStanMagento1\Reflection\Varien\Object\MagicMethodsReflectionExtension
tags:
- phpstan.broker.methodsClassReflectionExtension
-
class: PHPStanMagento1\Type\Mage\CoreModelLayout\Helper
tags:
- phpstan.broker.dynamicMethodReturnTypeExtension
-
class: PHPStanMagento1\Type\Mage\CoreModelLayout\GetBlockSingleton
tags:
- phpstan.broker.dynamicMethodReturnTypeExtension
-
class: PHPStanMagento1\Type\Mage\GetModel
tags:
- phpstan.broker.dynamicStaticMethodReturnTypeExtension
-
class: PHPStanMagento1\Type\Mage\GetResourceModel
tags:
- phpstan.broker.dynamicStaticMethodReturnTypeExtension
-
class: PHPStanMagento1\Type\Mage\GetSingleton
tags:
- phpstan.broker.dynamicStaticMethodReturnTypeExtension
-
class: PHPStanMagento1\Type\Mage\Helper
tags:
- phpstan.broker.dynamicStaticMethodReturnTypeExtension
7 changes: 0 additions & 7 deletions extension.neon
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,6 @@ parameters:
- phpstan-bootstrap.php
scanFiles:
- %magentoRootPath%/app/Mage.php
- %magentoRootPath%/app/code/core/Mage/Core/functions.php
scanDirectories:
#for static reflection, so we don't have to call autoloader
- %magentoRootPath%/lib/
- %magentoRootPath%/app/code/local/
- %magentoRootPath%/app/code/community/
- %magentoRootPath%/app/code/core/
typeAliases:
Mage_Catalog_Model_Entity_Product_Collection: 'Mage_Catalog_Model_Resource_Product_Collection'
callback: 'callable'
Expand Down
41 changes: 41 additions & 0 deletions phpstan-bootstrap-mage-autoload.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<?php
declare(strict_types=1);

use PHPStanMagento1\Autoload\Magento\ModuleControllerAutoloader;

/**
* @var $container \PHPStan\DependencyInjection\MemoizingContainer
*/
$magentoRootPath = $container->getParameter('magentoRootPath');
if (empty($magentoRootPath)) {
throw new \Exception('Please set "magentoRootPath" in your phpstan.neon.');
}

if (!defined('BP')) {
define('BP', $magentoRootPath);
}

(new ModuleControllerAutoloader('local'))->register();
(new ModuleControllerAutoloader('core'))->register();
(new ModuleControllerAutoloader('community'))->register();

/**
* We replace the original Varien_Autoload autoloader with a custom one in order to prevent errors with invalid classes
* that are used throughout the Magento core code.
* The original autoloader would in this case return false and lead to an error in phpstan because the type alias in extension.neon
* is evaluated afterwards.
*
* @see \Varien_Autoload::autoload()
*/
spl_autoload_register(static function($className) {
spl_autoload_unregister([Varien_Autoload::instance(), 'autoload']);

$classFile = str_replace(' ', DIRECTORY_SEPARATOR, ucwords(str_replace('_', ' ', $className)));
$classFile .= '.php';

foreach (explode(':', get_include_path()) as $path) {
if (\file_exists($path . DIRECTORY_SEPARATOR . $classFile)) {
return include $classFile;
}
}
}, true, true);
16 changes: 9 additions & 7 deletions phpstan-bootstrap.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,6 @@

use PHPStanMagento1\Autoload\Magento\ModuleControllerAutoloader;

if (!defined('DS')) {
define('DS', DIRECTORY_SEPARATOR);
}
if (!defined('PS')) {
define('PS', PATH_SEPARATOR);
}

/**
* @var $container \PHPStan\DependencyInjection\MemoizingContainer
*/
Expand All @@ -22,6 +15,15 @@
define('BP', $magentoRootPath);
}

define('staticReflection', true);

if (!defined('DS')) {
define('DS', DIRECTORY_SEPARATOR);
}
if (!defined('PS')) {
define('PS', PATH_SEPARATOR);
}

/**
* Set include path
*/
Expand Down
3 changes: 3 additions & 0 deletions src/Type/Mage/GetResourceModel.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@

final class GetResourceModel extends StaticMethodReturnTypeDetector
{
/**
* @throws \PHPStan\Broker\ClassNotFoundException
*/
public function getMagentoClassName(string $identifier): string
{
$className = $this->getMagentoConfig()->getResourceModelClassName($identifier);
Expand Down

0 comments on commit c615c3e

Please sign in to comment.