Laravel 在没有明确调用的情况下更新时间戳
Laravel Timestamp Being Updated Without Explicit Call To Do So
所以我 运行 遇到了 Laravel 更新和保存的恼人问题。我有一个 model/table Invoice
和 invoices
,它们有一个时间戳 sent_at
。
Invoice.php
class Invoice extends Model {
protected $dates = [
"sent_at",
];
}
我有以下更新 Invoice
的函数:
InvoicesController.php
:
public function postPayInvoice(Request $request, $invoiceId){
$user = $this->apiResponse->user;
$invoiceItemIds = $request->input("invoice_item_ids");
$invoice = Invoice::with(["invoiceItems" => function($subQuery) use($invoiceItemIds){
return $subQuery->whereIn("invoice_items.id", $invoiceItemIds);
}])->where("id", "=", $invoiceId)->first();
\Log::info("Load: ".$invoice->sent_at);
DB::beginTransaction();
try {
foreach($invoice->invoiceItems AS $invoiceItem){
$invoiceItem->status = "paid";
$invoiceItem->paid_at = Carbon::now();
$invoiceItem->save();
}
$totalInvoices = $invoice->invoiceItems()->count();
$paidInvoiceItems = $invoice->invoiceItems()->where("status", "=", "paid")->count();
if($totalInvoices == $paidInvoiceItems){
$invoice->status = "paid";
$invoice->paid_at = Carbon::now();
} else {
$invoice->status = "partially_paid";
}
\Log::info("Pre: ".$invoice->sent_at);
$invoice->save();
\Log::info("Post: ".$invoice->sent_at);
} catch(\Exception $ex){
DB::rollBack();
return $this->apiResponse->returnFail([], "Unable to Pay Invoice: ".$ex->getMessage(), 200);
}
DB::{$request->input("rollback", null) ? "rollback" : "commit"}();
\Log::info("Post Commit: ".$invoice->sent_at);
return $this->apiResponse->returnSuccess($invoice, "Invoice paid!", 200);
}
这样做是支付选定的 InvoiceItems
(Invoice
的子模型),并且,如果所有 InvoiceItems
都标记为 paid
,则更新 invoices.status
到paid
(或partially_paid
)和invoices.paid_at
到Carbon::now()
(或null
)。
一切正常,但不知何故,这段代码也在更新 sent_at
(因此 \Log
语句)。当代码加载 Invoice
时,在应用所有保存逻辑之后,在保存之后,最后在提交之后,记录了 sent_at
属性:
[2019-05-08 12:43:24] local.INFO: Load: 2019-05-08 12:42:50
[2019-05-08 12:43:24] local.INFO: Pre: 2019-05-08 12:42:50
[2019-05-08 12:43:24] local.INFO: Post: 2019-05-08 12:42:50
[2019-05-08 12:43:24] local.INFO: Post Commit: 2019-05-08 12:42:50
如您所见,sent_at
时间戳始终是 2019-05-08 12:42:50
。但是我一重新查询数据库,时间戳是2019-05-08 12:43:24
,这是paid_at
和updated_at
时间戳的值。
(status
, sent_at
, paid_at
, created_at
, updated_at
)
请注意,这是从 API 调用的,随后请求加载 Invoice
模型列表,它具有以下逻辑来确定附加逻辑:
$cutoff = $this->sent_at->addDays(3)->endOfDay();
但我看不出如何修改 sent_at
列(后面没有调用 save/update,即使调用了,2019-05-08 12:43:24
也不等同于 addDays(3)->endOfDay();
有人以前看过这个吗?它在另一个视图中弄乱了一些排序逻辑,所以我最终需要修复它...
编辑
如果我禁用 $invoice->save();
,它的 updated_at
时间戳仍然会更新,但我不知道为什么。而且,奇怪的是,禁用 $invoiceTransaction->save();
和 $invoiceItem->save();
不会导致 updated_at
发生任何变化...确实会导致数据错误,但这仍在开发中。
二次编辑
"CREATE TABLE `invoices` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`user_id` int(11) NOT NULL,
`account_id` int(11) NOT NULL,
`description` text,
`subtotal` decimal(10,2) NOT NULL,
`grand_total` decimal(10,2) NOT NULL,
`status` enum('pending','sent','partially_paid','paid') NOT NULL DEFAULT
'pending',
`sent_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`paid_at` timestamp NULL DEFAULT NULL,
`created_at` timestamp NULL DEFAULT NULL,
`updated_at` timestamp NULL DEFAULT NULL,
`deleted_at` timestamp NULL DEFAULT NULL,
PRIMARY KEY (`id`)
)
ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8"
我认为这里有问题:
sent_at
timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
这是由于 MySQL 5.7 配置,而不是 Laravel。
The first TIMESTAMP column in a table, if not explicitly declared with the NULL attribute or an explicit DEFAULT or ON UPDATE attribute, is automatically declared with the DEFAULT CURRENT_TIMESTAMP and ON UPDATE CURRENT_TIMESTAMP attributes.
修复方法是在迁移中将时间戳设置为可为空,and/or手动更改 table。
ALTER TABLE invoices CHANGE sent_at sent_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP;
所以我 运行 遇到了 Laravel 更新和保存的恼人问题。我有一个 model/table Invoice
和 invoices
,它们有一个时间戳 sent_at
。
Invoice.php
class Invoice extends Model {
protected $dates = [
"sent_at",
];
}
我有以下更新 Invoice
的函数:
InvoicesController.php
:
public function postPayInvoice(Request $request, $invoiceId){
$user = $this->apiResponse->user;
$invoiceItemIds = $request->input("invoice_item_ids");
$invoice = Invoice::with(["invoiceItems" => function($subQuery) use($invoiceItemIds){
return $subQuery->whereIn("invoice_items.id", $invoiceItemIds);
}])->where("id", "=", $invoiceId)->first();
\Log::info("Load: ".$invoice->sent_at);
DB::beginTransaction();
try {
foreach($invoice->invoiceItems AS $invoiceItem){
$invoiceItem->status = "paid";
$invoiceItem->paid_at = Carbon::now();
$invoiceItem->save();
}
$totalInvoices = $invoice->invoiceItems()->count();
$paidInvoiceItems = $invoice->invoiceItems()->where("status", "=", "paid")->count();
if($totalInvoices == $paidInvoiceItems){
$invoice->status = "paid";
$invoice->paid_at = Carbon::now();
} else {
$invoice->status = "partially_paid";
}
\Log::info("Pre: ".$invoice->sent_at);
$invoice->save();
\Log::info("Post: ".$invoice->sent_at);
} catch(\Exception $ex){
DB::rollBack();
return $this->apiResponse->returnFail([], "Unable to Pay Invoice: ".$ex->getMessage(), 200);
}
DB::{$request->input("rollback", null) ? "rollback" : "commit"}();
\Log::info("Post Commit: ".$invoice->sent_at);
return $this->apiResponse->returnSuccess($invoice, "Invoice paid!", 200);
}
这样做是支付选定的 InvoiceItems
(Invoice
的子模型),并且,如果所有 InvoiceItems
都标记为 paid
,则更新 invoices.status
到paid
(或partially_paid
)和invoices.paid_at
到Carbon::now()
(或null
)。
一切正常,但不知何故,这段代码也在更新 sent_at
(因此 \Log
语句)。当代码加载 Invoice
时,在应用所有保存逻辑之后,在保存之后,最后在提交之后,记录了 sent_at
属性:
[2019-05-08 12:43:24] local.INFO: Load: 2019-05-08 12:42:50
[2019-05-08 12:43:24] local.INFO: Pre: 2019-05-08 12:42:50
[2019-05-08 12:43:24] local.INFO: Post: 2019-05-08 12:42:50
[2019-05-08 12:43:24] local.INFO: Post Commit: 2019-05-08 12:42:50
如您所见,sent_at
时间戳始终是 2019-05-08 12:42:50
。但是我一重新查询数据库,时间戳是2019-05-08 12:43:24
,这是paid_at
和updated_at
时间戳的值。
(status
, sent_at
, paid_at
, created_at
, updated_at
)
请注意,这是从 API 调用的,随后请求加载 Invoice
模型列表,它具有以下逻辑来确定附加逻辑:
$cutoff = $this->sent_at->addDays(3)->endOfDay();
但我看不出如何修改 sent_at
列(后面没有调用 save/update,即使调用了,2019-05-08 12:43:24
也不等同于 addDays(3)->endOfDay();
有人以前看过这个吗?它在另一个视图中弄乱了一些排序逻辑,所以我最终需要修复它...
编辑
如果我禁用 $invoice->save();
,它的 updated_at
时间戳仍然会更新,但我不知道为什么。而且,奇怪的是,禁用 $invoiceTransaction->save();
和 $invoiceItem->save();
不会导致 updated_at
发生任何变化...确实会导致数据错误,但这仍在开发中。
二次编辑
"CREATE TABLE `invoices` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`user_id` int(11) NOT NULL,
`account_id` int(11) NOT NULL,
`description` text,
`subtotal` decimal(10,2) NOT NULL,
`grand_total` decimal(10,2) NOT NULL,
`status` enum('pending','sent','partially_paid','paid') NOT NULL DEFAULT
'pending',
`sent_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`paid_at` timestamp NULL DEFAULT NULL,
`created_at` timestamp NULL DEFAULT NULL,
`updated_at` timestamp NULL DEFAULT NULL,
`deleted_at` timestamp NULL DEFAULT NULL,
PRIMARY KEY (`id`)
)
ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8"
我认为这里有问题:
sent_at
timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
这是由于 MySQL 5.7 配置,而不是 Laravel。
The first TIMESTAMP column in a table, if not explicitly declared with the NULL attribute or an explicit DEFAULT or ON UPDATE attribute, is automatically declared with the DEFAULT CURRENT_TIMESTAMP and ON UPDATE CURRENT_TIMESTAMP attributes.
修复方法是在迁移中将时间戳设置为可为空,and/or手动更改 table。
ALTER TABLE invoices CHANGE sent_at sent_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP;