Php Laravel是介于开始和结束之间的时间;结束(防止重复预订)

Php Laravel是介于开始和结束之间的时间;结束(防止重复预订),php,mysql,laravel,datetime,Php,Mysql,Laravel,Datetime,我正在编写测试,以确保新预订不能被重复预订。我读过无数其他的SO帖子,现在我更困惑了,不确定自己做得对不对。我在我的项目和这个例子中特别使用了Laravel Migration.php ... $table->date('date'); // 2020-01-01 $table->time('time_start'); // 15:00:00 $table->time('time_end'); // 17:00:00 ... 'date' => date

我正在编写测试,以确保新预订不能被重复预订。我读过无数其他的SO帖子,现在我更困惑了,不确定自己做得对不对。我在我的项目和这个例子中特别使用了Laravel

Migration.php

...
$table->date('date');       // 2020-01-01
$table->time('time_start'); // 15:00:00
$table->time('time_end');   // 17:00:00
...
'date' => date('Y-m-d'),
'time_start' => '15:00:00',
'time_end' => '17:00:00',
...
$existing = DB::table('reservations')
    ->where('asset_id', '=', $request->asset_id)
    ->whereDate('date', '=', $request->date)
    ->whereTime('time_start', '>=', $request->time_start)  // or use $request->strtotime('time_start')
    ->whereTime('time_end', '<=', $request->time_end)
    ->where(function ($query) {
        $query
            ->where('status', '=', 'created')
            ->orWhere('status', '=', 'pending')
            ->orWhere('status', '=', 'completed');
    })
    ->get();

if ($existing->count() > 0) {
    // Not allowed
} else {
    // OK to proceed
}
...
...
$http->assertStatus(400)
    ->assertJsonStructure([
        'type', 'data' => [
            'reason'
        ]])
        ->assertJson([
            'type' => 'reservations',
            'data' => [
                'reason' => 'Asset is no longer available.',
            ],
        ]);
$asset = Asset::find($request->asset_id);

$existing = $asset->reservations()
    ->where(function ($query) use ($request) {
        $start_dt = new Carbon($request->time_start);
        $end_dt = new Carbon($request->time_end);

        $query->where('time_start', '>=', $start_dt)
            ->where('time_end', '<=', $end_dt);
        })
        ->whereIn('status', ['created', 'pending', 'completed'])
        ->get();

    if ($existing->count() > 0) {
        // Log::info('CANNOT MAKE RESERVATION FOR: ' . $request->first_name . ' ' . $request->last_name);
        return response()->json(['type' => 'reservations', 'data' => ['reason' => 'Asset is no longer available.']], 409);
    } else {
        $reservation = new Reservation();
        ...
        // Log::info('RESERVATION MADE FOR: ' . $reservation->first_name . ' ' . $reservation->last_name);
我曾经使用过
dateTime
timezone
。我陷入了一个陷阱,“我不需要日期,只需要时间。我正在将日期保存到其他地方。”然后,我会找到一个建议保存为
时间戳的线程,并在那里比较日期

我有一个预订工厂要生成(除其他详细信息外)
date
time\u start
time\u end

Factory.php

...
$table->date('date');       // 2020-01-01
$table->time('time_start'); // 15:00:00
$table->time('time_end');   // 17:00:00
...
'date' => date('Y-m-d'),
'time_start' => '15:00:00',
'time_end' => '17:00:00',
...
$existing = DB::table('reservations')
    ->where('asset_id', '=', $request->asset_id)
    ->whereDate('date', '=', $request->date)
    ->whereTime('time_start', '>=', $request->time_start)  // or use $request->strtotime('time_start')
    ->whereTime('time_end', '<=', $request->time_end)
    ->where(function ($query) {
        $query
            ->where('status', '=', 'created')
            ->orWhere('status', '=', 'pending')
            ->orWhere('status', '=', 'completed');
    })
    ->get();

if ($existing->count() > 0) {
    // Not allowed
} else {
    // OK to proceed
}
...
...
$http->assertStatus(400)
    ->assertJsonStructure([
        'type', 'data' => [
            'reason'
        ]])
        ->assertJson([
            'type' => 'reservations',
            'data' => [
                'reason' => 'Asset is no longer available.',
            ],
        ]);
$asset = Asset::find($request->asset_id);

$existing = $asset->reservations()
    ->where(function ($query) use ($request) {
        $start_dt = new Carbon($request->time_start);
        $end_dt = new Carbon($request->time_end);

        $query->where('time_start', '>=', $start_dt)
            ->where('time_end', '<=', $end_dt);
        })
        ->whereIn('status', ['created', 'pending', 'completed'])
        ->get();

    if ($existing->count() > 0) {
        // Log::info('CANNOT MAKE RESERVATION FOR: ' . $request->first_name . ' ' . $request->last_name);
        return response()->json(['type' => 'reservations', 'data' => ['reason' => 'Asset is no longer available.']], 409);
    } else {
        $reservation = new Reservation();
        ...
        // Log::info('RESERVATION MADE FOR: ' . $reservation->first_name . ' ' . $reservation->last_name);
我读过的大多数线程建议使用
strttime
进行比较。比如:

'time_start' => strtotime('15:00:00'),  // 1582210800
这是有道理的。但后来我读到,由于时区的原因,保存为
dateTime
timezone
更好

在我的控制器中,我正在检查现有的预订,如下所示:

Controller.php

...
$table->date('date');       // 2020-01-01
$table->time('time_start'); // 15:00:00
$table->time('time_end');   // 17:00:00
...
'date' => date('Y-m-d'),
'time_start' => '15:00:00',
'time_end' => '17:00:00',
...
$existing = DB::table('reservations')
    ->where('asset_id', '=', $request->asset_id)
    ->whereDate('date', '=', $request->date)
    ->whereTime('time_start', '>=', $request->time_start)  // or use $request->strtotime('time_start')
    ->whereTime('time_end', '<=', $request->time_end)
    ->where(function ($query) {
        $query
            ->where('status', '=', 'created')
            ->orWhere('status', '=', 'pending')
            ->orWhere('status', '=', 'completed');
    })
    ->get();

if ($existing->count() > 0) {
    // Not allowed
} else {
    // OK to proceed
}
...
...
$http->assertStatus(400)
    ->assertJsonStructure([
        'type', 'data' => [
            'reason'
        ]])
        ->assertJson([
            'type' => 'reservations',
            'data' => [
                'reason' => 'Asset is no longer available.',
            ],
        ]);
$asset = Asset::find($request->asset_id);

$existing = $asset->reservations()
    ->where(function ($query) use ($request) {
        $start_dt = new Carbon($request->time_start);
        $end_dt = new Carbon($request->time_end);

        $query->where('time_start', '>=', $start_dt)
            ->where('time_end', '<=', $end_dt);
        })
        ->whereIn('status', ['created', 'pending', 'completed'])
        ->get();

    if ($existing->count() > 0) {
        // Log::info('CANNOT MAKE RESERVATION FOR: ' . $request->first_name . ' ' . $request->last_name);
        return response()->json(['type' => 'reservations', 'data' => ['reason' => 'Asset is no longer available.']], 409);
    } else {
        $reservation = new Reservation();
        ...
        // Log::info('RESERVATION MADE FOR: ' . $reservation->first_name . ' ' . $reservation->last_name);
看起来它将被保存为
time
列。在我的测试中,如果不能创建
400
,我会检查是否返回了它

Test.php

...
$table->date('date');       // 2020-01-01
$table->time('time_start'); // 15:00:00
$table->time('time_end');   // 17:00:00
...
'date' => date('Y-m-d'),
'time_start' => '15:00:00',
'time_end' => '17:00:00',
...
$existing = DB::table('reservations')
    ->where('asset_id', '=', $request->asset_id)
    ->whereDate('date', '=', $request->date)
    ->whereTime('time_start', '>=', $request->time_start)  // or use $request->strtotime('time_start')
    ->whereTime('time_end', '<=', $request->time_end)
    ->where(function ($query) {
        $query
            ->where('status', '=', 'created')
            ->orWhere('status', '=', 'pending')
            ->orWhere('status', '=', 'completed');
    })
    ->get();

if ($existing->count() > 0) {
    // Not allowed
} else {
    // OK to proceed
}
...
...
$http->assertStatus(400)
    ->assertJsonStructure([
        'type', 'data' => [
            'reason'
        ]])
        ->assertJson([
            'type' => 'reservations',
            'data' => [
                'reason' => 'Asset is no longer available.',
            ],
        ]);
$asset = Asset::find($request->asset_id);

$existing = $asset->reservations()
    ->where(function ($query) use ($request) {
        $start_dt = new Carbon($request->time_start);
        $end_dt = new Carbon($request->time_end);

        $query->where('time_start', '>=', $start_dt)
            ->where('time_end', '<=', $end_dt);
        })
        ->whereIn('status', ['created', 'pending', 'completed'])
        ->get();

    if ($existing->count() > 0) {
        // Log::info('CANNOT MAKE RESERVATION FOR: ' . $request->first_name . ' ' . $request->last_name);
        return response()->json(['type' => 'reservations', 'data' => ['reason' => 'Asset is no longer available.']], 409);
    } else {
        $reservation = new Reservation();
        ...
        // Log::info('RESERVATION MADE FOR: ' . $reservation->first_name . ' ' . $reservation->last_name);
这很有效。如果我创建了一个从
15:00:00
17:00:00
相同日期/资产等的预订,我的测试通过。我得到的400错误完全符合我的预期。但是,如果我通过
15:01:00
我的测试失败。这并不奇怪,但这说明我没有正确处理比较。看起来我就在终点线上,但后来两双鞋都解开了

用户界面只是一个下拉菜单,上面有人类可读的时间。我正计划将这些值保存为24小时时间。例如,
15:00:00
。我不知道还能怎么做

如能提出建议,以便更好地了解:

  • 最好节省时间
    时间
    时间戳
    日期时间
  • 使用
    strotime
    (或不使用)。如果是,理想的数据类型是什么<代码>时间戳
日期时间
  • 使用适当的错误响应;400是理想的吗
  • 非常感谢你的任何想法

    更新

    按照@miken32的建议——我确实已经用这种方式建立了关系,所以这是有意义的

    我现在将
    time\u start
    time\u end
    保存为迁移中的
    dateTime
    字段

    Controller.php

    ...
    $table->date('date');       // 2020-01-01
    $table->time('time_start'); // 15:00:00
    $table->time('time_end');   // 17:00:00
    ...
    
    'date' => date('Y-m-d'),
    'time_start' => '15:00:00',
    'time_end' => '17:00:00',
    
    ...
    $existing = DB::table('reservations')
        ->where('asset_id', '=', $request->asset_id)
        ->whereDate('date', '=', $request->date)
        ->whereTime('time_start', '>=', $request->time_start)  // or use $request->strtotime('time_start')
        ->whereTime('time_end', '<=', $request->time_end)
        ->where(function ($query) {
            $query
                ->where('status', '=', 'created')
                ->orWhere('status', '=', 'pending')
                ->orWhere('status', '=', 'completed');
        })
        ->get();
    
    if ($existing->count() > 0) {
        // Not allowed
    } else {
        // OK to proceed
    }
    ...
    
    ...
    $http->assertStatus(400)
        ->assertJsonStructure([
            'type', 'data' => [
                'reason'
            ]])
            ->assertJson([
                'type' => 'reservations',
                'data' => [
                    'reason' => 'Asset is no longer available.',
                ],
            ]);
    
    $asset = Asset::find($request->asset_id);
    
    $existing = $asset->reservations()
        ->where(function ($query) use ($request) {
            $start_dt = new Carbon($request->time_start);
            $end_dt = new Carbon($request->time_end);
    
            $query->where('time_start', '>=', $start_dt)
                ->where('time_end', '<=', $end_dt);
            })
            ->whereIn('status', ['created', 'pending', 'completed'])
            ->get();
    
        if ($existing->count() > 0) {
            // Log::info('CANNOT MAKE RESERVATION FOR: ' . $request->first_name . ' ' . $request->last_name);
            return response()->json(['type' => 'reservations', 'data' => ['reason' => 'Asset is no longer available.']], 409);
        } else {
            $reservation = new Reservation();
            ...
            // Log::info('RESERVATION MADE FOR: ' . $reservation->first_name . ' ' . $reservation->last_name);
    
    $asset=asset::find($request->asset\u id);
    $existing=$asset->reservations()
    ->其中(函数($query)使用($request){
    $start\u dt=新碳($request->time\u start);
    $end\u dt=新碳($request->time\u end);
    $query->where('time\u start','>=',$start\u dt)
    
    ->其中('time_end','您最好将此信息存储为两列
    DATETIME
    。优点包括能够利用Laravel内置的碳日期转换功能,避免在午夜预订约会的麻烦

    然后,假设
    $request->time\u start
    $request->time\u end
    是完整的日期/时间,您的查询如下:

    $existing=DB::table('reservations')
    ->其中('asset\u id',$request->asset\u id)
    ->在哪里(
    fn($q)=>$q->whereBetween('time\u start',[$request->time\u start,$request->time\u end])
    ->或者两者之间('time\u end',[$request->time\u start,$request->time\u end])
    ->或者在哪里(
    fn($q)=>$q->where('time\u start','',$request->time\u end);
    )
    )
    ->其中('状态',['已创建','待处理','已完成')
    ->get();
    
    您还可以将
    time\u start
    time\u end
    添加到模型的
    $dates
    数组中,以充分利用它们

    说到模型,如果您的关系设置正确,则此查询可能是这样的,而不是使用
    DB
    facade:

    $asset=asset::find($request->asset\u id);
    $existing=$asset
    ->保留()
    ->在哪里(
    fn($q)=>$q->whereBetween('time\u start',[$request->time\u start,$request->time\u end])
    ->或者两者之间('time\u end',[$request->time\u start,$request->time\u end])
    ->或者在哪里(
    fn($q)=>$q->where('time\u start','',$request->time\u end)
    )
    )
    ->其中('状态',['已创建','待处理','已完成')
    ->get();
    
    它并不短,但在我看来,它更容易一目了然地看到正在搜索的内容


    至于HTTP响应,你使用什么并不重要。这都是你的代码,所以你知道应该期待什么。但是如果你想学究的话(我完全支持),也许可以满足你的需要

    409(冲突)状态代码表示请求无法执行 由于与目标的当前状态冲突而无法完成 此代码用于用户可能是 能够解决冲突并重新提交请求。服务器 应该为用户生成包含足够信息的有效负载 认识到冲突的根源


    您可能不想在这里进行比较,但是您需要检查两件事:开始或结束时间是否属于任何已存在的预订时间间隔;或者在现有预订时间间隔之前和之后开始(因为你不能在上午9点到14点进行新的预订,如果上午10点到11点已经存在的话。)400在这里不是一个真正合适的响应。引用Wikipedia的HTTP状态代码,“400错误请求-由于明显的客户端错误,服务器无法或不会处理请求(例如,请求语法格式错误、大小过大、请求无效)