إنشاء سلة مشتريات في Laravel 5


محمد أحمد العيل

هذا الدرس جزء من سلسلة تعلم Laravel والتي تنتهج مبدأ "أفضل وسيلة للتعلم هي الممارسة"، حيث ستكون ممارستنا عبارة عن إنشاء تطبيق ويب للتسوق مع ميزة سلة المشتريات. يتكون فهرس السلسلة من التالي:

laravel5-shopping-cart.thumb.png.c4b4027

نكمل بناء متجرنا الإلكتروني بإضافة خاصية سلة المشتريات. سنستخدم حزمة Laravel ShoppingCart لإضافة هذه الخاصية إلى المشروع. يغطي الدرس المواضيع التالية:

  • تثبيت حزمة Laravel Shopping Cart بـComposer.

  • إعداد Laravel 5 لاستخدام الحزمة.
  • إضافة عناصر إلى سلة المشتريات.
  • العثور على العناصر الموجودة في سلة المشتريات.
  • تحديث عنصر في سلة المشتريات.
  • حذف عنصر من سلة المشتريات.

استخدام Composer لتثبيت Laravel Shopping Cart

نفتح ملف composer.json لإضافة اعتمادية جديدة للمشروع.

نبحث عن فقرة require:

"require": {
        "php": ">=5.5.9",
        "laravel/framework": "5.2.*",
        "doctrine/dbal": "v2.4.2"
    },

نضيف حزمة ShoppingCart على النحو التالي:

"require": {
        "php": ">=5.5.9",
        "laravel/framework": "5.2.*",
        "doctrine/dbal": "v2.4.2",
        "gloudemans/shoppingcart": "~1.3"
    },

ملحوظة: انتبه للفواصل في نهاية الأسطر.

نعلم Composer أننا نريد تثبيت الإصدار 1.3 من الحزمة gloudemans/shoppingcart؛ ثم نحدّث المشروع بتنفيذ الأمر التالي:

composer update

إعداد Laravel لاستخدام حزمة ShoppingCart

نحتاج بعد تثبيت حزمة ShoppingCart لإعداد Laravel للعمل معها. نفتح ملف الإعداد config/app.php ونضيف السطر التالي إلى مصفوفة providers:

Gloudemans\Shoppingcart\ShoppingcartServiceProvider::class,

يسجل الإعداد أعلاه مزوّد خدمة Provider لسلة المشتريات.

ملحوظة: يتيح مزود الخدمة Service Provider في Laravel تحميل صنف (في الذاكرة) مع بدء عمل التطبيق، كما أنه يمكِّن من إضافة عناصر جديدة إلى حاويات الخدمة Service container وهي أداة تدير الاعتمادات بين مختلف الأصناف في إطار العمل.

سنضيف الآن كنية Alias لصنف سلة المشتريات. افتح ملف الإعداد config/app.php وأضف العنصر التالي إلى مصفوفة aliases:

'Cart'    => Gloudemans\Shoppingcart\Facades\Cart::class,

ملحوظة: الكنى Aliases هي أسماء مختصرة للأصناف تُكتب بدلا من الاسم الكامل للصنف. يسجّل التطبيقُ عند بدئه هذه الأصنافَ لكنه لا يحملها إلا عند الحاجة.

إضافة عناصر لسلة المشتريات

سنضيف في هذه الفقرة إمكانية إضافة عنصر إلى سلة المشتريات في صفحة المنتج. تُجرى العملية على ثلاث خطوات:

  • إنشاء مسار لإجراء HTTP POST الذي يضيف العناصر إلى سلة المشتريات.
  • التعديل على القالب products.blade.php من أجل تضمين استمارة لإرسال البيانات مع معرّف المنتَج.
  • التعديل على المتحكم Front.php لكي يتبقى بيانات الاستمارة ويضيفها إلى السلة.

مسار إجراء HTTP POST

افتح ملف المسارات routes.php وأضف المسار التالي:

Route::post('/cart', 'Front@cart');

يعرف السطر السابق مسارات لتلقي إجراءات POST على رابط سلة المشتريات. سيُستخدَم هذا المسار لإضافة عناصر إلى سلة المشتريات.

استمارة صفحة المنتج

الخطوة التالية هي التعديل على قالب صفحة المنتج وإضافة استمارة form لإرسال معرّف المنتج إلى سلة المشتريات من أجل إضافته إليها. افتح ملف العرض products.blade.php وعدّله ليصبح محتواه التالي:

@extends('layouts.layout')

@section('content')       
<section id="advertisement">
    <div class="container">
        <img src="{{asset('images/shop/advertisement.jpg')}}" alt="" />
    </div>
</section>

<section>
    <div class="container">
        <div class="row">
            <div class="col-sm-3">
                <div class="left-sidebar">
                    @include('shared.sidebar')
                </div>
            </div>

            <div class="col-sm-9 padding-right">
                <div class="features_items"><!--features_items-->
                    <h2 class="title text-center">Features Items</h2>
                    @foreach ($products as $product)
                    <div class="col-sm-4">
                        <div class="product-image-wrapper">
                            <div class="single-products">
                                <div class="productinfo text-center">
                                    <img src="{{asset('images/shop/product9.jpg')}}" alt="" />
                                    <h2>${{$product->price}}</h2>
                                    <p>{{$product->name}}</p>
                                    <a href="{{url('cart')}}" class="btn btn-default add-to-cart"><i class="fa fa-shopping-cart"></i>Add to cart</a>
                                    <a href='{{url("products/details/$product->id")}}' class="btn btn-default add-to-cart"><i class="fa fa-info"></i>View Details</a>
                                </div>
                                <div class="product-overlay">
                                    <div class="overlay-content">
                                        <h2>${{$product->price}}</h2>
                                        <p>${{$product->name}}</p>
                                        <form method="POST" action="{{url('cart')}}">
                                            <input type="hidden" name="product_id" value="{{$product->id}}">
                                            <input type="hidden" name="_token" value="{{ csrf_token() }}">
                                            <button type="submit" class="btn btn-fefault add-to-cart">
                                                <i class="fa fa-shopping-cart"></i>
                                                Add to cart
                                            </button>
                                        </form>
                                        <a href='{{url("products/details/$product->id")}}' class="btn btn-default add-to-cart"><i class="fa fa-info"></i>View Details</a>
                                    </div>
                                </div>
                            </div>
                            <div class="choose">
                                <ul class="nav nav-pills nav-justified">
                                    <li><a href=""><i class="fa fa-plus-square"></i>Add to wishlist</a></li>
                                    <li><a href=""><i class="fa fa-plus-square"></i>Add to compare</a></li>
                                </ul>
                            </div>
                        </div>
                    </div>
                    @endforeach
                    <ul class="pagination">
                        <li class="active"><a href="">1</a></li>
                        <li><a href="">2</a></li>
                        <li><a href="">3</a></li>
                        <li><a href="">»</a></li>
                    </ul>
                </div><!--features_items-->
            </div>
        </div>
    </div>
</section>
@endsection

التغيير الأساسي هنا هو إضافة استمارة form مع إجراء post:

<form method="POST" action="{{url('cart')}}">...</form>

تُرسل الاستمارة معرف المنتج إلى سلة المشتريات الذي يعرفه حقل product_id:

<input type="hidden" name="product_id" value="{{$product->id}}">

تحتوي الاستمارة أيضا على عنصر أمني هو:

<input type="hidden" name="token" value="{{ csrftoken() }}">

الذي يعرف رمز أمان Security token للحماية ضد هجمات تزوير الطلب عبر الموقع Cross-site request forgery (تُكتب CSRF أو XCRF اختصارا).

احفظ التعديلات.

ملحوظة: تقوم هجمات تزوير الطلب عبر الموقع على البحث عن روابط تمكن إعادة استخدامها لتنفيذ إجراءات معينة تحتاج لصلاحيات خاصة، تتوفر عادة عند المستخدمين المسجلين، ثم الاحتيال عليهم لكي يفتحوا هذه الروابط - غالبا دون علمهم - وتنفيذ الإجراءات الطلوبة. تحمي رموز الأمان المستخدمين من هذه الهجمات.

التعديل على المتحكم Front

نحتاج، ليمكن لنا استخدام سلة المشتريات، التعديل على دالة cart لاستيرد فضاء الأسماء Cart. افتح ملف المتحكم Front.php وأضف الأسطر التالية لاستيراد فضاءات الأسماء Redirect، Request وCart على التوالي:

يُستخدَم Request للوصول إلى بيانات إجراءات HTTP.

  • يُستخدَم Redirect لتوجيه المستخدم بعد تنفيذ عملية لا تحتاج لإظهار بيانات في الصفحة.
  • للوصول إلى عناصر سلة المشتريات نستخدم Cart.

اعثُر على الدالة cart في المتحكم Front.php وحدّثها كالتالي:

public function cart() {
    if (Request::isMethod('post')) {
        $product_id = Request::get('product_id');
        $product = Product::find($product_id);
        Cart::add(array('id' => $product_id, 'name' => $product->name, 'qty' => 1, 'price' => $product->price));
    }

    $cart = Cart::content();

    return view('cart', array('cart' => $cart, 'title' => 'Welcome', 'description' => '', 'page' => 'home'));
}

نفحص أولا نوع إجراء HTTP الذي أتى منه الطلب إلى الدالة:

if if (Request::isMethod(‘

فإن كان الإجراء من نوع POST ننفذ الشفرة الموالية.

نعثر علي معرف المنتج المُرسَل في الطلب:

$productid = Request::get('productid');

دالة Request::get لا تتعلق بنوعية إجراء HTTP ويتساوى عندها POST وGET. تُستخدَم هذه الدالة للعثور على متغيرات مرسلة في الطلب.

نستخدم نموذج المنتج Product للعثور على المنتج في قاعدة البيانات:

$product = Product::find($product_id);

نستخدم كائن المنتج في التعليمة السابقة للحصول على بيانات المنتج وإضافتها إلى سلة المشتريات بإرسال نداء إلى الدالة Cart::add:

Cart::add(array('id' => $product_id, 'name' => $product->name, 'qty' => 1, 'price' => $product->price));

ننادي الدالة Cart::content للحصول على محتوى سلة المشتريات ونضيفه إلى المتغيرات الممررة إلى العرض cart.blade.php:

$cart = Cart::content();
return view('cart', array('cart' => $cart, 'title' => 'Welcome', 'description' => '', 'page' => 'home'));

العثور على العناصر الموجودة في سلة المشتريات

بقيت لنا خطوة واحدة قبل أن نستطيع تجربة سلة المشتريات. نحتاج لتعديل العرض cart لكي يُظهر محتويات السلة. نفتح ملف العرض cart.blade.php لتحريره. نعدّل الملف على النحو التالي:

@extends('layouts.layout')

@section('content')       
<section id="cart_items">
    <div class="container">
        <div class="breadcrumbs">
            <ol class="breadcrumb">
                <li><a href="#">Home</a></li>
                <li class="active">Shopping Cart</li>
            </ol>
        </div>
        <div class="table-responsive cart_info">
            @if(count($cart))
            <table class="table table-condensed">
                <thead>
                    <tr class="cart_menu">
                        <td class="image">Item</td>
                        <td class="description"></td>
                        <td class="price">Price</td>
                        <td class="quantity">Quantity</td>
                        <td class="total">Total</td>
                        <td></td>
                    </tr>
                </thead>
                <tbody>
                    @foreach($cart as $item)
                    <tr>
                        <td class="cart_product">
                            <a href=""><img src="images/cart/one.png" alt=""></a>
                        </td>
                        <td class="cart_description">
                            <h4><a href="">{{$item->name}}</a></h4>
                            <p>Web ID: {{$item->id}}</p>
                        </td>
                        <td class="cart_price">
                            <p>${{$item->price}}</p>
                        </td>
                        <td class="cart_quantity">
                            <div class="cart_quantity_button">
                                <a class="cart_quantity_up" href=""> + </a>
                                <input class="cart_quantity_input" type="text" name="quantity" value="{{$item->qty}}" autocomplete="off" size="2">
                                <a class="cart_quantity_down" href=""> - </a>
                            </div>
                        </td>
                        <td class="cart_total">
                            <p class="cart_total_price">${{$item->subtotal}}</p>
                        </td>
                        <td class="cart_delete">
                            <a class="cart_quantity_delete" href=""><i class="fa fa-times"></i></a>
                        </td>
                    </tr>
                    @endforeach
                    @else
                <p>You have no items in the shopping cart</p>
                @endif
                </tbody>
            </table>
        </div>
    </div>
</section> <!--/#cart_items-->

<section id="do_action">
    <div class="container">
        <div class="heading">
            <h3>What would you like to do next?</h3>
            <p>Choose if you have a discount code or reward points you want to use or would like to estimate your delivery cost.</p>
        </div>
        <div class="row">
            <div class="col-sm-6">
                <div class="chose_area">
                    <ul class="user_option">
                        <li>
                            <input type="checkbox">
                            <label>Use Coupon Code</label>
                        </li>
                        <li>
                            <input type="checkbox">
                            <label>Use Gift Voucher</label>
                        </li>
                        <li>
                            <input type="checkbox">
                            <label>Estimate Shipping & Taxes</label>
                        </li>
                    </ul>
                    <ul class="user_info">
                        <li class="single_field">
                            <label>Country:</label>
                            <select>
                                <option>United States</option>
                                <option>Bangladesh</option>
                                <option>UK</option>
                                <option>India</option>
                                <option>Pakistan</option>
                                <option>Ucrane</option>
                                <option>Canada</option>
                                <option>Dubai</option>
                            </select>

                        </li>
                        <li class="single_field">
                            <label>Region / State:</label>
                            <select>
                                <option>Select</option>
                                <option>Dhaka</option>
                                <option>London</option>
                                <option>Dillih</option>
                                <option>Lahore</option>
                                <option>Alaska</option>
                                <option>Canada</option>
                                <option>Dubai</option>
                            </select>

                        </li>
                        <li class="single_field zip-field">
                            <label>Zip Code:</label>
                            <input type="text">
                        </li>
                    </ul>
                    <a class="btn btn-default update" href="">Get Quotes</a>
                    <a class="btn btn-default check_out" href="">Continue</a>
                </div>
            </div>
            <div class="col-sm-6">
                <div class="total_area">
                    <ul>
                        <li>Cart Sub Total <span>$59</span></li>
                        <li>Eco Tax <span>$2</span></li>
                        <li>Shipping Cost <span>Free</span></li>
                        <li>Total <span>${{Cart::total()}}</span></li>
                    </ul>
                    <a class="btn btn-default update" href="{{url('clear-cart')}}">Clear Cart</a>
                    <a class="btn btn-default check_out" href="{{url('checkout')}}">Check Out</a>
                </div>
            </div>
        </div>
    </div>
</section><!--/#do_action-->
@endsection

نستخدم الدالة count لتحديد ما إذا كان المتغير cart يحوي أي عناصر، فإن كان أنشأنا جدولا لعرض عناصر سلة المشتريات ديناميكيا:

@if(count($cart))
                <table class="table table-condensed">

نستخدم الحلقة التكرارية foreach لعدّ عناصر سلة المشتريات:

@foreach(item)

لكل منتج في سلة المشتريات نعرض اسم المنتج، معرّفه، ثمنه ومجموعا فرعيا Subtotal لتكلفة المنتج على التوالي:

{{$item->name}}
{{$item->id}}
{{$item->price}}
{{$item->subtotal}}

المجموع الفرعي هو حاصل ضرب ثمن المنتج بكميّته. في الأسفل نعرض الثمن الكلي للمنتجات الموجودة في سلة المشتريات:

{{Cart::total()}}

تحديث العناصر الموجودة في سلة المشتريات

نضيف في هذه الفقرة إمكانية تحديث كمية المنتج في سلة المشتريات بالنقر على زر الزيادة + أو النقصان - بجانب الكمية. سنستخدم لهذا الغرض الاستعلام عن طريق رابط URL.

افتح ملف العرض cart.blade.php واعثر على السطرين:

<a class="cart_quantity_up" href=""> + </a>
<a class="cart_quantity_down" href=""> - </a>

حدّث الشفرة المصدرية لكل منهما حتى تصبح على النحو التالي:

<a class="cart_quantity_up" href='{{url("cart?product_id=$item->id&increment=1")}}'> + </a>
<a class="cart_quantity_down" href='{{url("cart?product_id=$item->id&decrease=1")}}'> - </a>

تولد الشفرة:

{{url("cart?productid=$item->id&increment=1")}}

رابطا بالهيئة http://larashop.dev/cart?productid=1&increment=1. يعيّن الرابط معرّف المنتج الذي نريد تحديث كميته واتجاه التحديث. إذا كان المتسوق يريد زيادة الكمية (نقر على +) نعطي القيمة 1 للمعطى increment؛ أما إذا كان المتسوق يريد نقص الكمية (نقر على -) فنعطي القيمة 1 للمتغير decrease.

يجب الآن تعديل المتحكم للتعاطي مع رغبة المتسوق في تحديث الكمية. نعدل الدالة cart لتصبح على النحو التالي:

public function cart() {
    // إضافة منتج جديد إلى سلة المشتريات
    if (Request::isMethod('post')) {
        $product_id = Request::get('product_id');
        $product = Product::find($product_id);
        Cart::add(array('id' => $product_id, 'name' => $product->name, 'qty' => 1, 'price' => $product->price));
    }


    // زيادة كمية منتج في سلة المشتريات
    if (Request::get('product_id') && (Request::get('increment')) == 1) {
        $rowId = Cart::search(array('id' => Request::get('product_id')));
        $item = Cart::get($rowId[0]);

        Cart::update($rowId[0], $item->qty + 1);
    }

            // نقص كمية منتج في سلة المشتريات
    if (Request::get('product_id') && (Request::get('decrease')) == 1) {
        $rowId = Cart::search(array('id' => Request::get('product_id')));
        $item = Cart::get($rowId[0]);

        Cart::update($rowId[0], $item->qty - 1);
    }

    $cart = Cart::content();

    return view('cart', array('cart' => $cart, 'title' => 'Welcome', 'description' => '', 'page' => 'home'));
}

في الشيفرة أعلاه نتحقق من تعيين المتغيّرين product_id وincrement.

if (Request::get('product_id') && (Request::get('increment')) == 1)

إذا كان المتغيران معيَّنيْن وقيمة المتغيّر increment تساوي 1 فهذا يعني أن المتسوق أراد زيادة الكمية.

يستخدم السطر الموالي معرّف المنتج product_id للبحث بين عناصر سلة المشتريات ويرجع مصفوفة بمعرّفات أسطُر rowId موافقة للبحث:

$rowId = Cart::search(array('id' => Request::get('product_id')));

معرّف السطر هو معرّف وحيد لعنصُر في السلة يُولّد تلقائيا، ويُستخدَم لتحديث العناصر في السلة. نستخدم معرف العنصر للعثور على كائن يمثل المنتج في سلة المشتريات:

$item = Cart::get($rowId[0]);

نحتفظ بالعنصر الأول من المصفوفة التي ترجعها الدالة Cart::get، في حالتنا لا يوجد سوى عنصر واحد. نبحث عن كائن المنتج لمعرفة الكمية الموجودة في السلة وبالتالي يمكن لنا زيادتها أو نقصها.

نستدعي الدالة Cart::update ونمرر لها معرف المنتج ونزيد الكمية بـ1:

Cart::update($rowId[0], $item->qty + 1); 

السطر الموالي يتحقق من تعيين المتغيرين product_id وdecrease:

if (Request::get('productid') && (Request::get('decrease')) == 1)

وفي حال كانت الإجابة نعم يفحص قيمة المتغير decrease وإذا كانت 1 ينقص كمية المنتج بـ1 في سلة المشتريات:

Cart::update($rowId[0], $item->qty 1); 

افتح رابط صفحة المنتجات http://larashop.dev/products، اختر أحدها بتمرير المؤشر فوقه وأضفه إلى سلة المشتريات بالنقر على زر Add to cart.

01_shopping_cart.thumb.png.f0667aed8f7e8

ستحصل على النتيجة التالية (تتغير النتيجة حسب المنتج الذي اخترته في الخطوة السابقة).

02_shopping_cart.thumb.png.d5d56d92ca58e

اضغط على الزر + لزيادة كمية منتج في سلة المشتريات. لاحظ تغير المجموع الفرعي مع تغير الكمية.

03_shopping_cart.thumb.png.6c6516f03eb08

حذف عناصر من سلة المشتريات

حذفُ عنصُر من سلة المشتريات مشابه لتحديثه:

$rowId = Cart::search(array('id' => Request::get('product_id')));
Cart::remove($rowId[0]);

تحذف الدالة Cart::remove عنصرا من سلة المشتريات اعتمادا على معرف السطر الممرَّر إليها.

لحذف جميع عناصر سلة المشتريات دفعة واحدة نستخدم الدالة Cart::destroy.

خاتمة

كان الهدف من هذا الدرس شرح كيفية تثبيت حزمة Laravel ShoppingCart واستخدامها في مشروع Laravel الخاص بك للحصول على ميزة سلة مشتريات. استعملنا خلال هذا الدرس الحزمة في صفحة المنتج، يمكنك التوسع في استخدام الحزمة في صفحات الموقع الأخرى إن أردت.

ترجمة -وبتصرّف- لمقال Laravel 5 Shopping Cart لصاحبه Rodrick Kazembe.





تفاعل الأعضاء


شكراً جزيلاً على هذه المقالة

كما أشكرك جزيلاً على هذه السلسلة الرائعة التي ساعدتني على دخول عالم Laravel

 

لكن تنويه بسيط, في هذه المقالة في بداية فقرة: "التعديل على المتحكم Front" نسيت كتابة الأسطر التي يجب كتابتها استيراد فضاءات الأسماء Redirect، Request وCart

بحثت في المقالة الأصلية Laravel 5 Shopping Cart لصاحبه Rodrick Kazembe.

ووجدتها:

use Illuminate\Support\Facades\Request;
use Illuminate\Support\Facades\Redirect;
use Cart;

 

أرجو أن لا تفهمني خطأً, فأنا أقدر العمل الرائع الذي قمت به بنقل المعلومة لنا

تمّ تعديل بواسطة Fuad_Sale7

شارك هذا التعليق


رابط هذا التعليق
شارك على الشبكات الإجتماعية


يجب أن تكون عضوًا لدينا لتتمكّن من التعليق

انشاء حساب جديد

يستغرق التسجيل بضع ثوان فقط


سجّل حسابًا جديدًا

تسجيل الدخول

تملك حسابا مسجّلا بالفعل؟


سجّل دخولك الآن