尝试从Laravel 5.2中的排队作业访问会话数据

时间:2016-05-24 15:13:06

标签: php laravel laravel-5.2

我正在构建一个网络应用程序,允许人们与教师预约时间。按照目前的情况,一旦将时间添加到用户购物车中,没有其他人可以看到此时间可用或将其添加到购物车。

我正在使用darryldecode's shopping cart,只要会话持续存在(2小时),就会存储项目。但是,我希望在添加后5分钟内自动删除项目。为了实现这一点,我已经设置了一个排队的工作,延迟5分钟。

我的问题是,作业会将时间更改为在5分钟后再次显示给其他用户,但不会将其从购物车中删除,因为它似乎无法访问存储购物车数据的会话。任何人都可以建议我如何从排队的工作中访问存储在会话中的购物车数据? 谢谢。

这是作业的代码,一切都有效,除了Cart :: remove()

namespace App\Jobs;

use App\Jobs\Job;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use App\TimeSlot;
use Cart;

class RemoveTimeSlotFromCart extends Job implements ShouldQueue
{
    use InteractsWithQueue, SerializesModels;

    public $timeSlot;

    /**
     * Create a new job instance.
     *
     * @return void
     */
    public function __construct(TimeSlot $timeSlot)
    {
        $this->timeSlot = $timeSlot;
    }

    /**
     * Execute the job.
     *
     * @return void
     */
    public function handle()
    {
        $timeSlot = $this->timeSlot;
        if ($timeSlot->booked == 0 && $timeSlot->in_basket == 1) {
            $timeSlot->in_basket = 0;
            $timeSlot->save();
            Cart::remove($timeSlot->id);
        }
    }
}

1 个答案:

答案 0 :(得分:1)

Cron Jobs在新会话中运行。您的购物车库(darryldecode / laravelshoppingcart)是基于会话的。如果不是来自当前用户的浏览器发起的会话,那么更改会话数据(可能不可能?取决于您的会话驱动程序)将非常困难。具体来说,这一行:

Cart::remove($timeSlot->id);

购物车模型无法知道从哪个购物车中移除商品。从用户体验的角度来看 - 您将要向用户提供一些反馈,表明他们的时间段已被删除;因此,在每个页面绘制(或在js上异步)编写一个删除检查不应该是意料之外的工作。

在每个页面上绘制,循环访问访问者购物车中的每个项目。我不知道你是如何构建cart :: add(...)来处理一个唯一的购物车商品ID,所以这假设时间段ID与购物车商品ID匹配。

$removed = [];
foreach(Cart::getContent() as $item) {
    $timeSlot = timeSlot::findOrFail($item->id);
    if( $timeSlot->in_basket === 0 ) {
        Cart::remove($timeSlot->id);
    }
}
if(count($removed)) {
    //inject a HTML/JS popup message like "your timeslot has been dropped because you're too slow
    //or pass it along into the request
    $request->session()->flash('slots-dropped', $removed);
}

理想情况下,这是在cartUpdate中间件中处理的,但可以在控制器内完成,具体取决于您网站的复杂程度。

[编辑] 由于数据库结构,上述解决方案存在缺陷 - 用户A保留时间段但未在结账窗口内结账,在用户A注意到之前,时间段返回“非购物车”状态几分钟;同时,用户B在返回到可用时隙池之后和用户A查看另一个页面之前看到相同的时隙(并且购物车更新了相应的消息)。此时,时间段是B人的购物车。当页面刷新查看人员A的时间段是否在“任何”购物车中时 - 它显示“是,它在购物车中因为$ timeslot-> in_basket == 1”。人员A继续退房并获得时间段,即使它在人员B的购物车中。

对此的修复非常简单 - 将in_basket的数据类型从布尔值更改为字符串,并在每次将其添加到购物车时为其分配session_id的值。从我在购物车类中看到的,可能是app() - > session-> get('session')。你var_dump(app() - > session-> all())在你提交重构之前看看是否正确。更新的解决方案将如下所示:

$removed = [];
foreach(Cart::getContent() as $item) {
    $timeSlot = timeSlot::findOrFail($item->id);
    if( $timeSlot->in_basket !== app()->session->get('session') ) {
        Cart::remove($timeSlot->id);
    }
}
if(count($removed)) {
    //inject a HTML/JS popup message like "your timeslot has been dropped because you're too slow
    //or pass it along into the request
    $request->session()->flash('slots-dropped', $removed);
}