Open iainfogg opened 3 years ago
PS in case it matters, that particular class is being loaded with a classmap in the composer
autoloading config in composer.json
, rather than using PSR-0 or PSR-4.
"autoload" :
{
"classmap" :
[
"modules/namespace/ClassName.php"
]
},
And if I had to guess why it's going wrong, it would be that these lines in vendor/autoload_classmap.php
(and the other autoloading files that composer generates) are ending up with /layers/paketo-buildpacks_php-composer/php-composer-packages
in $baseDir
instead of APPROOT.
$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
or if composer
is using the autoload_static.php
file, it's this bit towards the end of that file that's ending up with the wrong value:
public static $classMap = array (
'My\\Namespace\\ClassName' => __DIR__ . '/../..' . '/modules/namespace/ClassName.php',
);
Could you provide a full app? We have a vendored app here that we test, but it doesn't seem to use classmap.
@arjun024 thanks, I just tried creating a super simple app that used a classmap, and it actually worked fine, so I'm going to need to try and figure out exactly what it was about the full application that's different and is causing this problem. I'll update you when I manage to identify it.
@arjun024 I've just spent some more time on this, and I think there's something more nuanced going on, potentially around caching.
The code that I said worked later stopped working, after I did some more work and rebuilding, and I couldn't work out why.
I then added a composer dependency (originally there were none, just some autoloading instructions), rebuilt and reran the code, and then it all started working again.
So I've got some demo code, but it either works or doesn't work and I can't figure out why.
Is there a way to force clearing any caches used in the process?
Or do you have any other ideas?
@iainfogg Interesting. With pack build
, you can use the --clear-cache
flag to always clear cache before build.
Hey @iainfogg, it's been a little while since we last heard from you. Any update on the issue you're experiencing?
Hi, I'm sorry it's taken a long time to come back to you on this.
I've created a full application to demo the problem, which I've outlined fully in the README of the project, but I believe it's to do with having the vendor folder as a symlink to another location, rather than vendor existing as a concrete folder within the application. This seems to cause problems when Composer tries to move out of the vendor folder to autoload files within the application.
https://github.com/iainfogg/paketo-composer-demo
Hope that helps!
I'm facing the same issue. Simply put the problem is that /workspace/vendor
ends up being a symbolic link to /layers/paketo-buildpacks_php-composer/php-composer-packages/vendor
. This isn't supported by Composer and breaks autoloading for any class outside of the vendor directory because composer in the end generates for example vendor/composer/autoload_classmap.php
like this:
<?php
// autoload_classmap.php @generated by Composer
$vendorDir = dirname(__DIR__);
$baseDir = dirname($vendorDir);
return array(
'App\\Kernel' => $baseDir . '/src/Kernel.php',
);
Here $baseDir
ends up being /layers/paketo-buildpacks_php-composer/php-composer-packages
while it should be /workspace
meaning that $baseDir . '/src/Kernel.php'
doesn't exist and the Kernel class can't be autoloaded.
cc @joshuatcasey
@enumag @iainfogg thank you for the details. We're in the process of rewriting this buildpack, so I'll make sure this issue is taken into consideration
Thinking about this further I believe there is actually a second issue lurking behind the first one. And that is composer's optimization --classmap-authoritative
.
Based on the fact that you apparently prepare the vendor directory on a different layer (presumably for layer caching because composer dependencies don't change that often) I believe that the classmap won't contain classes outside of vendor. To fix this you need to run composer dump-autoload --classmap-authoritative
after you copy the application files.
What happened?
I'm finding that autoloading is not working in applications using PHP and
composer
. Specifically, it's when the autoloading is attempting to autoload a class which is outside of the vendor folder.For example, I have an
public/index.php
which the web server points to which requires abootstrap.php
file from the root folder of the application. That has the following code:The class ClassName lives in APPROOT/modules/namespace/ClassName.php
If I run that directly on my machine, using PHP 7.4, I get
It exists
in the browser.With an image built with
pack
v. 0.19.0 using the commandpack build my-pack --builder paketobuildpacks/builder:full
and the following config, I get the following error.Config:
Error:
(the code is actually an anonymised version of the real code, but I believe I've corrected everything).
The issue seems to be that the file is at
APPROOT/modules/namespace/ClassName.php
, but becausevendor
is symlinked into the APPROOT folder but actually lives in/layers/paketo-buildpacks_php-composer/php-composer-packages/vendor
, any folder references using within the vendor folder that get the folder location are actually using the real path, not the symlinked location. So, when they try to go up to the APPROOT folder using../../
it actually ends up in/layers/paketo-buildpacks_php-composer/php-composer-packages
instead of in APPROOT. Then when it tries to go down into themodules
folder of APPROOT, it can't find it as it doesn't exist in/layers/paketo-buildpacks_php-composer/php-composer-packages
.I'm using the full buildpack.
The versions are:
The full build output is here: