Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

Mohammed's avatar

Laravel, Creating unique order on foreach

I know it should be simple :(

My problem is, I have an app for libraries and students, so libraries can have many books in their library this is the tables.

  /**
     * Run the migrations.
     */
    public function up(): void
    {
        Schema::create('books', function (Blueprint $table) {
            $table->id();
            $table->string('book_name')->unique()->nullable();
            $table->string('author_name')->nullable();
            $table->string('edition_number')->nullable();
            $table->string('volume_number')->nullable();
            $table->timestamps();
        });
    }
public function up(): void
    {
        Schema::create('libraries', function (Blueprint $table) {
            $table->id();
            $table->string('name')->unique()->nullable();
            $table->string('phone')->unique()->nullable();
            $table->string('CR')->nullable();
            $table->string('district')->nullable();
            $table->string('city')->nullable();
            $table->string('google_maps')->nullable();

            $table->foreignIdFor(User::class, 'user_id')
                ->constrained('users', 'id')
                ->cascadeOnDelete();
            $table->timestamps();
        });
    }
 public function up(): void
    {
        Schema::create('book_library', function (Blueprint $table) {
            $table->id();
            $table->string('qty')->nullable();
            $table->decimal('price', 10, 2)->nullable();
            $table->text('offer')->nullable();

            $table->foreignIdFor(Book::class, 'book_id')
                ->constrained('books', 'id')
                ->cascadeOnDelete();

            $table->foreignIdFor(Library::class, 'library_id')
                ->constrained('libraries', 'id')
                ->cascadeOnDelete();
        });
    }

As you can see every libeary can have the same book.

where is the problom here:

 public function store(Request $request)
    {
        try {
            DB::transaction(function () use ($request) {
                foreach ($request->carts as $book) {
                    foreach ($book['books'] as $libraryBook) {
                        $order = Order::firstOrCreate(
                            [
                                'library_id' => $book['library_id'],
                                'user_id' => $book['user_id'],
                            ],
                            [
                                'total_payment' => 0
                            ]
                        );
                        $detail = Orderdetail::create([
                            'order_id' => $order->id,
                            'book_library_id' => $book['book_library_id'],
                            'book_id' => $libraryBook['book_id'],
                            'price' => $libraryBook['price'],
                            'total_price' => $libraryBook['price']
                        ]);

                        $order->increment('total_payment', $libraryBook['price']);
                    }
                    if (!$order->latestStatus(Order::STATUS['sent_to_library']['key'])) {
                        $order->setStatus(Order::STATUS['sent_to_library']['key']);
                    }
                    BookLibrary::findOrFail($detail->book_library_id)->decrement('qty');
                }

                $request->user()->carts()->delete();
            });
            return redirect()->route('user.order.index');
        } catch (\Exception $e) {
            Log::error($e);
        }
    }

I here

$order = Order::firstOrCreate(
                            [
                                'library_id' => $book['library_id'],
                                'user_id' => $book['user_id'],
                            ],
                            [
                                'total_payment' => 0
                            ]
                        );

I want to create uniqe order even if the order exists, i mean the student could add to card book A and place order order id now is 1, and than same user add the book A again to the cart and place order i want a new order not updating the exist order. But also if he adds more then one book it will keep creating orders if I change firstOrCreate to create!!

will appropriate your help.

0 likes
10 replies
MohamedTammam's avatar

Just to understand your question. If the user order the following books with A,B,B,C.

The expected behavior should be creating an order with A,B and C books and another order with only book with ID B? is this your question?

1 like
Mohammed's avatar

@MohamedTammam Thanks for your reply, that's what i want, but let's say the Library A have books A,B and Library B have books A,B. When the user order from library A the books A,B it should be in one order even he also at the same time order from Library B the books A,B would be another order.

Webdevashish's avatar

@mohammed

Why don't you create order directly?

$order = Order::create([
	 'library_id' => $book['library_id'],
	 'user_id' => $book['user_id'],
	 'total_payment' => 0
]);
Tompe's avatar

@Mohammed Could changing the library_id column within the Order model to be book_library_id work? I think this way you should be able to insert new orders for each book from a different library as they would have a different id in the book_library table. And if you needed to get the library or book at any point you should be able to do:

$order = Order::where('book_library_id', $book['book_library_id'])->first();
$order->bookLibrary->library;
$order->bookLibrary->book;

Though the above would of course mean you need to implement those relationships.

Or are the requirements like this, to expand on @mohamedtammam question:

User orders the following books:

  • Book A (Library A) x1
  • Book B (Library B) x1
  • Book B (Library C) x1
  • Book C (Library A) x2

Because users usually could add multiple quantities of the same product.

Mohammed's avatar

@Tompe That's work if i want to create an order for every book, but what about if i want to group the books that is for the library?

Tompe's avatar

@Mohammed Do you mean group them within the user interface so that books from one library appear in their own section of the cart and books from another library in a separate section?

If no, and you mean grouping by using SQL grouping via ->groupBy() then without replicating your setup and trying stuff out myself I'm not sure I can offer a solution.

But if yes, then with the method I described you should be able to, in the cart controller, fetch all orders belonging to a specific user and then separate them out into an associative array based on each order's bookLibrary->library relationship.

If my thinking is correct then this way you're removing an order's link to a library and replacing it with references to the table that holds the many-to-many book to library relationships, which should prevent issues with firstOrCreate() as you will only ever have 1 reference to a book_library entry per user's order.

1 like
Mohammed's avatar
Mohammed
OP
Best Answer
Level 2

@tompe Thank you for helping, I solve it by doing this.

   public function store(Request $request)
    {
        try {
            DB::transaction(function () use ($request) {
                $libraries = [];

                foreach ($request->carts as $cart) {
                    $libraryId = $cart['library_id'];

                    if (!isset($libraries[$libraryId])) {
                        $libraries[$libraryId] = Order::create([
                            'total_payment' => 0,
                            'user_id' => $request->user()->id,
                            'library_id' => $libraryId,
                        ]);
                    }

                    $order = $libraries[$libraryId];

                    foreach ($cart['books'] as $book) {
                        $order->increment('total_payment', $book['price']);

                        $detail = Orderdetail::create([
                            'order_id' => $order->id,
                            'book_library_id' => $cart['book_library_id'],
                            'book_id' => $book['book_id'],
                            'price' => $book['price'],
                            'total_price' => $book['price']
                        ]);

                        BookLibrary::findOrFail($detail->book_library_id)->decrement('qty');
                    }

                    if (!$order->latestStatus(Order::STATUS['sent_to_library']['key'])) {
                        $order->setStatus(Order::STATUS['sent_to_library']['key']);
                    }
                }

                $request->user()->carts()->delete();
            });

            return redirect()->route('user.order.index');
        } catch (\Exception $e) {
            Log::error($e);
        }
    }

1 like

Please or to participate in this conversation.