Laravel: 无法声明 class App\Models\Customer,因为该名称已被使用
Laravel: Cannot declare class App\Models\Customer, because the name is already in use
我有点困惑。我在我的用户(实际上是“客户”)模型上有一个简单的方法 return 用户的订阅续订日期:
public function subscriptionRenewalDate() : string
{
$subscription = $this->subscriptions()->active()->first()->asStripeSubscription();
return Carbon::createFromTimeStamp($subscription->current_period_end)->format('F jS, Y');
}
我从 blade 模板 ({{ auth()->user()->subscriptionRenewalDate() }}
) 对经过身份验证的用户调用此方法,它在本地工作正常,但一旦我上传它到远程登台服务器它失败并出现错误:
Cannot declare class App\Models\Customer, because the name is already in use
它指向 Customer 模型中的这一行:
class Customer extends Authenticatable
{
奇怪的是,它不仅仅是远程登台服务器,它也是 Travis CI 失败的地方(当 运行 PHP 单元测试时 - 这些相同的测试在本地运行良好).
显然这似乎是某种缓存或配置问题,但我不明白是什么导致了这个错误。
它与数据库无关,因为测试使用 RefreshDatabase
。如果我删除 ENV 变量 (CASHIER_MODEL: App\Models\Customer
),它将失败并出现预期的“找不到模型用户”错误,因此它正确地获取了 ENV 变量。我已经尝试清除 Laravel 缓存 (php artisan optimize:clear
) 和 composer dump-autoload
。很混乱。
我只知道错误是由asStripeSubscription()
引起的。如果我从方法中删除它,blade 模板加载正常(一切正常)。
明确地说,我可以成功(这是本地、远程和 Travis CI):
- 在Laravel
注册
- 登录Laravel
- 重置我的密码
- 更新我的个人资料
- 输入付款信息以订阅 Stripe 订阅
- 查看和修改我的 Stripe 订阅
- 在 Stripe.com
上查看我的所有客户和订阅信息
- 编辑我在 Stripe.com 上的信息,并通过我的服务器上的 webhook 查看更新信息
只有当 asStripeSubscription()
出现在代码中时才会出现问题。而且它只在远程服务器上。即使在本地也能正常工作。
我已经尝试将此调用转移到各种模型。我试过从控制器调用它并将结果传递给视图。我什至尝试过重启服务器并清除 Travis CI 的缓存。错误保持不变。
什么会导致 asStripeSubscription()
产生此错误?如果我可以在本地复制,我就可以调试它!固执地坚持本地完美,远程失败
我正在使用 Laravel 8、PHP 7.3 和 Cashier 12.10。
我只是无法理解会导致 Cannot declare class App\Models\Customer, because the name is already in use
错误的原因。
堆栈跟踪:
来自 Laravel.log:
[2021-03-22 10:29:23] production.ERROR: Cannot declare class App\Models\Customer, because the name is already in use {"userId":1127215,"exception":"[object] (Symfony\Component\ErrorHandler\Error\FatalError(code: 0): Cannot declare class App\Models\Customer, because the name is already in use at /var/app/current/app/Models/Customer.php:13)
[stacktrace]
你在数据库中更新你的关系吗?也许您应该在生产服务器上刷新迁移。
If you're using a model other than Laravel's supplied App\Models\User
model, you'll need to publish and alter the Cashier migrations provided to match your alternative model's table name.
另一个可能的问题是您没有为授权设置合适的模型。
// auth.php
'providers' => [
'users' => [
'driver' => 'eloquent',
'model' => App\Models\Customer::class,
],
],
还要确保您的模型具有正确的命名空间。
PHP 可能不会报告重复的 classes,而没有重复的 classes。
通常存在三种可能的陷阱:
A) 重复项 class 的问题可能是由重复项 class.
引起的
这可以通过查找并删除有问题的 class 文件来解决,例如:
find . | grep Customer.php
这应该return两个结果,其中一个导致了错误信息;然后 运行 rm filename
.
B) 它可能来自一个过时的 autoload.php
,可以通过 运行ning composer dump-autoload
.
刷新
C) 可能是命名空间的东西;例如。 use Stripe\Customer as StripeCustomer;
那 method 除了:
StripeSubscription::retrieve(
['id' => $this->stripe_id, 'expand' => $expand], $this->owner->stripeOptions()
);
而App\Models\Customer
可能是SubscriptionBuilder.php
的$owner
。
我找到了解决方案。我不知道这一点,但这基本上是一个与 ENV 变量相关的缓存问题,以及我如何传递这些变量。
对于我们的 Elastic Beanstalk 暂存服务器,我通过 .ebextensions 文件夹中的 .config 文件声明环境变量。例如:
option_settings:
"aws:elasticbeanstalk:application:environment":
APP_NAME: Membership
APP_ENV: production
...
这在大多数情况下都非常有效。您可以在 AWS 中看到变量,大多数应用程序将完全按预期工作。
但是在这种情况下,我需要确保我 运行 php artisan config:cache
作为部署的一部分(感谢@DimitriMostrey)。如果您这样做...它会忽略您已传递给 Elastic Beanstalk 的 ENV 变量!呵呵
我不知道为什么,因为您可以轻松确认您的应用程序能够读取 env('DB_HOST')
等,但它实际上无法使用它们连接到您的数据库或其他任何东西。
如果您不这样做 运行 config:cache
,那么收银台将无法按预期工作(给出完全令人困惑的错误)。
所以我将我的生产环境变量从 .config 文件移动到他们自己的 .env 文件,然后在部署期间使用命令将该文件重命名为 .env
。
现在一切正常。
对于 Travis CI,情况类似:我将重要的环境变量移至 .env.travis
,然后确保 运行 config:cache
在 .travis.yml
中。
在 Travis 中 CI 现在一切也都按预期工作了。
我不知道 Elastic Beanstalk 环境变量的处理方式与 .env 文件中的不同...但我不会忘记的!
我有点困惑。我在我的用户(实际上是“客户”)模型上有一个简单的方法 return 用户的订阅续订日期:
public function subscriptionRenewalDate() : string
{
$subscription = $this->subscriptions()->active()->first()->asStripeSubscription();
return Carbon::createFromTimeStamp($subscription->current_period_end)->format('F jS, Y');
}
我从 blade 模板 ({{ auth()->user()->subscriptionRenewalDate() }}
) 对经过身份验证的用户调用此方法,它在本地工作正常,但一旦我上传它到远程登台服务器它失败并出现错误:
Cannot declare class App\Models\Customer, because the name is already in use
它指向 Customer 模型中的这一行:
class Customer extends Authenticatable
{
奇怪的是,它不仅仅是远程登台服务器,它也是 Travis CI 失败的地方(当 运行 PHP 单元测试时 - 这些相同的测试在本地运行良好).
显然这似乎是某种缓存或配置问题,但我不明白是什么导致了这个错误。
它与数据库无关,因为测试使用 RefreshDatabase
。如果我删除 ENV 变量 (CASHIER_MODEL: App\Models\Customer
),它将失败并出现预期的“找不到模型用户”错误,因此它正确地获取了 ENV 变量。我已经尝试清除 Laravel 缓存 (php artisan optimize:clear
) 和 composer dump-autoload
。很混乱。
我只知道错误是由asStripeSubscription()
引起的。如果我从方法中删除它,blade 模板加载正常(一切正常)。
明确地说,我可以成功(这是本地、远程和 Travis CI):
- 在Laravel 注册
- 登录Laravel
- 重置我的密码
- 更新我的个人资料
- 输入付款信息以订阅 Stripe 订阅
- 查看和修改我的 Stripe 订阅
- 在 Stripe.com 上查看我的所有客户和订阅信息
- 编辑我在 Stripe.com 上的信息,并通过我的服务器上的 webhook 查看更新信息
只有当 asStripeSubscription()
出现在代码中时才会出现问题。而且它只在远程服务器上。即使在本地也能正常工作。
我已经尝试将此调用转移到各种模型。我试过从控制器调用它并将结果传递给视图。我什至尝试过重启服务器并清除 Travis CI 的缓存。错误保持不变。
什么会导致 asStripeSubscription()
产生此错误?如果我可以在本地复制,我就可以调试它!固执地坚持本地完美,远程失败
我正在使用 Laravel 8、PHP 7.3 和 Cashier 12.10。
我只是无法理解会导致 Cannot declare class App\Models\Customer, because the name is already in use
错误的原因。
堆栈跟踪:
来自 Laravel.log:
[2021-03-22 10:29:23] production.ERROR: Cannot declare class App\Models\Customer, because the name is already in use {"userId":1127215,"exception":"[object] (Symfony\Component\ErrorHandler\Error\FatalError(code: 0): Cannot declare class App\Models\Customer, because the name is already in use at /var/app/current/app/Models/Customer.php:13) [stacktrace]
你在数据库中更新你的关系吗?也许您应该在生产服务器上刷新迁移。
If you're using a model other than Laravel's supplied
App\Models\User
model, you'll need to publish and alter the Cashier migrations provided to match your alternative model's table name.
另一个可能的问题是您没有为授权设置合适的模型。
// auth.php
'providers' => [
'users' => [
'driver' => 'eloquent',
'model' => App\Models\Customer::class,
],
],
还要确保您的模型具有正确的命名空间。
PHP 可能不会报告重复的 classes,而没有重复的 classes。
通常存在三种可能的陷阱:
A) 重复项 class 的问题可能是由重复项 class.
引起的
这可以通过查找并删除有问题的 class 文件来解决,例如:
find . | grep Customer.php
这应该return两个结果,其中一个导致了错误信息;然后 运行 rm filename
.
B) 它可能来自一个过时的 autoload.php
,可以通过 运行ning composer dump-autoload
.
C) 可能是命名空间的东西;例如。 use Stripe\Customer as StripeCustomer;
那 method 除了:
StripeSubscription::retrieve(
['id' => $this->stripe_id, 'expand' => $expand], $this->owner->stripeOptions()
);
而App\Models\Customer
可能是SubscriptionBuilder.php
的$owner
。
我找到了解决方案。我不知道这一点,但这基本上是一个与 ENV 变量相关的缓存问题,以及我如何传递这些变量。
对于我们的 Elastic Beanstalk 暂存服务器,我通过 .ebextensions 文件夹中的 .config 文件声明环境变量。例如:
option_settings:
"aws:elasticbeanstalk:application:environment":
APP_NAME: Membership
APP_ENV: production
...
这在大多数情况下都非常有效。您可以在 AWS 中看到变量,大多数应用程序将完全按预期工作。
但是在这种情况下,我需要确保我 运行 php artisan config:cache
作为部署的一部分(感谢@DimitriMostrey)。如果您这样做...它会忽略您已传递给 Elastic Beanstalk 的 ENV 变量!呵呵
我不知道为什么,因为您可以轻松确认您的应用程序能够读取 env('DB_HOST')
等,但它实际上无法使用它们连接到您的数据库或其他任何东西。
如果您不这样做 运行 config:cache
,那么收银台将无法按预期工作(给出完全令人困惑的错误)。
所以我将我的生产环境变量从 .config 文件移动到他们自己的 .env 文件,然后在部署期间使用命令将该文件重命名为 .env
。
现在一切正常。
对于 Travis CI,情况类似:我将重要的环境变量移至 .env.travis
,然后确保 运行 config:cache
在 .travis.yml
中。
在 Travis 中 CI 现在一切也都按预期工作了。
我不知道 Elastic Beanstalk 环境变量的处理方式与 .env 文件中的不同...但我不会忘记的!