Problem/Motivation

error:

Vendor binary path not correct or phpstan is not installed there. Did you install Upgrade Status with composer? Checked: /var/www/html/docroot/vendor/bin/phpstan

Steps to reproduce

  • using ddev multisite
  • core 8.9.3
  • Upgrade Status was installed using composer require 'drupal/upgrade_status:^2.0'
  • upgrade_status module was enable
  • on the Upgrade Status page: /admin/reports/upgrade-status , there is a warning:

Vendor binary path not correct or phpstan is not installed there. Did you install Upgrade Status with composer? Checked: /var/www/html/docroot/vendor/bin/phpstan

Proposed resolution

Remaining tasks

User interface changes

API changes

Data model changes

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

mario.elias created an issue. See original summary.

Gábor Hojtsy’s picture

Category: Bug report » Support request
Status: Active » Postponed (maintainer needs more info)

Is phpstan actually in /var/www/html/docroot/vendor/bin/phpstan? If not, what would be the vendor directory to find it in?

mario.elias’s picture

On my environment the file is under /var/www/html/vendor/bin/phpstan

ls -l   /var/www/html/vendor/bin/phpstan
lrwxr-xr-x 1 user user 26 Aug 14 09:25 /var/www/html/vendor/bin/phpstan -> ../phpstan/phpstan/phpstan

I used composer to install. Below are the files added
git diff --name-only da3477f52 8c4d91bf9

composer.json
composer.lock
docroot/modules/contrib/upgrade_status/LICENSE.txt
docroot/modules/contrib/upgrade_status/README.md
docroot/modules/contrib/upgrade_status/composer.json
docroot/modules/contrib/upgrade_status/config/install/upgrade_status.settings.yml
docroot/modules/contrib/upgrade_status/config/schema/upgrade_status.schema.yml
docroot/modules/contrib/upgrade_status/css/upgrade_status.admin.theme.css
docroot/modules/contrib/upgrade_status/deprecation_testing.neon
docroot/modules/contrib/upgrade_status/drush.services.yml
docroot/modules/contrib/upgrade_status/icons/check.svg
docroot/modules/contrib/upgrade_status/icons/error.svg
docroot/modules/contrib/upgrade_status/icons/ex.svg
docroot/modules/contrib/upgrade_status/icons/questionmark-disc.svg
docroot/modules/contrib/upgrade_status/icons/warning.svg
docroot/modules/contrib/upgrade_status/icons/wrench.svg
docroot/modules/contrib/upgrade_status/src/Commands/UpgradeStatusCommands.php
docroot/modules/contrib/upgrade_status/src/Controller/ScanResultController.php
docroot/modules/contrib/upgrade_status/src/DeprecationAnalyzer.php
docroot/modules/contrib/upgrade_status/src/DeprecationMessage.php
docroot/modules/contrib/upgrade_status/src/Form/UpgradeStatusForm.php
docroot/modules/contrib/upgrade_status/src/LibraryDeprecationAnalyzer.php
docroot/modules/contrib/upgrade_status/src/ProjectCollector.php
docroot/modules/contrib/upgrade_status/src/ScanResultFormatter.php
docroot/modules/contrib/upgrade_status/src/ThemeFunctionDeprecationAnalyzer.php
docroot/modules/contrib/upgrade_status/templates/upgrade-status-ascii-export.html.twig
docroot/modules/contrib/upgrade_status/templates/upgrade-status-html-export.html.twig
docroot/modules/contrib/upgrade_status/templates/upgrade-status-summary-counter.html.twig
docroot/modules/contrib/upgrade_status/tests/modules/upgrade_status_test_contrib_error/src/Controller/UpgradeStatusTestContribErrorController.php
docroot/modules/contrib/upgrade_status/tests/modules/upgrade_status_test_contrib_error/upgrade_status_test_contrib_error.info.yml
docroot/modules/contrib/upgrade_status/tests/modules/upgrade_status_test_contrib_no_error/upgrade_status_test_contrib_no_error.info.yml
docroot/modules/contrib/upgrade_status/tests/modules/upgrade_status_test_error/fatal.php
docroot/modules/contrib/upgrade_status/tests/modules/upgrade_status_test_error/src/Controller/UpgradeStatusTestErrorController.php
docroot/modules/contrib/upgrade_status/tests/modules/upgrade_status_test_error/src/DummyTestClass.php
docroot/modules/contrib/upgrade_status/tests/modules/upgrade_status_test_error/upgrade_status_test_error.info.yml
docroot/modules/contrib/upgrade_status/tests/modules/upgrade_status_test_library/upgrade_status_test_library.info.yml
docroot/modules/contrib/upgrade_status/tests/modules/upgrade_status_test_library/upgrade_status_test_library.libraries.yml
docroot/modules/contrib/upgrade_status/tests/modules/upgrade_status_test_library/upgrade_status_test_library.module
docroot/modules/contrib/upgrade_status/tests/modules/upgrade_status_test_library_exception/upgrade_status_test_library_exception.info.yml
docroot/modules/contrib/upgrade_status/tests/modules/upgrade_status_test_library_exception/upgrade_status_test_library_exception.libraries.yml
docroot/modules/contrib/upgrade_status/tests/modules/upgrade_status_test_no_error/upgrade_status_test_no_error.info.yml
docroot/modules/contrib/upgrade_status/tests/modules/upgrade_status_test_submodules/modules/upgrade_status_test_submodules_a/upgrade_status_test_submodules_a.info.yml
docroot/modules/contrib/upgrade_status/tests/modules/upgrade_status_test_submodules/upgrade_status_test_submodules.info.yml
docroot/modules/contrib/upgrade_status/tests/modules/upgrade_status_test_submodules_with_error/modules/upgrade_status_test_submodules_with_error_a/upgrade_status_test_submodules_with_error_a.info.yml
docroot/modules/contrib/upgrade_status/tests/modules/upgrade_status_test_submodules_with_error/upgrade_status_test_submodules_with_error.info.yml
docroot/modules/contrib/upgrade_status/tests/modules/upgrade_status_test_theme_functions/upgrade_status_test_theme_functions.info.yml
docroot/modules/contrib/upgrade_status/tests/modules/upgrade_status_test_theme_functions/upgrade_status_test_theme_functions.module
docroot/modules/contrib/upgrade_status/tests/modules/upgrade_status_test_twig/templates/test.html.twig
docroot/modules/contrib/upgrade_status/tests/modules/upgrade_status_test_twig/upgrade_status_test_twig.info.yml
docroot/modules/contrib/upgrade_status/tests/modules/upgrade_status_test_twig/upgrade_status_test_twig.libraries.yml
docroot/modules/contrib/upgrade_status/tests/src/Functional/UpgradeStatusAccessTest.php
docroot/modules/contrib/upgrade_status/tests/src/Functional/UpgradeStatusAnalyzeTest.php
docroot/modules/contrib/upgrade_status/tests/src/Functional/UpgradeStatusTestBase.php
docroot/modules/contrib/upgrade_status/tests/src/Functional/UpgradeStatusUiTest.php
docroot/modules/contrib/upgrade_status/tests/themes/upgrade_status_test_theme/templates/test.html.twig
docroot/modules/contrib/upgrade_status/tests/themes/upgrade_status_test_theme/upgrade_status_test_theme.info.yml
docroot/modules/contrib/upgrade_status/tests/themes/upgrade_status_test_theme/upgrade_status_test_theme.libraries.yml
docroot/modules/contrib/upgrade_status/tests/themes/upgrade_status_test_theme/upgrade_status_test_theme.theme
docroot/modules/contrib/upgrade_status/upgrade_status.api.php
docroot/modules/contrib/upgrade_status/upgrade_status.info.yml
docroot/modules/contrib/upgrade_status/upgrade_status.install
docroot/modules/contrib/upgrade_status/upgrade_status.libraries.yml
docroot/modules/contrib/upgrade_status/upgrade_status.links.menu.yml
docroot/modules/contrib/upgrade_status/upgrade_status.module
docroot/modules/contrib/upgrade_status/upgrade_status.routing.yml
docroot/modules/contrib/upgrade_status/upgrade_status.services.yml
vendor/bin/generate-deps-for-config-factory
vendor/bin/generate-factory-for-class
vendor/bin/phpstan
vendor/bin/phpstan.phar
vendor/composer/autoload_classmap.php
vendor/composer/autoload_files.php
vendor/composer/autoload_psr4.php
vendor/composer/autoload_static.php
vendor/composer/installed.json
vendor/laminas/laminas-servicemanager/CHANGELOG.md
vendor/laminas/laminas-servicemanager/COPYRIGHT.md
vendor/laminas/laminas-servicemanager/LICENSE.md
vendor/laminas/laminas-servicemanager/README.md
vendor/laminas/laminas-servicemanager/bin/generate-deps-for-config-factory
vendor/laminas/laminas-servicemanager/bin/generate-factory-for-class
vendor/laminas/laminas-servicemanager/composer.json
vendor/laminas/laminas-servicemanager/src/AbstractFactory/ConfigAbstractFactory.php
vendor/laminas/laminas-servicemanager/src/AbstractFactory/ReflectionBasedAbstractFactory.php
vendor/laminas/laminas-servicemanager/src/AbstractFactoryInterface.php
vendor/laminas/laminas-servicemanager/src/AbstractPluginManager.php
vendor/laminas/laminas-servicemanager/src/Config.php
vendor/laminas/laminas-servicemanager/src/ConfigInterface.php
vendor/laminas/laminas-servicemanager/src/DelegatorFactoryInterface.php
vendor/laminas/laminas-servicemanager/src/Exception/ContainerModificationsNotAllowedException.php
vendor/laminas/laminas-servicemanager/src/Exception/CyclicAliasException.php
vendor/laminas/laminas-servicemanager/src/Exception/ExceptionInterface.php
vendor/laminas/laminas-servicemanager/src/Exception/InvalidArgumentException.php
vendor/laminas/laminas-servicemanager/src/Exception/InvalidServiceException.php
vendor/laminas/laminas-servicemanager/src/Exception/ServiceNotCreatedException.php
vendor/laminas/laminas-servicemanager/src/Exception/ServiceNotFoundException.php
vendor/laminas/laminas-servicemanager/src/Factory/AbstractFactoryInterface.php
vendor/laminas/laminas-servicemanager/src/Factory/DelegatorFactoryInterface.php
vendor/laminas/laminas-servicemanager/src/Factory/FactoryInterface.php
vendor/laminas/laminas-servicemanager/src/Factory/InvokableFactory.php
vendor/laminas/laminas-servicemanager/src/FactoryInterface.php
vendor/laminas/laminas-servicemanager/src/Initializer/InitializerInterface.php
vendor/laminas/laminas-servicemanager/src/InitializerInterface.php
vendor/laminas/laminas-servicemanager/src/PluginManagerInterface.php
vendor/laminas/laminas-servicemanager/src/Proxy/LazyServiceFactory.php
vendor/laminas/laminas-servicemanager/src/PsrContainerDecorator.php
vendor/laminas/laminas-servicemanager/src/ServiceLocatorInterface.php
vendor/laminas/laminas-servicemanager/src/ServiceManager.php
vendor/laminas/laminas-servicemanager/src/Test/CommonPluginManagerTrait.php
vendor/laminas/laminas-servicemanager/src/Tool/ConfigDumper.php
vendor/laminas/laminas-servicemanager/src/Tool/ConfigDumperCommand.php
vendor/laminas/laminas-servicemanager/src/Tool/FactoryCreator.php
vendor/laminas/laminas-servicemanager/src/Tool/FactoryCreatorCommand.php
vendor/laminas/laminas-text/CHANGELOG.md
vendor/laminas/laminas-text/COPYRIGHT.md
vendor/laminas/laminas-text/LICENSE.md
vendor/laminas/laminas-text/README.md
vendor/laminas/laminas-text/composer.json
vendor/laminas/laminas-text/src/Exception/ExceptionInterface.php
vendor/laminas/laminas-text/src/Exception/InvalidArgumentException.php
vendor/laminas/laminas-text/src/Exception/OutOfBoundsException.php
vendor/laminas/laminas-text/src/Exception/OverflowException.php
vendor/laminas/laminas-text/src/Exception/RuntimeException.php
vendor/laminas/laminas-text/src/Exception/UnexpectedValueException.php
vendor/laminas/laminas-text/src/Figlet/Exception/ExceptionInterface.php
vendor/laminas/laminas-text/src/Figlet/Exception/InvalidArgumentException.php
vendor/laminas/laminas-text/src/Figlet/Exception/RuntimeException.php
vendor/laminas/laminas-text/src/Figlet/Exception/UnexpectedValueException.php
vendor/laminas/laminas-text/src/Figlet/Figlet.php
vendor/laminas/laminas-text/src/Figlet/laminas-project.flf
vendor/laminas/laminas-text/src/MultiByte.php
vendor/laminas/laminas-text/src/Table/Column.php
vendor/laminas/laminas-text/src/Table/Decorator/Ascii.php
vendor/laminas/laminas-text/src/Table/Decorator/Blank.php
vendor/laminas/laminas-text/src/Table/Decorator/DecoratorInterface.php
vendor/laminas/laminas-text/src/Table/Decorator/Unicode.php
vendor/laminas/laminas-text/src/Table/DecoratorManager.php
vendor/laminas/laminas-text/src/Table/Exception/ExceptionInterface.php
vendor/laminas/laminas-text/src/Table/Exception/InvalidArgumentException.php
vendor/laminas/laminas-text/src/Table/Exception/InvalidDecoratorException.php
vendor/laminas/laminas-text/src/Table/Exception/OutOfBoundsException.php
vendor/laminas/laminas-text/src/Table/Exception/OverflowException.php
vendor/laminas/laminas-text/src/Table/Exception/UnexpectedValueException.php
vendor/laminas/laminas-text/src/Table/Row.php
vendor/laminas/laminas-text/src/Table/Table.php
vendor/mathieuviossat/arraytotexttable/.gitignore
vendor/mathieuviossat/arraytotexttable/LICENSE
vendor/mathieuviossat/arraytotexttable/README.md
vendor/mathieuviossat/arraytotexttable/composer.json
vendor/mathieuviossat/arraytotexttable/composer.lock
vendor/mathieuviossat/arraytotexttable/src/ArrayToTextTable.php
vendor/mglaman/phpstan-drupal/.circleci/config.yml
vendor/mglaman/phpstan-drupal/.circleci/generate-local-config.sh
vendor/mglaman/phpstan-drupal/.circleci/run-local-config.sh
vendor/mglaman/phpstan-drupal/.editorconfig
vendor/mglaman/phpstan-drupal/.github/FUNDING.yml
vendor/mglaman/phpstan-drupal/.github/SECURITY.md
vendor/mglaman/phpstan-drupal/LICENSE
vendor/mglaman/phpstan-drupal/README.md
vendor/mglaman/phpstan-drupal/composer.json
vendor/mglaman/phpstan-drupal/drupal-autoloader.php
vendor/mglaman/phpstan-drupal/extension.neon
vendor/mglaman/phpstan-drupal/phpunit.xml
vendor/mglaman/phpstan-drupal/src/Drupal/DrupalAutoloader.php
vendor/mglaman/phpstan-drupal/src/Drupal/DrupalServiceDefinition.php
vendor/mglaman/phpstan-drupal/src/Drupal/Extension.php
vendor/mglaman/phpstan-drupal/src/Drupal/ExtensionDiscovery.php
vendor/mglaman/phpstan-drupal/src/Drupal/RecursiveExtensionFilterIterator.php
vendor/mglaman/phpstan-drupal/src/Drupal/ServiceMap.php
vendor/mglaman/phpstan-drupal/src/Reflection/EntityFieldReflection.php
vendor/mglaman/phpstan-drupal/src/Reflection/EntityFieldsViaMagicReflectionExtension.php
vendor/mglaman/phpstan-drupal/src/Reflection/FieldItemListPropertyReflection.php
vendor/mglaman/phpstan-drupal/src/Rules/Classes/EnhancedRequireParentConstructCallRule.php
vendor/mglaman/phpstan-drupal/src/Rules/Classes/PluginManagerInspectionRule.php
vendor/mglaman/phpstan-drupal/src/Rules/Deprecations/AccessDeprecatedConstant.php
vendor/mglaman/phpstan-drupal/src/Rules/Drupal/Coder/DiscouragedFunctionsRule.php
vendor/mglaman/phpstan-drupal/src/Rules/Drupal/GlobalDrupalDependencyInjectionRule.php
vendor/mglaman/phpstan-drupal/src/Rules/Drupal/LoadIncludes.php
vendor/mglaman/phpstan-drupal/src/Rules/Drupal/PluginManager/AbstractPluginManagerRule.php
vendor/mglaman/phpstan-drupal/src/Rules/Drupal/PluginManager/PluginManagerSetsCacheBackendRule.php
vendor/mglaman/phpstan-drupal/src/Type/EntityTypeManagerGetStorageDynamicReturnTypeExtension.php
vendor/mglaman/phpstan-drupal/src/Type/ServiceDynamicReturnTypeExtension.php
vendor/nette/finder/composer.json
vendor/nette/finder/contributing.md
vendor/nette/finder/license.md
vendor/nette/finder/readme.md
vendor/nette/finder/src/Utils/Finder.php
vendor/nette/utils/.phpstorm.meta.php
vendor/nette/utils/composer.json
vendor/nette/utils/contributing.md
vendor/nette/utils/license.md
vendor/nette/utils/readme.md
vendor/nette/utils/src/Iterators/CachingIterator.php
vendor/nette/utils/src/Iterators/Mapper.php
vendor/nette/utils/src/Utils/ArrayHash.php
vendor/nette/utils/src/Utils/ArrayList.php
vendor/nette/utils/src/Utils/Arrays.php
vendor/nette/utils/src/Utils/Callback.php
vendor/nette/utils/src/Utils/DateTime.php
vendor/nette/utils/src/Utils/FileSystem.php
vendor/nette/utils/src/Utils/Helpers.php
vendor/nette/utils/src/Utils/Html.php
vendor/nette/utils/src/Utils/IHtmlString.php
vendor/nette/utils/src/Utils/ITranslator.php
vendor/nette/utils/src/Utils/Image.php
vendor/nette/utils/src/Utils/Json.php
vendor/nette/utils/src/Utils/ObjectHelpers.php
vendor/nette/utils/src/Utils/ObjectMixin.php
vendor/nette/utils/src/Utils/Paginator.php
vendor/nette/utils/src/Utils/Random.php
vendor/nette/utils/src/Utils/Reflection.php
vendor/nette/utils/src/Utils/SmartObject.php
vendor/nette/utils/src/Utils/StaticClass.php
vendor/nette/utils/src/Utils/Strings.php
vendor/nette/utils/src/Utils/Validators.php
vendor/nette/utils/src/Utils/exceptions.php
vendor/phpstan/phpstan-deprecation-rules/.editorconfig
vendor/phpstan/phpstan-deprecation-rules/.gitattributes
vendor/phpstan/phpstan-deprecation-rules/.gitignore
vendor/phpstan/phpstan-deprecation-rules/.travis.yml
vendor/phpstan/phpstan-deprecation-rules/README.md
vendor/phpstan/phpstan-deprecation-rules/build.xml
vendor/phpstan/phpstan-deprecation-rules/composer.json
vendor/phpstan/phpstan-deprecation-rules/phpcs.xml
vendor/phpstan/phpstan-deprecation-rules/phpstan.neon
vendor/phpstan/phpstan-deprecation-rules/rules.neon
vendor/phpstan/phpstan-deprecation-rules/src/Rules/Deprecations/AccessDeprecatedPropertyRule.php
vendor/phpstan/phpstan-deprecation-rules/src/Rules/Deprecations/AccessDeprecatedStaticPropertyRule.php
vendor/phpstan/phpstan-deprecation-rules/src/Rules/Deprecations/CallToDeprecatedFunctionRule.php
vendor/phpstan/phpstan-deprecation-rules/src/Rules/Deprecations/CallToDeprecatedMethodRule.php
vendor/phpstan/phpstan-deprecation-rules/src/Rules/Deprecations/CallToDeprecatedStaticMethodRule.php
vendor/phpstan/phpstan-deprecation-rules/src/Rules/Deprecations/DeprecatedClassHelper.php
vendor/phpstan/phpstan-deprecation-rules/src/Rules/Deprecations/DeprecatedScopeHelper.php
vendor/phpstan/phpstan-deprecation-rules/src/Rules/Deprecations/FetchingClassConstOfDeprecatedClassRule.php
vendor/phpstan/phpstan-deprecation-rules/src/Rules/Deprecations/FetchingDeprecatedConstRule.php
vendor/phpstan/phpstan-deprecation-rules/src/Rules/Deprecations/ImplementationOfDeprecatedInterfaceRule.php
vendor/phpstan/phpstan-deprecation-rules/src/Rules/Deprecations/InheritanceOfDeprecatedClassRule.php
vendor/phpstan/phpstan-deprecation-rules/src/Rules/Deprecations/InheritanceOfDeprecatedInterfaceRule.php
vendor/phpstan/phpstan-deprecation-rules/src/Rules/Deprecations/InstantiationOfDeprecatedClassRule.php
vendor/phpstan/phpstan-deprecation-rules/src/Rules/Deprecations/TypeHintDeprecatedInClassMethodSignatureRule.php
vendor/phpstan/phpstan-deprecation-rules/src/Rules/Deprecations/TypeHintDeprecatedInClosureSignatureRule.php
vendor/phpstan/phpstan-deprecation-rules/src/Rules/Deprecations/TypeHintDeprecatedInFunctionSignatureRule.php
vendor/phpstan/phpstan-deprecation-rules/src/Rules/Deprecations/UsageOfDeprecatedCastRule.php
vendor/phpstan/phpstan-deprecation-rules/src/Rules/Deprecations/UsageOfDeprecatedTraitRule.php
vendor/phpstan/phpstan/.gitattributes
vendor/phpstan/phpstan/.gitignore
vendor/phpstan/phpstan/LICENSE
vendor/phpstan/phpstan/README.md
vendor/phpstan/phpstan/bootstrap.php
vendor/phpstan/phpstan/composer.json
vendor/phpstan/phpstan/conf/bleedingEdge.neon
vendor/phpstan/phpstan/phpstan
vendor/phpstan/phpstan/phpstan.phar
vendor/phpstan/phpstan/phpstan.phar.asc
lambch’s picture

I am also getting this exact message.
The message asks "did you install with Composer", when yes, I definitely did.

The /vendor/bin/phpstan binary is definitely there. Or rather, as an alias for /phpstan/phpstan/phpstan

Within command-line I browse to both of the above mentioned locations and running php phpstan works.

My local dev is a Vagrant based VM.

powlessn’s picture

I had the same problem. The module couldn't find my vendor/bin folder because it's outside my web root/DRUPAL_ROOT.
According to a related issue[1], you can specify a /bin path in composer.json. In my case, I added this to the composer.json
file that was inside my web root/DRUPAL_ROOT.

"config": {
    "bin-dir": "../vendor/bin",
    ...
},

[1] https://www.drupal.org/project/upgrade_status/issues/3129430

Dennis Cohn’s picture

I've got the same problem as @lambch
Did you found any solution?

Edit:
Our composer.json file is also outside the root folder.
When I copy our data from the composer.json into the composer.json within the root folder, and changed the vender folder...
It works...But this is not really THE solution I think.

lambch’s picture

Thank you @powlessn. What you suggested works.

I modified the composer.json file what's in the drupal root folder and added `"bin-dir": "../vendor/bin",` in the config section.
The Upgrade Status module works as expected.

For the record, the composter project I am using builds itself from one folder higher. So phpstan must end up in the vendor directory in there, unable to be found by the module when it's needed.

I also do not feel that manually editing the drupal/core composer.json file is a great long-term solution. It'll only get overwritten when my project gets scaffolded.
So I'd either have to patch it post-scaffold... Or completely redo my scaffold (more likely, ugh).
These are problems for another day.
At least the module is working on my local dev, allowing me to use it for its purpose.

This composer stuff is confusing.

Gábor Hojtsy’s picture

Somehow Upgrade Status needs to find the binary. See DeprecationAnalyzer::findBinPath():

  /**
   * Finds bin-dir location.
   *
   * This can be set in composer.json via `bin-dir` config and may not be inside
   * vendor directory.
   *
   * @return string
   *   Bin directory path if found.
   *
   * @throws \Exception
   */
  protected function findBinPath() {
    // The bin directory may be found inside the vendor directory.
    if (file_exists($this->vendorPath . '/bin/phpstan')) {
      return $this->vendorPath . '/bin';
    }
    else {
      $attempted_paths = [$this->vendorPath . '/bin/phpstan'];
    }

    // See if we can locate a custom bin directory based on composer.json
    // settings.
    $composerFileName = trim(getenv('COMPOSER')) ?: 'composer.json';
    $rootComposer = $this->finder->getComposerRoot() . '/' . $composerFileName;
    $json = json_decode(file_get_contents($rootComposer), TRUE);

    if (is_null($json)) {
      throw new \Exception('Unable to decode composer information from ' . $rootComposer);
    }

    if (is_array($json) && isset($json['config']['bin-dir'])) {
      $binPath = $this->finder->getComposerRoot() . '/' . $json['config']['bin-dir'];
      if (file_exists($binPath . '/phpstan')) {
        return $binPath;
      }
      else {
        $attempted_paths[] = $binPath . '/phpstan';
      }
    }

    // Bail here as continuing makes no sense.
    throw new \Exception('Vendor binary path not correct or phpstan is not installed there. Did you install Upgrade Status with composer? Checked: ' . join(',', $attempted_paths));
  }

Would updating the exception message help to point people to the right direction to suggest updating your composer.json? @lambch do you have suggestions on how would the module find your path without you telling it about it?

Gábor Hojtsy’s picture

Note that we are using https://github.com/webflo/drupal-finder to find the Drupal composer file. @Dennis Cohn could that project do something better to find the "right" composer file for you? How would it tell which one is the right one?

lambch’s picture

The thing that dead-ended me with that error message was where it said "Did you install Upgrade Status with composer?"
Because, yes I did. The exception message suggests that using composer is the right way to do it. But even so, it doesn't always work.

Personally I didn't mind having to add that extra line to Drupal's composer file to repoint it to the correct vendor binary directory. It's just that the prompts that this was the actual solution were not obvious.
Helpful error messages are great. But more generally it's better when things 'just work'.

fundawangcn’s picture

Same here.

But after disabling selinux, the error went out.

StepanISK’s picture

I am getting the same error. But in my case, the problem is in the direction of slashes. I have Windows with an OpenServer.

Vendor binary path not correct or phpstan is not installed there. Did you install Upgrade Status with composer? Checked: F:\OSPanel\domains\2020/vendor/bin/phpstan

i added changes to

"config": {
    "bin-dir": "\vendor\bin",
    ...
},

the problem is gone. But a new one appeared

Unable to decode F:\OSPanel\domains\2020/composer.json

how can I solve this problem?
I think that this problem will most likely not be on the server. Nuances for local build.

brunodbo’s picture

Version: 8.x-2.9 » 8.x-3.1

Ran into this as well. I found https://github.com/webflo/drupal-finder/pull/55, which might help us.

fgm’s picture

Similar issue:

  • composer create-project drupal/recommended-project:8.9.13 demo (which installs 8.8 ?)
  • cd demo
  • composer require -nvv drush/drush drupal/core:8.9.13 drush/drush drupal_upgrade_status
  • drush si --db-url=mysql://user:pass@localhost:3306/base standard
  • drush en -y upgrade_status
  • drush us-a upgrade_status

Result:

On the CLI:

In UpgradeStatusCommands.php line 245:

  The project machine name upgrade_status is invalid. Is this a project on this site? (For community projects, use the machine name of the drupal.org project itself).

On admin/reports/upgrade-status

Vendor binary path not correct or phpstan is not installed there. Did you install Upgrade Status with composer? Checked:
 /(project dir)/web/vendor/bin/phpstan

The error is obvious: phpstan is in (project)/vendor/bin/phpstan instead. The problem materializes in DeprecationAnalyzer::initEnvironment() where DrupalFinder->getVendorDir() returns an incorrect directory with this layout: (project)/web/vendor instead of (project)/vendor. DrupalFinder sets vendorDir from composerRoot, incorrectly assuming composerRoot == drupalRoot, which is only true with the drupal/drupal layout.

Gábor Hojtsy’s picture

Hm, is there a way to make DrupalFinder able to find Drupal in these cases?

fgm’s picture

The thing is, DrupalFinder does find Drupal. What it doesn't find is the vendor dir.

The drupal-finder PR 55 mentioned in #13 would allow it to use environment variables for that purpose. However, I think that a better approach would be to either:

  • not just use the assumption that vendor is below drupal root, but check there and in ../vendor, which matches both the legacy scaffold and the current one
  • use the vendor-dir from composer, which covers more cases, but may be problematic as Composer is not present in some deployments, and not available as a service even when present
  • slightly modify the composer template to include config.vendor-dir = vendor, and since DrupalFinder knows how to fetch composer.json, read its config section to check whether vendor-dir is defined:
    • if there's no composer available, it's a legacy layout with vendor below root
    • if there's a composer but no config use composer-dir/vendor
    • if there's a composer and a vendor-dir config, use composer-dir/(value in config)
Gábor Hojtsy’s picture

Title: Vendor binary path not correct or phpstan is not installed there. » Improve guidance for case when phpstan is not found but composer was used
Category: Support request » Bug report
Status: Postponed (maintainer needs more info) » Needs review
FileSize
789 bytes

re @fgm in #14: as I copied the code in #8, Upgrade Status already supports reading the bin-dir from composer.json (does not need composer itself present in the environment) and uses that if the vendor path returned by DrupalFinder was not correct.

re @StepanISK in #12, I would try specifying the path in composer.json with a regular slash, that should work with PHP. The backslash is an escape sequence in JSON, so that should not be used as path separator. See https://stackoverflow.com/a/19176131

We can definitely improve the error text here to point people to the right direction. What about this?

fgm’s picture

re @Gábor Hojtsy then it's very strange; did you do this change since 8.x-3.1 ? I'm asking because :

  • I tried with and without bin-dir, with identical results
  • what I described is an execution I followed in Xdebug step by step: this is how I saw what DrupalFinder actually does
  • when using U.S. with that layout, two thing happen:
    • I get the error message in #14
    • The scan button is disabled

What fixed the issue somehow was creating a (project)/web/vendor/bin directory and symlinking (project)/vendor/bin/phpstan there. This allows the scan to run somehow, although it seems to be missing configuration for phpstan because some well-known deprecations were not being picked up, and running drush us-a returned errors about missing configuration (which did not happen in the web UI).

OTOH, symlinking (project)/vendor below (project)/web allowed it to run from the Web UI, but then drush no longer worked, looping indefinitely on a relaunch on the local version.

One thing I didn't try was using an absolute path for bin-dir: I used "./vendor/bin" and "vendor/bin", though.

Gábor Hojtsy’s picture

@fgm, no 3.0 already has bin-dir support: https://git.drupalcode.org/project/upgrade_status/-/blob/8.x-3.0/src/Dep... -- if the bin-dir was found in the composer.json structure, the "Checked: ..." part should display both the attempted vendor path from DrupalFinder as well as the vendor path based on bin-dir, that is two entries. So if your error message does not list two paths attempted, then the bin-dir was not found in composer.json.

Gábor Hojtsy’s picture

FileSize
4.38 KB
4.26 KB

Went off to refactor this entirely for much better error handling. Now checking the most specific options first and then the least specific. We may also just want to bail if the most specific one did not work out instead of keeping to try? Either way, this should give much better guidance as to what to do if the phpstan binary was not found at one of the three places checked. I did un-abstract the vendor directory detection from DrupalFinder here for better error messages for the specific cases.

What do you all think?

Status: Needs review » Needs work

The last submitted patch, 20: 3164067-20.patch, failed testing. View results
- codesniffer_fixes.patch Interdiff of automated coding standards fixes only.

Gábor Hojtsy’s picture

Status: Needs work » Needs review
FileSize
4.3 KB
740 bytes

Meh, protected method.

Status: Needs review » Needs work

The last submitted patch, 22: 3164067-22.patch, failed testing. View results
- codesniffer_fixes.patch Interdiff of automated coding standards fixes only.

Gábor Hojtsy’s picture

Status: Needs work » Needs review
FileSize
753 bytes
4.3 KB

Should I try my patches before posting them? I should :D

Gábor Hojtsy’s picture

FileSize
5.04 KB
4.03 KB

Yeah I think we should bail as early as we can because otherwise we may end up using a binary that is different from what the developer intended based on the configuration. So yeah if the configuration does not result in finding phpstan, we should tell right away. Also we use the vendor directory at one more location, we also need to bail there if the actual files were not found as the results will be practically empty without that. (This is for the case when a non-standard vendor directory is used but not properly configured in composer.json or if only the bin-dir was specified, which makes phpstan capable to run, but not the configuration assembly that requires vendor-dir to be set). So also modified the error in the binpath check to only suggest setting up vendor-dir, because that solves for both problems, not just the binary.

Would really welcome manual testing of this in non-default scenarios even if the tests pass on the default scenario :)

ronaldtebrake’s picture

Can confirm this patch works for Open Social although our scenario is very much default so my review might not really weigh in on that.
It already worked before (and still works after applying the patch).

Manually moving and altering paths seemed to work as expected, what I can tell I like the DX experience here :)

So will just leave the status as is for others to provide there input.
Thanks for these helpful insights!

fgm’s picture

I just tested with patch #25.

With "vendor-dir" set to "vendor", "./vendor", "/(projectpath)/vendor", or not set ;
with "bin-dir": "./vendor/bin", as well as with no "bin-dir", and with "bin-dir": "/(projectpath)/vendor/bin", the result remains the same:

The PHPStan binary was not found in the default vendor directory. You may need to configure a vendor-dir in composer.json. See https://getcomposer.org/doc/06-config.md#vendor-dir. Attempted: /(projectpath)/web/vendor/bin/phpstan.

I checked what happened, and the problem is that even this patch assumes that DrupalFinder successfully finds the project composer.json, whereas it works more naively than that, and returns the composer.json below the web root, not the project composer.json, and everything is wrong after that: the line $this->finder->locateRoot(DRUPAL_ROOT); is the root of the issue.

AFAICS, there are only two reasonably safe ways to access the composer information in any project layout: (1) during install/update operations, (2) within the autoloader.

The former is problematic because it either complexifies instructions, because dependency scripts are ignored during an install/update except for plugins; the latter is problematic because it will rely on undocumented features of specific autoloaders.

Which leaves three likely paths: (a) have the standard scaffold inject layout information somewhere below drupal root, e.g. in private files (b) make a series of guesses starting from drupal root and moving up one directory for both the legacy and current projects, which is fragile (c) allow the path to be configured manually if discovery fails.

Gábor Hojtsy’s picture

FileSize
1.64 KB
5.12 KB

Thanks, good feedback. I think this improvement is still good, even if it does not fix all cases. Making location of composer.json more specific for now. I'll commit this for an interim fix if it is fine then we can continue looking at figuring out how to find the right composer.json and thus vendor directory better. At lease this would make the error much cleaner for people telling them which composer.json we considered and which value we considered from there.

  • Gábor Hojtsy committed 61b37d1 on 8.x-3.x
    Issue #3164067 by Gábor Hojtsy, mario.elias, ronaldtebrake, fgm, lambch...
Gábor Hojtsy’s picture

Status: Needs review » Active

Committed this but leaving open for figuring out the composer.json location problem.

Gábor Hojtsy’s picture

Status: Active » Fixed

Better for issue management, I copied the conclusions from @fgm to #3194911: Composer file only found in webroot, DrupalFinder assumption is not necessarily correct and credited all of you there too. Let's move over there.

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.

leewbutler’s picture

For anyone developing using Lando, in terminal try doing a "lando composer install" as opposed to simply a "composer install". According to this issue post for the Lando project it "will create new sim-links in vendor/bin" which fixed the issue for me: https://github.com/lando/lando/issues/2328#issuecomment-638744838

Gábor Hojtsy’s picture

@leewbutler: hm, https://www.drupal.org/project/upgrade_status does not mention composer install, do you mean composer require?

jim22’s picture

I had the same issue with phpstan not able to find vendor+bin. I was able to get upgrade_status scanning working by adding 2 lines to the Drupal root composer.json file (app/docroot/composer.json)

"config": {
    ...
    "vendor-dir": "../vendor",
    "bin-dir": "../vendor/bin"
}

I hope this saves someone else a couple hours of time.

Gábor Hojtsy’s picture

@jim22: Great tip! I believe our error message already suggests to specify the vendor-dir? If that is not the case, it would be great if you could open an issue for that. Thanks a lot!

jim22’s picture

Thanks, Gábor!

I just wanted to be sure to explain that using my "main" app root composer.json (including specifying vendor-dir) had no affect on this issue. To fix this, I needed to add the `vendor-dir`/`bin-dir` settings in the Drupal/web root composer file, which is unusual. I'm not sure why it wouldn't locate the correct composer.json file, but I do have a nested Drupal directory... so not sure if that was the reason. Either way, I wasted some time updating the wrong composer file and figured this extra detail might save friends some time.

Thanks again! Have a great day!

3CWebDev’s picture

My issue was that my installation had an (empty) composer.json file in the /web directory that was throwing off the finding of PHPStan. Removing the composer.json file fixed the issue.

fgm’s picture

FWIW, it just started again. I've been working on the same D9 install for over one month and suddenly today it stopped working after a brew upgrade, saying it could not find PHP.

Stopping the brew php service and restarting it fixed the problem. It seems there is an attempt to find the exact same php binary as the one used to serve the report page, which is not the case when upgrading.