对不同长度的产品进行分类

时间:2014-03-30 05:50:29

标签: php mysql laravel laravel-4

我们有一个电子商务网站,现在已经销售了几天的商品。我们有一个可以订购产品的系统,因此“特色”产品位于顶部,销售情况不佳的产品位于折扣底部。

我们最近推出的产品运行了几天而不是一天,但这会对我们的排序算法造成严重破坏。

以前我们每天都会设置产品订单,所以如果我们在一天内销售了5件产品,我们会在数据库中将其设置为:

Position | Product
----------------------
1        | Product # 1
5        | Product # 2
4        | Product # 3
2        | Product # 4
3        | Product # 5

然后,我们可以将产品列表拉出一天,按位置和显示进行排序。但是现在我们必须补偿多天运行的产品,因此可以在多天内拥有多个仓位。我们认为我们可以轻松调整算法以在整个产品表中运行,如下所示:

Position | Product
----------------------
51       | Product # 1
75       | Product # 2
69       | Product # 3
62       | Product # 4
66       | Product # 5

这些产品的订单仍与原先相同,但该位置基于表中的每个产品,而不仅仅是当天。这给了我们一个我们期望的日历(数字是产品表中的当前位置): enter image description here

当我们想要重新订购产品时,问题就出现了。如果我们的产品#6运行了3天,那么它的位置可能是64,当时它位于#4和#3以上,但是当我们重新订购这些产品时,它会移动并获得jQuery UI数据列表中与任何事物无关的位置,虽然我们知道产品与其他日子的关系,但我们不知道那些日子是如何联系在一起的。

我们目前在每次下降后都会触发回调,因此我们只需要处理一次移动的产品。这减少了我们需要做的计算,但我们宁愿一次性设置顺序并从那里处理它。这也为用户提供了中止的机会。

这是我们当前的排序算法,它将产品插入到其他两个之间:

public function setPosition($after, $before)
{
    // Get products which this product is after and before
    $after  = $this->find($after);
    $before = $this->find($before);

    // Move all items down to clear a space for the product
    $this->where('position', '>', $before->position)->update(array('position', DB::raw('position + 1')));

    $this->position = $after->position + 1;
    $this->updateUniques();
}

我们确信我们不是唯一遇到过此问题的人,并认为必须有办法解决这个问题。

2 个答案:

答案 0 :(得分:0)

我认为当你展示它们时,条目的“位置”真的很重要。唯一重要的是显示的条目的相对位置。因此,你可以交换他们的整体头寸。所以在你的第二个例子中,

Position | Product
----------------------
51       | Product # 1
75       | Product # 2
69       | Product # 3
62       | Product # 4
66       | Product # 5

如果要交换产品2和3,只需将#2位置设置为69,将#3位置设置为75.

Position | Product
----------------------
51       | Product # 1
75       | Product # 3
69       | Product # 2
62       | Product # 4
66       | Product # 5

如果我理解正确,我认为这不会影响其他日子。

为了实现这一点,我将在HTML元素上使用data属性,类似data-position,并将其设置为从数据库返回的值。然后在jQuery中,当您交换行时,您可以通过AJAX轻松地将两个data-position发送到您的SQL查询中以交换位置。

如果您决定重新排序所有条目并发送一个回调,这也应该有效。在您关闭回调时,只需对每个元素使用data-position

希望这是有道理的。

答案 1 :(得分:0)

这不是完美的,但是我没有移动产品本身,而是最终移动了受影响的产品并且似乎有效。

数据作为数组从jQueryUI可排序传递。

控制器具有此更新功能:

/**
 * Update the schedule order
 *
 * @return object
 */
public function update()
{
    // Find product before and after
    foreach (Input::get('order') as $key => $product)
    {
        if ($product['id'] != Input::get('id')) continue;

        // Find the products before or after this product
        $before = Input::get('order.' . ($key - 1) . '.id') ?: 0;
        $after  = Input::get('order.' . ($key + 1) . '.id') ?: 0;
        break;
    }

    // Find product
    $product = Product::find(Input::get('id'));

    $product->updatePosition($before, $after);

    return $this->get();
}

该模型具有此updatePosition函数:

/**
 * Move/reorder a product into another position
 *
 * @param int $before [= 0]
 * @param int $after [= 0]
 * @return void
 */
public function updatePosition($before = 0, $after = 0)
{
    // Get products which are before or after this product
    $before = $this->find($before);
    $after  = $this->find($after);

    // Determine which direction we've moved this product
    if ( ! $before) $direction = -1;
    elseif ( ! $after) $direction = 1;
    elseif ($before->position < $this->position && $after->position < $this->position) $direction = -1;
    else $direction = 1;

    // Determine how much we've moved
    if ($direction == 1)
    {
        // We've moved this product down
        $difference = $this->position - $before->position - 1;
        $this->whereNull('parent_id')->where('position', '<=', $before->position)->where('id', '!=', $this->id)->update(array('position' => DB::raw('position + ' . $difference)));
    }
    else
    {
        $difference = $this->position - $after->position + 1;
        $this->whereNull('parent_id')->where('position', '>=', $after->position)->where('id', '!=', $this->id)->update(array('position' => DB::raw('position + ' . $difference)));
    }
}

这样做的缺点是我仍然需要在每次下降之后保存,而不是重新排序一堆产品并计算出他们的新职位但是它有效......