Laravel时间戳被更新,而无需明确调用 [英] Laravel Timestamp Being Updated Without Explicit Call To Do So

查看:49
本文介绍了Laravel时间戳被更新,而无需明确调用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

所以我在Laravel更新和保存时遇到了一个烦人的问题.我有一个模型/表 Invoice invoices ,它们的时间戳记为 sent_at .

Invoice.php

 类发票扩展了模型{受保护的$ dates = ["sent_at",];} 

我具有以下更新发票的功能:

InvoicesController.php :

 公共函数postPayInvoice(Request $ request,$ invoiceId){$ user = $ this-> apiResponse-> user;$ invoiceItemIds = $ request-> input("invoice_item_ids");$ invoice =发票:: with([" invoiceItems"=>函数($ subQuery)使用($ invoiceItemIds){返回$ subQuery-> whereIn("invoice_items.id",$ invoiceItemIds);}])-> where("id","=",$ invoiceId)-> first();\ Log :: info("Load:".$ invoice-> sent_at);DB :: beginTransaction();尝试 {foreach($ invoice-> invoiceItems AS $ invoiceItem){$ invoiceItem-> status =已付款";$ invoiceItem-> paid_at = Carbon :: now();$ invoiceItem-> save();}$ totalInvoices = $ invoice-> invoiceItems()-> count();$ paidInvoiceItems = $ invoice-> invoiceItems()-> where("status","=","paid")-> count();if($ totalInvoices == $ paidInvoiceItems){$ invoice-> status =已付款";$ invoice-> paid_at = Carbon :: now();} 别的 {$ 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([],无法支付发票:".$ ex-> getMessage(),200);}DB :: {$ request-> input("rollback",null)吗?"rollback":"commit"}();\ Log :: info("Post Commit:".$ invoice-> sent_at);return $ this-> apiResponse-> returnSuccess($ invoice,已支付发票!",200);} 

此操作将支付选定的 InvoiceItems ( Invoice 的子模型),并且,如果所有 InvoiceItems 都标记为付费,然后将 invoices.status 更新为 paid (或 partially_paid )并将 invoices.paid_at 更改为 Carbon :: now()(或 null ).

这一切都很好,但是以某种方式,此代码也正在更新 sent_at (因此, \ Log 语句也是如此).当代码加载了 Invoice 时,在应用所有保存逻辑之后,紧随保存之后以及最后紧随提交之后,都会记录 sent_at 属性:

[2019-05-08 12:43:24]本地信息:负载:2019-05-08 12:42:50
[2019-05-08 12:43:24] local.INFO:前:2019-05-08 12:42:50
[2019-05-08 12:43:24] local.INFO:发表:2019-05-08 12:42:50
[2019-05-08 12:43:24] local.INFO:提交日期:2019-05-08 12:42:50

如您所见, sent_at 时间戳始终是 2019-05-08 12:42:50 .但是一旦我重新查询数据库,时间戳就是 2019-05-08 12:43:24 ,这是 paid_at 的值Updated_at 时间戳.

(<状态> ,<发送>/p>

请注意,这是从API调用的,随后请求加载发票模型的列表,该模型具有以下逻辑来确定其他逻辑:

  $ cutoff = $ this-> sent_at-> addDays(3)-> endOfDay(); 

但是我看不到如何修改 sent_at 列(以下未调用保存/更新,即使这样做也是如此, 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`文字,小计小数(10,2)NOT NULL,grand_total十进制(10,2)NOT NULL,`status`枚举('pending','sent','partially_paid','paid')NOT NULL缺省'待办的',`sent_at`时间戳记NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,`paid_at`时间戳NULL默认DEFAULT NULL,`created_at`时间戳NULL默认DEFAULT NULL,`updated_at`时间戳NULL默认DEFAULT NULL,`deleted_at`时间戳NULL默认DEFAULT NULL,主键(`id`))ENGINE = InnoDB AUTO_INCREMENT = 2 DEFAULT CHARSET = utf8 

我相信那里是一个问题:

sent_at 时间戳记非空默认CURRENT_TIMESTAMP开启UPDATE CURRENT_TIMESTAMP,

解决方案

这是由于MySQL 5.7配置,而不是Laravel.

如果未使用NULL属性或显式的DEFAULT或ON UPDATE属性显式声明表中的第一个TIMESTAMP列,则会使用DEFAULT CURRENT_TIMESTAMP和ON UPDATE CURRENT_TIMESTAMP属性自动声明.

src-Mysql Docs

解决方法是在迁移中将时间戳记设置为可为空,和/或手动更改表.

  ALTER TABLE发票更改send_at send_at时间戳记NOT NULL DEFAULT CURRENT_TIMESTAMP; 

So I'm running into an annoying problem with Laravel update and save. I have a model/table Invoice and invoices, that has a timestamp sent_at.

Invoice.php

class Invoice extends Model {
    protected $dates = [
        "sent_at",
    ];
}

I have the following function that updates the 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);
}

What this does is pays the selected InvoiceItems (child model of Invoice), and, if all InvoiceItems are marked as paid, then updates invoices.status to paid (or partially_paid) and invoices.paid_at to Carbon::now() (or null).

This all works fine, but somehow, this code is also updating sent_at (hence the \Log statements). When the code loads the Invoice, after applying all save logic, right after saving and finally right after committing, the sent_at attribute is logged:

[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

As you can see, the sent_at timestamp is consistently 2019-05-08 12:42:50. But as soon as I re-query the database, the timestamp is 2019-05-08 12:43:24, which is the value of the paid_at and updated_at timestamps.

(status, sent_at, paid_at, created_at, updated_at)

Note this is called from an API, with a subsequent request to load a list of Invoice models, which has the following logic to determine so additional logic:

$cutoff = $this->sent_at->addDays(3)->endOfDay();

But I don't see how that could modify the sent_at column (no save/update is called following, and even if it did, 2019-05-08 12:43:24 does not equate to addDays(3)->endOfDay();

Has anyone seen this before? It's messing up some ordering logic in another view, so I need to fix it eventually...

Edit

If I disable $invoice->save();, it's updated_at timestamp is still updated, but I have no idea why. And, oddly enough, disabling $invoiceTransaction->save(); and $invoiceItem->save(); results in no change to updated_at... Does result in bad data, but this is still in development.

Secondary Edit

"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"

I believe there is an issue there:

sent_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,

解决方案

This is due to the MySQL 5.7 configuration, and not 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.

src - Mysql Docs

The fix is to set the timestamp to nullable in the migration, and/or alter the table manually.

ALTER TABLE invoices CHANGE sent_at sent_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP;

这篇关于Laravel时间戳被更新,而无需明确调用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆