为啥 Laravel 总是在每个 Artisan 命令中调用 schedule()?
Posted
技术标签:
【中文标题】为啥 Laravel 总是在每个 Artisan 命令中调用 schedule()?【英文标题】:Why Laravel keeps calling schedule() with every Artisan Command?为什么 Laravel 总是在每个 Artisan 命令中调用 schedule()? 【发布时间】:2017-12-06 06:00:56 【问题描述】:我有一张名为dc_user_meta
的表,我创建了一个工匠命令并将其安排在kernel.php
中。克隆存储库后,当我尝试运行 PHP artisan migrate
时,我收到此错误。
[Illuminate\Database\QueryException]
SQLSTATE[42S02]: Base table or view not found: 1146 Table 'database.dc_user_meta' doesn't exist (SQL: select * from `dc_user_met
a` where `meta_key` = usage_in_days)
不仅php artisan migrate
,而且我根本无法运行任何工匠命令!我不知道为什么 PHP 每次尝试执行任何工匠命令时都会调用 schedule
方法。
在这种情况下,我可以做些什么来解决这个错误,就像这样在schedule
方法中覆盖我的逻辑。
if(Schema::hasTable('dc_user_meta'))
// Code here
但从长远来看,我认为这并不好。解决此错误的正确方法是什么?
更新:
我只是尝试像这样覆盖kernel.php
中的命令调用,但仍然没有成功!
if(Schema::hasTable('dc_user_meta'))
$schedule->command('usage:update')->daily();
更新: 我得到了解决方案。但我不认为这是问题的答案。它解决了我的问题,但我认为这不是标准解决方案。我只是像这样被Command login覆盖。
if(Schema::hasTable('dc_user_meta'))
// Command Logic
关于为什么 Laravel 使用每个 artisan
命令调用 schedule() 的任何具体答案,以及如果发生这种情况如何以标准方式解决错误!
【问题讨论】:
我无法重现它(L5.4)我做了一个命令调用一个不存在的表,但调用它时只得到一个错误。 @cbaconnier 在数据库中创建表,然后尝试运行“php artisan migrate:refresh” 你使用的是哪个版本的 Laravel? 我使用的是 laravel5.4 【参考方案1】:你的错误是表dc_user_meta
,而你的逻辑是表user_meta
,你需要做Schema::hasTable('dc_user_meta')
【讨论】:
【参考方案2】:我确信数据库中不存在表 dc_user_meta。
【讨论】:
如果您的代码没有任何错误,它应该可以工作。在您的代码中某处存在导致迁移失败的错误。执行:php artisan migrate -vvv
以查看完整堆栈并在此处发布
正在尝试。会告诉你会发生什么!【参考方案3】:
据我了解,您的表是“user_meta”而不是“dc_user_meta”,但您已经编写了使用表“dc_user_meta”的代码,因此出现错误提示“dc_user_meta”表未找到。
【讨论】:
它是dc_user_meta
。 dc_
是前缀。只是为了给你看表的名字,我写了user_meta
。实际表名是dc_user_meta
,我为dc_user_meta
编写了代码。【参考方案4】:
从技术上讲,调度方法是通过 Illuminate\Foundation\Console\Kernel 的构造函数调用的(这是 app\Console\Kernel.php 的父类)
因此,每次实例化控制台内核时,都会执行 schedule() 方法。
让我们看看在哪种情况下执行了什么($schedule->call() 可以替换为 $schedule->command() 或 $schedule->exec()):
protected function schedule(Schedule $schedule)
// everything that is inside the schedule function is executed everytime the console kernel is booted.
// gets exectuted every time
\App\User::where('foo', 1)->get();
$schedule->call(function()
// gets executed for every call to php artisan schedule:run
\App\User::where('foo', 1)->get();
);
$schedule->call(function()
// gets executed for every call to php artisan schedule:run
// IF the closure in the when() function is true;
\App\User::where('foo', 1)->get();
)->when(function()
// if true is returned the scheduled command or closure is executed otherwise it is skipped
\Schema::hasColumn('user', 'foo');
);
但是为什么每个命令都要执行 schedule 命令呢?
嗯,显然 php artisan schedule:run 本身就是一个控制台命令。所以它肯定需要有关预定命令的信息。
其他命令也可能需要有关计划命令的信息...例如,如果您想编写一个工匠命令 list:scheduledTasks。此命令将要求所有计划的命令都已添加到控制台计划列表中。
也许还有其他几个(内部)参数为什么调度函数必须每次都运行。 (我没有对源代码挖掘太深...) 不过...有关预定命令的信息可能对各种用例都有用。
【讨论】:
那么,编写与数据库一起使用的命令逻辑的最佳方法是什么,我们可以运行php artisan migrate
和php artisan migrate:refresh
。
我会将最后一个示例与 when() 方法一起使用。因此,仅在满足要求(在您的情况下存在特定表)时才执行该命令。如果您将代码封装在 $schedule->command() 或 $schedule->call() 中,则 php artisan migrate 和 php artisan migrate:refresh 完全不受影响
所以,这是摆脱这个错误的标准方法。在执行确切的命令逻辑之前检查表是否存在。对吗?
这是避免错误的唯一可能方法....但是如果您不使用示例中的 when() 函数。然后命令根本没有被调度(所以没有其他命令或进程有关于调度命令的信息)。如果您根本不需要,您的示例将起作用。
那么酷!这就是我想知道的!【参考方案5】:
如果还有人关心这个……
<?php
# This is your app/Console/Kernel.php
use ...;
class Kernel extends ConsoleKernel
# Other stuff...
protected function schedule(Schedule $schedule)
if( in_array('schedule:run', $_SERVER['argv']) )
# Your scheduler commands here...
【讨论】:
以上是关于为啥 Laravel 总是在每个 Artisan 命令中调用 schedule()?的主要内容,如果未能解决你的问题,请参考以下文章
为啥我不能使用 PHP artisan serve 运行我的 laravel 应用程序?
为啥 php artisan 使用 empty up 方法创建迁移类?