I’m on a Laravel project using new-ish versions of PHP, Laravel and Composer 2, as of this writing. I added a new app/Traits/MyTrait.php
file beside several existing trait files but unfortunately Composer absolutely will not detect the new file. I’m getting this error:
Trait 'AppTraitsMyTrait' not found
Similar to:
Laravel Custom Trait Not Found
Here is the general layout of the code:
# app/Traits/MyTrait.php:
<?php
namespace AppTraits;
trait MyTrait {
// ...
}
# app/Notifications/MyBaseClass.php:
<?php
namespace AppNotifications;
use AppTraitsMyTrait;
class MyBaseClass
{
use MyTrait;
// ...
}
# app/Notifications/MyChildClass.php
<?php
namespace AppNotifications;
class MyChildClass extends MyBaseClass
{
// ...
}
The weird thing is that this code runs fine in my local dev, but no matter what I try, it won’t work when deployed to the server while running in a Docker container. I’ve tried everything I can think of like saving "optimize-autoloader": true
in composer.json
and running composer dump-autoload -o
during deployment, but nothing fixes it:
https://getcomposer.org/doc/articles/autoloader-optimization.md
I’m concerned that this inheritance permutation may not have been tested properly by Composer or Laravel, so this may be a bug in the tools. If worse comes to worse, I’ll try these (potentially destructive) workarounds:
- Calling
composer dump-autoload -o
(greatly slows deployment, as this is a large project, and so far doesn’t seem to fix it anyway) - Deleting via
rm vendor/composer/autoload_classmap.php
,rm vendor/composer/autoload_psr4.php
and/orrm vendor/composer/autoload_namespaces.php
(or similar) in thevendor
folder before each deployment to force Composer to rebuild. - Deleting via
rm -rf vendor
The sinister part about this is that we must have full confidence in our deploy process. We can’t hack this in our server dev environments by manually deleting stuff like vendor
and then have it fail in the production deploy because Composer tripped over stale data in its vendor
folder. My gut feeling is that this is exactly what’s happening, perhaps due to an upgrade from Composer 1 to Composer 2 or version change or stale cache files from work in recent months.
Even a verification like "this minimal sample project deployed to Docker works for us" would help to narrow this down thanks.
Edit: this is a useful resource on how the Composer autoloader works: https://jinoantony.com/blog/how-composer-autoloads-php-files
2
Answers
The problem turned out to be caused by the container/filesystem on AWS being case-sensitive, but my local dev environment on macOS being case-insensitive.
My original trait (kept secret) ended with
URL
in its name, but I was including its path as, and using it in the base class as,Url
.So this issue had nothing to do with traits, base classes or Composer. It also didn't require any modification of
composer.json
or the way we call it during deployment. But I think it's still best practice to have this incomposer.json
, I use it this way in local dev too currently (good/bad?):The real problems here (industry-wide) are:
It wasn't convenient to ssh into the server (by design). So to troubleshoot, I temporarily committed this onto my branch:
Then deployed without merging in GitLab and compared the response to the error in AWS Cloudwatch, which is when the typo jumped out.
Then I removed the temporary commit with:
And force-pushed my branch with:
So was able to solve this without affecting our CI/CD setup or committing code permanently to the develop or master branches.
I've been doing this for a lot of years, and even suspected a case-sensitivity issue here, but sometimes we're just too close to the problem. If you're knee-deep in code and about to have an anxiety attack, it helps to have another set of eyes review your thought process with you from first principles.
I also need to figure out how to run my local Docker containers as case-sensitive as well, to match the server (since that's the whole point of using Docker containers in the first place).
I had the same problem and it was related to my file name. I had put it in lowercase at the beginning, that is:
apiResponser.php
. I added some changes and renamed my file toApiResponser.php
and sent it to production, but … oh, oh!I had the same problem.
The only way it worked for me was, do the git name replacement: