【问题标题】:Laravel - generate unique order numberLaravel - 生成唯一的订单号
【发布时间】:2018-09-01 22:24:46
【问题描述】:

我目前正在尝试在用户到达 create 方法时生成一个唯一的订单号。订单号在种子中是这样生成的,也需要看起来像这样

种子

foreach(range(1,25) as $index)
    {
        DB::table('orders')->insert([

            'user_id' => rand(1,25),
            'order_nr' => '#' . sprintf("%08d", $index),
            'price_sum' => $faker->randomNumber($nbDigits = 4, $strict = false) . '.' . $faker->randomNumber($nbDigits = 2, $strict = false),
            'status' => $faker->randomElement(['paid', 'pending', 'failed']),
            'created_at' => Carbon::now(),
            'updated_at' => Carbon::now(),

        ]);
    }

订单号如下所示#00000001#00000002。现在,当用户到达我的控制器中的 create 方法时,需要在此序列中创建一个新的唯一订单号。我怎样才能做到这一点?控制器当前如下所示:

 public function create()
{
    $order = new Order;

    $order->user_id = Auth()->id();
    $order->order_nr = 


    dd($order);


    return view('steps.order');
}

它需要检查最新的订单号并在该订单号上创建一个+1。例如,有 25 个订单,最后一个订单是 #00000025,接下来需要创建的订单是 #00000026。我怎样才能做到这一点?

【问题讨论】:

    标签: php laravel laravel-5 laravel-4


    【解决方案1】:

    您可以使用Laravel ID generator

    首先安装它: composer require haruncpi/laravel-id-generator

    在你的控制器中导入类。

    use Haruncpi\LaravelIdGenerator\IdGenerator;
    

    现在只需使用它

    $prefix = "#";  
    $id = IdGenerator::generate(['table' => 'your_table_name', 'length' => 9, 'prefix' =>$prefix]);
    

    输出

    #00000001
    #00000002
    #00000003
    ...
    

    【讨论】:

    • 只是为了评论这个包似乎从 Laravel 8 开始出现错误,至少如果要填充的字段不是数据库中的 id 字段而是自定义字段。该包不使用ID字段的实际ID号,而是从1开始。然后一旦达到10,它会再次从1开始生成非唯一ID
    【解决方案2】:

    读取最大值 id 并增加它时存在问题。 在重型服务器或并行请求中,两个请求可能从 MySQL 读取相同的 max(id)。

    创建唯一序列号的最佳方法是使用只有一个自动递增字段的序列表。

    1. 首先在序列表中插入新记录。
    2. 然后通过 LAST_INSERT_ID() MySQL 函数从 db 中读取最后插入的 id。
    3. 最后你可以删除低于你id的旧记录了。

    Laravel 方式:

    $id = DB::table('seq_foo')->insertGetId(['id' => null]);
    DB::table('seq_foo')->where('id', '<', $id)->delete();
    

    $id 是您的唯一序列号。

    【讨论】:

      【解决方案3】:

      我找到了更好的解决方案:

      $paynowbillprefix1="ADDON-";
      $paynowbillprefix1=strlen($paynowbillprefix1);
      $query2 = "select gen_id from user_cart_addon order by id desc limit 0, 1";
      $exec2 = mysqli_query($conn,$query2) or die ("Error in Query2".mysqli_error());
      $res2 = mysqli_fetch_array($exec2);
      $num2 = mysqli_num_rows($exec2);
      $billnumber = $res2["gen_id"];
      $billdigit=strlen($billnumber);
      if ($billnumber == '')
      {
          $billnumbercode ='ADDON-'.'1';
      }
      else
      {
          $billnumber = $res2["gen_id"];
          $billnumbercode = substr($billnumber,$paynowbillprefix1, $billdigit);
          $billnumbercode = intval($billnumbercode);
          $billnumbercode = $billnumbercode + 1;
          $maxanum = $billnumbercode;   
          $billnumbercode = 'ADDON-'.$maxanum;
      }
      

      【讨论】:

        【解决方案4】:

        使用行的自动列 ID 值来生成订单号。但是,不要为您的订单号创建额外的列,因为这会给您一个未标准化的数据库,因为订单列完全依赖于 id 列。

        相反,将此方法添加到您 order 模型

        public function get_order_number()
        {
            return '#' . str_pad($this->id, 8, "0", STR_PAD_LEFT);
        }
        

        如果您的上一个订单的 ID 为 5,而您将其删除,那么下一个订单的 ID 为 6

        唯一可能的例外是您在交易中创建订单。如果事务回滚,则将跳过关联的订单 ID。

        【讨论】:

          【解决方案5】:

          你可以试试这个:

          public function generateOrderNR()
          {
              $orderObj = \DB::table('orders')->select('order_nr')->latest('id')->first();
              if ($orderObj) {
                  $orderNr = $orderObj->order_nr;
                  $removed1char = substr($orderNr, 1);
                  $generateOrder_nr = $stpad = '#' . str_pad($removed1char + 1, 8, "0", STR_PAD_LEFT);
              } else {
                  $generateOrder_nr = '#' . str_pad(1, 8, "0", STR_PAD_LEFT);
              }
              return $generateOrder_nr;
          }
          

          您可以在 create() 函数中使用以下代码生成 order_nr$this-&gt;generateOrderNR();

          此外,mt_rand()rand() 快 4 倍,您可以使用它来获得更好的用户体验。

          【讨论】:

            【解决方案6】:

            尝试如下操作

            $order = new Order;
            
            $order->user_id = Auth()->id();
            $latestOrder = App\Order::orderBy('created_at','DESC')->first();
            $order->order_nr = '#'.str_pad($latestOrder->id + 1, 8, "0", STR_PAD_LEFT);
            $order->save();
            

            这里我假设 id 是自动递增的。有关详细信息,请参阅str_pad 方法

            【讨论】:

            • 这对我有用。谢谢!
            • 我不确定这个解决方案。假设,我有以下命令:[1 =&gt; order1, 2 =&gt; order2, 3 =&gt; order3, ];您的订单将作为电子邮件发送给下订单或其他东西的客户。订单的链接是 www.blah/order3 。但是如果我要删除第三个订单并且它在例如客户的邮箱中。然后我会创建新订单,它也将具有相同的链接,因为您将创建具有相同名称的订单。然后链接将不正确。我不知道这是否是您的用例,但最好记住它。 @RainierLaan
            • 也许我理解错了,为什么不使用 MySQL 在您想要的 id 列上使用 INT(8) ZEROFILL 来实现这一点,无论是自动增量还是对外键的引用
            • @Epsilon47 当用户进入屏幕查看订单总和时,他们会得到 2 个选项。要么不付款,这意味着它会删除整个订单,并且他们可以选择付款,这会填充其余的值并使其永久化。当用户付款时。他们无法从系统中删除订单。因为他们为什么首先要这样做?只有当用户决定删除他/她的帐户时,他们的订单才会被删除。在那之前,订单将保留。如果这是思考甚至处理这个问题的正确方法吗?
            • @RainierLaan 我认为您根本不应该删除订单或考虑使用软删除(我不确定在这种情况下 id 的行为方式)。因为你可以解决我写的问题。所以如果你想删除它们,我会使用随机数,而不是有序的,或者我不会删除它们。或者在存储之前,我会检查具有此 ID 的订单是否已经不存在。
            最近更新 更多