【问题标题】:Laravel - Eloquent overwriting a custom timestamp... WHY?Laravel - 雄辩地覆盖自定义时间戳......为什么?
【发布时间】:2016-06-27 01:08:21
【问题描述】:

我正在制作一个库存管理系统。 当产品缺货时,我会在表格中输入一个条目,并在“oos_at”字段中注明日期/时间。

稍后,当它重新有货时,我找到该条目并更新“restocked_at”时间戳字段。

但是,当我执行第二个操作时,我的“oos_at”字段被查询('updated_at')字段的时间戳覆盖...... 我必须在另一个实体上跟踪这个“oos_at”字段,这样它就不会被覆盖,然后在更新该表时使用该字段再次更新“oos_at”字段......

下面是我的代码......

class Pusher extends Model {
/**
 *
 *
 * @param Carbon $oos_at
 * @return bool
 */
public function setAsOutOfStock(Carbon $oos_at)
{
    Log::info([
        'FILE'  => get_class($this),
        'method'   => 'setAsOutOfStock',
        'pusher'    => $this->id,
        'param:oos_at'  => $oos_at->toDateTimeString(),
    ]);

    $this->pusherOutOfStocks()->create([
        'location_id'   => $this->location_id,
        'product_id'    => $this->product_id,
        'oos_at'        => $oos_at->toDateTimeString(),
    ]);

    $this->oos = true;
    $this->oos_at = $oos_at;
    return $this->save();
}

/**
 * Clear the PusherOutOfStocks attached to $this Pusher
 * (This Pusher has been restocked!)
 *
 * @param Carbon $time
 * @return bool
 */
public function setAsInStock(Carbon $time)
{
    Log::info([
        'FILE'      => get_class($this),
        'method'    => 'setAsInStock',
        'pusher'    => $this->id,
        'param:time' => $time->toDateTimeString(),
    ]);

    $this->pusherOutOfStocks()->where('restocked_at', null)
        ->update(['restocked_at' => $time->toDateTimeString()]);

    $this->oos = false;
    $this->oos_at = null;
    return $this->save();
}
}

当我在推杆重新进货之前死掉并倾倒 PusherOutOfStocks 时,“oos_at”会被适当地设置。

Illuminate\Database\Eloquent\Collection {#340
  #items: array:1 [
    0 => Newave\Engineering\PusherOutOfStock {#343
      #fillable: array:5 [
        0 => "pusher_id"
        1 => "location_id"
        2 => "product_id"
        3 => "oos_at"
        4 => "restocked_at"
      ]
      #dates: array:2 [
        0 => "oos_at"
        1 => "restocked_at"
      ]
      #connection: null
      #table: null
      #primaryKey: "id"
      #perPage: 15
      +incrementing: true
      +timestamps: true
      #attributes: array:9 [
        "id" => 246
        "pusher_id" => 216
        "location_id" => 634
        "product_id" => 378
        "oos_at" => "2016-03-11 03:00:00"
        "restocked_at" => null
        "created_at" => "2016-03-11 12:12:01"
        "updated_at" => "2016-03-11 12:12:01"
        "deleted_at" => null
      ]
      #original: array:9 [
        "id" => 246
        "pusher_id" => 216
        "location_id" => 634
        "product_id" => 378
        "oos_at" => "2016-03-11 03:00:00"
        "restocked_at" => null
        "created_at" => "2016-03-11 12:12:01"
        "updated_at" => "2016-03-11 12:12:01"
        "deleted_at" => null
      ]
      #relations: []
      #hidden: []
      #visible: []
      #appends: []
      #guarded: array:1 [
        0 => "*"
      ]
      #dateFormat: null
      #casts: []
      #touches: []
      #observables: []
      #with: []
      #morphClass: null
      +exists: true
      +wasRecentlyCreated: false
      #forceDeleting: false
    }
  ]
}

当我在推送器补货后死亡并倾倒 PusherOutOfStocks 时,“oos_at”与“updated_at”相同

Illuminate\Database\Eloquent\Collection {#408
  #items: array:1 [
    0 => Newave\Engineering\PusherOutOfStock {#775
      #fillable: array:5 [
        0 => "pusher_id"
        1 => "location_id"
        2 => "product_id"
        3 => "oos_at"
        4 => "restocked_at"
      ]
      #dates: array:2 [
        0 => "oos_at"
        1 => "restocked_at"
      ]
      #connection: null
      #table: null
      #primaryKey: "id"
      #perPage: 15
      +incrementing: true
      +timestamps: true
      #attributes: array:9 [
        "id" => 244
        "pusher_id" => 214
        "location_id" => 626
        "product_id" => 374
        "oos_at" => "2016-03-11 12:10:23"
        "restocked_at" => "2016-03-11 04:00:00"
        "created_at" => "2016-03-11 12:10:22"
        "updated_at" => "2016-03-11 12:10:23"
        "deleted_at" => null
      ]
      #original: array:9 [
        "id" => 244
        "pusher_id" => 214
        "location_id" => 626
        "product_id" => 374
        "oos_at" => "2016-03-11 12:10:23"
        "restocked_at" => "2016-03-11 04:00:00"
        "created_at" => "2016-03-11 12:10:22"
        "updated_at" => "2016-03-11 12:10:23"
        "deleted_at" => null
      ]
      #relations: []
      #hidden: []
      #visible: []
      #appends: []
      #guarded: array:1 [
        0 => "*"
      ]
      #dateFormat: null
      #casts: []
      #touches: []
      #observables: []
      #with: []
      #morphClass: null
      +exists: true
      +wasRecentlyCreated: false
      #forceDeleting: false
    }
  ]
}

我什至使用过 DB::getQueryLog() 并没有看到 'oos_at' 正在被显式设置/更新....

我的代码中没有其他地方修改过此表...

有谁明白这里发生了什么???? 谢谢!!

=============

额外的代码片段

表迁移::

    Schema::create('pusher_out_of_stocks', function (Blueprint $table) {
        $table->increments('id');

        $table->integer('pusher_id');
        $table->integer('location_id');
        $table->integer('product_id');

        $table->timestamp('oos_at');
        $table->timestamp('restocked_at')->nullable();

        $table->timestamps();
        $table->softDeletes();
    });

PusherOutOfStock 类

class PusherOutOfStock extends Model
{
    use SoftDeletes;

    protected $fillable = [
        'pusher_id',
        'location_id',
        'product_id',
        'oos_at',
        'restocked_at',
    ];

    protected $dates = [
        'oos_at',
        'restocked_at'
    ];

    /**
     * A PusherOutOfStock belongsTo a Product
     *
     * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
     */
    public function product()
    {
        return $this->belongsTo(Product::class);
    }

    /**
     * A PusherOutOfStock belongsTo a Pusher
     *
     * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
     */
    public function pusher()
    {
        return $this->belongsTo(Pusher::class);
    }

    /**
     * A PusherOutOfStock belongsTo a Location
     *
     * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
     */
    public function location()
    {
        return $this->belongsTo(Location::class);
    }
}

下面是代码执行更新方法的顺序

首先,它会在我的 API 命名空间中访问我的 InventoryController

    public function upload(Request $request)
    {
        $data = $request->all();

        $header = $this->getHeader($data);
        $body   = $this->getBody($data);

        $reader = $this->getReaderFromHeader($header);

        if ( ! $this->guardAgainstNoReader($reader))
            return (new Response("Reader with mac-address: ". $header['reader_mac'] . " does not exist.", 409));

        $result = $this->inventoryRepository->uploadPusherData($reader, $header, $body);

        return $result;
    }

然后它将请求发送到 InventoryRepository

public function uploadPusherData(Reader $reader, $header, $body)
{
    foreach ($body as $pusherData)
    {
        $result[] = $this->processPusherData($pusher, $header['timestamp'], $pusherData);
    }
    return $result;
}

然后,在存储库中,它一次处理一行(在我的测试中,只有一行)

private function processPusherData(Pusher $pusher, $timestamp, $pusherData)
{
    $latestInventory = $pusher->latestInventory;

    if (! $latestInventory)
        return $this->updatePusher($pusher, $timestamp, $pusherData);

    if ($latestInventory->tags_blocked == $pusherData['data_TAGSBLKED'])
        return $this->noChangeRecorded($pusher, $latestInventory, $timestamp);

    return $this->updatePusher($pusher, $timestamp, $pusherData);
}

那么推送器就更新了……

public function updatePusher($pusher, $timestamp, $pusherData)
{
    // See if there are any existing already
    $prevInv = $pusher->latestInventory;

    // Create the new data
    $inventory = Inventory::create([
        'pusher_id'     => $pusher->id,
        'product_id'    => $pusher->product_id,
        'reader_id'     => $pusher->reader->id,
        'tags_blocked'  => $pusherData['data_TAGSBLKED'],
        'paddle_exposed'=> $pusherData['paddle_exposed'],
        'created_at'    => Carbon::createFromTimestamp($timestamp)
                            ->toDateTimeString(),
    ]);

    if (  !$prevInv || $prevInv->id == $inventory->id )
    {
        return "first-data" . $timestamp;
    }

    return $this->checkForEvents($inventory, $prevInv);
}

我们检查是否应该触发任何事件...在这种情况下,以前的库存有 9 件库存...现在有 0 个。

private function checkForEvents(Inventory $currentInventory, Inventory $previousInventory)
{
    if ( ! $previousInventory->oos && $currentInventory->oos && $previousInventory->pusher->oos_notified == 0)
    {
        $currentInventory->pusher->oos_notified = true;
        $currentInventory->pusher->save();
        return Event::fire(new InventoryOutOfStock($currentInventory));

    }

    if ( ( $previousInventory->oos || $previousInventory->status == "RESTOCK" )
            && $currentInventory->tags_blocked > 2 )
    {
        return Event::fire(new PusherWasRestocked($currentInventory));
    }

    if ( $currentInventory->status == "RESTOCK" && $previousInventory->pusher->low_stock_notified == 0)
    {
        $currentInventory->pusher->low_stock_notified = true;
        $currentInventory->pusher->save();
        return Event::fire(new LowStockAlert($currentInventory));
    }

    return "no-events";
}

然后触发事件 InventoryOutOfStock

触发 3 个事件... 2 个与正在发送的通知等有关。

    'App\Events\InventoryOutOfStock' => [
        'App\Listeners\InventoryOutOfStockUpdater',
        'App\Listeners\EmailInventoryOutOfStockNotification',
        'App\Listeners\SMSInventoryOutOfStockNotification',

// 'App\Listeners\OutOfStocksUpdater', ],

这导致我们...

public function handle(InventoryOutOfStock $event)
{
    $pusher = $event->pusher;
    $inventory = $event->inventory;
    $product = $pusher->product;

    $oos = $pusher->setAsOutOfStock($inventory->created_at);

    $locationPushers = $product->getPushersByLocation($pusher->location);
    $isInStock = false;
    foreach ($locationPushers as $pusher)
        if ($pusher->oos == 0)
            $isInStock = true;

    if (! $isInStock)
        $product->productOutOfStocks()->create([
            'location_id'   => $pusher->location_id,
            'oos_at'        => $event->inventory->created_at,
        ]);
}

【问题讨论】:

  • 你能发布你的这个表的迁移文件吗?
  • @El_Matella 我添加了我的迁移和类代码。
  • 我非常怀疑 Eloquent 是否会自行更新您的列值,它自己处理的唯一时间戳是 created_at 和 updated_at 和 seen here。因此,请包含从请求开始时针对发生问题的场景运行的代码(包括代码中调用 setAsOutOfStock 方法的任何地方),因为我很确定您的您缺少的代码。

标签: mysql laravel eloquent


【解决方案1】:

我认为你不必使用timestamp 方法来创建你的字段,但你应该使用dateTime 方法:

Schema::create('pusher_out_of_stocks', function (Blueprint $table) {
    $table->increments('id');

    $table->integer('pusher_id');
    $table->integer('location_id');
    $table->integer('product_id');

    $table->dateTime('oos_at');
    $table->dateTime('restocked_at')->nullable();

    $table->timestamps();
    $table->softDeletes();
});

这应该工作:)

希望对您有所帮助!

【讨论】:

  • 亲爱的主......它确实有效......为什么会有任何效果?!?迁移中的 Schema/Blueprint 中的 timestamp 和 dateTime 有何不同?
  • 好吧,我认为 Timestamp 的存在是为了保存更新/创建的当前日期... DateTime 更适合您,因为您不希望与保存/更新日期有任何关系:/
  • 这里的Mysql文档:dev.mysql.com/doc/refman/5.5/en/datetime.html是这样说的:The TIMESTAMP data type offers automatic initialization and updating to the current date and time.
  • @El_Matella 是对的。这是因为timestamp 列默认为传递null 时的当前日期时间,如果不允许它们具有空值。所以$table->timestamp('oos_at')->nullable(); 会产生相同的效果,但从语义的角度来看,datetime 在这种情况下更好。
  • 哦!因此,如果我不在每个更新查询上设置它,它可能/将被覆盖......有趣.. 很高兴知道!太感谢了!你救了我很多个不眠之夜,哈哈
猜你喜欢
  • 2014-07-23
  • 2023-03-10
  • 1970-01-01
  • 2022-01-19
  • 1970-01-01
  • 2018-05-17
  • 1970-01-01
  • 2023-01-18
  • 2017-04-30
相关资源
最近更新 更多