【问题标题】:Laravel: Cannot declare class App\Models\Customer, because the name is already in useLaravel:无法声明类 App\Models\Customer,因为该名称已在使用中
【发布时间】:2021-06-13 01:08:33
【问题描述】:

我有点困惑。我的用户(实际上是“客户”)模型有一个简单的方法来返回用户的订阅续订日期:

public function subscriptionRenewalDate() : string
{
    $subscription = $this->subscriptions()->active()->first()->asStripeSubscription();

    return Carbon::createFromTimeStamp($subscription->current_period_end)->format('F jS, Y');
}

我从刀片模板 ({{ auth()->user()->subscriptionRenewalDate() }}) 对经过身份验证的用户调用此方法,并且 它在本地工作正常,但是一旦我将它上传到远程登台服务器,它就会失败并出现错误:

无法声明类 App\Models\Customer,因为该名称已在使用中

它指向客户模型中的这一行:

class Customer extends Authenticatable
{

奇怪的是,它不仅仅是远程登台服务器,它也是 Travis CI 失败的地方(在运行 PHPUnit 测试时——这些相同的测试在本地运行良好)。

显然这似乎是某种缓存或配置问题,但我不明白会导致此错误的原因。

它与数据库无关,因为测试使用RefreshDatabase。如果我删除 ENV 变量 (CASHIER_MODEL: App\Models\Customer),它会因预期的“找不到模型用户”错误而失败,因此它正确获取了 ENV 变量。我已经尝试清除我的 Laravel 缓存 (php artisan optimize:clear) 和 composer dump-autoload。这很混乱。

我只知道这个错误是由asStripeSubscription() 引起的。如果我从方法中删除它,刀片模板加载正常(一切正常)。

明确地说,我可以成功(这是在本地、远程和 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:无法声明类 App\Models\Customer,因为名称已在使用中 {"userId":1127215,"exception":"[object] (Symfony\Component\ErrorHandler\Error\FatalError(代码:0):无法声明类 App\Models\Customer,因为该名称已在 /var/app/current/app/Models/Customer.php:13 中使用) [堆栈跟踪]

【问题讨论】:

  • 你试过composer dump-autoload吗?它可能会有所帮助
  • 您是否将 Billable 特征添加到您的用户(客户)模型中?
  • @TomaszKisiel 与 Cashier 和 Stripe 相关的所有内容都能完美运行。我可以注册,添加订阅,按预期做所有事情。唯一出现问题的是使用asStripeSubscription() 时。所以是的,Billable 特征在 Customer 模型上。
  • @TomaszKisiel 我已经彻底清除了我的数据库。删除所有表,然后从头开始运行迁移。然后我再次注册并订阅,一切正常。然后我尝试访问一个调用asStripeSubscription() 的页面,它也可以正常工作。它只是在远程(托管服务器和 Travis CI)失败。
  • 运行php artisan config:cache 可能会解决问题。在这种情况下,它确实是一个 laravel 缓存造成了冲突。将此与 composer dump-autoload -o(或 --optimize)结合起来,作曲家解释为“优化 PSR0 和 PSR4 包以加载类映射,这对生产有好处。”

标签: php laravel stripe-payments laravel-cashier


【解决方案1】:

我找到了解决方案。我没有意识到这一点,但这基本上是一个与 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,那么 Cashier 将无法按预期工作(给出完全令人困惑的错误)。

所以我将我的生产环境变量从 .config 文件移动到他们自己的 .env 文件中,然后在部署期间使用命令将该文件重命名为 .env

现在一切都按预期进行。

对于 Travis CI,情况类似:我将重要的环境变量移动到 .env.travis,然后确保在 .travis.yml 中运行 config:cache

在 Travis CI 中,现在一切都按预期工作了。

我不知道 Elastic Beanstalk 环境变量的处理方式与 .env 文件中的环境变量不同......但我不会着急忘记!

【讨论】:

  • 感谢分享您如何解决此问题的详细信息!
  • 很高兴您找到了解决方案。生产中的 .env 文件被完全忽略。出于安全原因。如果您在生产服务器上使用composer,我习惯将此行添加到composer.json中的"post-autoload-dump"对象:"@php artisan config:cache --ansi",Api/route,视图和事件也被缓存,我也在@之后运行这些987654331@.
  • .env 用于产品。一次。您将在bootsrap/cache/config.php 中找到值。还有一些其他文件可能对缓存映射感兴趣。
  • @DimitriMostrey 是的,我现在使用 EB 上的部署后挂钩来执行与缓存相关的命令。但是我相信 AWS 已经从基于 Linux 2 的服务器中删除了这个钩子,所以我将来需要另一个缓存命令的解决方案。
  • 后来才看到答案,但我的评论很接近......使用完整的堆栈跟踪(在错误日志中提供)可能比仅使用错误消息更容易回答。
【解决方案2】:

PHP 可能不会报告重复的类,但没有重复的类。

通常存在三种可能的陷阱:

A) 重复类的问题可能是由重复类引起的。
这可以通过查找并删除有问题的类文件来解决,例如:

find . | grep Customer.php

这应该返回两个结果,其中一个导致错误消息;然后运行rm filename

B) 它可能来自过时的autoload.php,可以通过运行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

【讨论】:

  • 这是来自 grep 的响应:./app/Models/Customer.php ./vendor/laravel/cashier/src/Exceptions/InvalidCustomer.php ./vendor/laravel/cashier/src/Concerns/ManagesCustomer.php ./vendor/stripe/stripe-php/lib/Customer.php。只是提醒一下,在 localhost 上一切正常(这个 grep 完成的地方)。
  • 这是失败的 EC2 实例上的结果:./app/Models/Customer.php ./vendor/laravel/cashier/src/Exceptions/InvalidCustomer.php ./vendor/laravel/cashier/src/Concerns/ManagesCustomer.php ./vendor/stripe/stripe-php/lib/Customer.php(相同。)嗯!!!
  • 我在我的应用程序中将 Customer 重命名为 Cust。我更新了所有内容,然后运行了所有单元测试。一切都在本地完美运行。手动测试了它。工作完美。我部署了它和同样的问题:Cannot declare class App\Models\Cust, because the name is already in use。我跑了find . | grep Cust.php,只出现了一个:./app/Models/Cust.php。我完全感到困惑。我觉得我一定在某个地方做了什么愚蠢的事情,但我不知道在哪里。
  • @ChuckLeButt 完全不清楚您如何部署站点;暂时允许远程站点上的xdebug 可能会提供一些见解。类似的东西也可以来自require()require_once()。尝试运行composer dump-autoload 作为部署后步骤,也许?一般来说,.env 可能是一个整体 - 这可能是原因。
【解决方案3】:

您是否更新了数据库中的关系?也许你应该在生产服务器上刷新你的迁移。

如果您使用的模型不是 Laravel 提供的 App\Models\User 模型,则需要发布和更改提供的 Cashier 迁移以匹配您的替代模型的表名。

另一个可能的问题是您没有为身份验证设置合适的模型。

// auth.php
'providers' => [
    'users' => [
        'driver' => 'eloquent',
        'model' => App\Models\Customer::class,
    ],
],

还要确保您的模型具有正确的命名空间。

【讨论】:

  • 正如我所说,在 Travis CI 中一切正常——因此是一个全新的机器实例,具有迁移和一切——直到我将 asStripeSubscription() 添加到代码中。一旦遇到该方法,它就会触发我提到的错误消息 (Cannot declare class App\Models\Customer, because the name is already in use)。不管我把代码放在哪里。只有当它到达asStripeSubscription() 时。其他一切仍按预期工作。
  • 能否分享一下这个函数的代码 asStripeSubscription()
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-08-17
  • 2020-06-21
  • 2019-09-24
  • 2023-03-14
  • 1970-01-01
  • 1970-01-01
  • 2021-11-09
相关资源
最近更新 更多