【问题标题】:Trying to access session data from a queued job in Laravel 5.2尝试从 Laravel 5.2 中的排队作业访问会话数据
【发布时间】:2016-05-24 15:13:05
【问题描述】:

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

我正在使用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);
        }
    }
}

【问题讨论】:

  • 您需要在将其丢弃之前获取开放预订的列表,以便将它们从购物车中释放。这一切都需要由您的排队作业处理 - 您能分享一下您目前如何从数据库中清除它们吗?
  • 我不确定您所说的“开放预订”是什么意思,抱歉。当前,当将时间添加到购物车时,它的“in_cart”值在数据库中设置为 1,然后在 5 分钟后由排队作业自动设置回 0。问题是我无法在作业中使用 Cart 外观,因为作业似乎无法访问它。也许可以,但我做错了什么?
  • 你能分享一下你工作的代码吗?
  • 添加到最初的帖子中,谢谢。

标签: php laravel laravel-5.2


【解决方案1】:

Cron 作业在新会话中运行。您的购物车库 (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);
}

【讨论】:

  • 谢谢!您的回答非常有帮助,我非常感谢您花时间编写它。对于留在网站上的用户来说,这是一个很好的解决方案。对于用户在购物车中添加东西然后立即离开网站的情况,您会推荐什么?我应该让会话在 5 分钟后过期吗?
  • 如果他们离开了站点,他们的会话应该使用自然会话到期来到期 - 同样,取决于您使用的会话驱动程序,但通常默认为两个小时,并且购物车将从记忆。如果有人离开您的网站并在两小时内返回 - 他们可能仍然希望有一辆购物车,其中仍有他们的时间段......所以向他们展示相反的消息将是一个很好的用户体验实践。您不必以任何不同的方式处理这种情况 - 这一切都遵循相同的逻辑:在每次页面绘制时,检查会话/购物车是否存在,如果时间段无效则更新购物车。
猜你喜欢
  • 2016-09-12
  • 2020-03-11
  • 1970-01-01
  • 1970-01-01
  • 2020-11-04
  • 1970-01-01
  • 2021-12-18
  • 1970-01-01
  • 2017-03-12
相关资源
最近更新 更多