Very Simple Online Shop without Use any Extension

It is very helpfull for any one who want to create online shop.

In this project I use no any extension, due to most of them are less informative how to implement it in our own project.

I use simple term, because I assume your shop only use payment method by bank transfer, and we only use plain Yii2 features.

Little know-how on the use of yii\bootstrap\Modal will be advantage, it will make our forms more interactive.

1. Model

Structur of the model is like this:

  • product, it will contain detail of product you will sell. The field required in this table are ID and price.
  • order, it will save order’s detail.
  • order item, it will be our place to put item for each order.

Tabel 1

CREATE TABLE smf_product_pricing (
id int(3) UNSIGNED NOT NULL,
product_type varchar(200) NOT NULL,
standard_id int(2) UNSIGNED DEFAULT NULL,
currency varchar(20) NOT NULL,
title varchar(250) DEFAULT NULL,
description text DEFAULT NULL,
price decimal(10,2) UNSIGNED NOT NULL,
notes varchar(200) DEFAULT NULL,
status varchar(250) DEFAULT NULL,
created_at datetime NOT NULL,
updated_at datetime NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

ALTER TABLE smf_product_pricing
ADD PRIMARY KEY (id);

ALTER TABLE smf_product_pricing
MODIFY id int(3) UNSIGNED NOT NULL AUTO_INCREMENT;
COMMIT;

On the above table there is standard_id, it is for detail description of the product. You can omit it if you do not need it.

Tabel 2

CREATE TABLE smf_product_order (
id int(6) UNSIGNED NOT NULL,
user_id int(4) UNSIGNED DEFAULT NULL,
method varchar(200) NOT NULL,
status varchar(100) NOT NULL,
foto varchar(300) DEFAULT NULL,
created_at datetime DEFAULT NULL,
updated_at datetime DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

ALTER TABLE smf_product_order
ADD PRIMARY KEY (id);

ALTER TABLE smf_product_order
MODIFY id int(6) UNSIGNED NOT NULL AUTO_INCREMENT;
COMMIT;

In the above table, user_id is to record who make order. It is very important field.

Table 3

CREATE TABLE smf_product_order_item (
id int(6) UNSIGNED NOT NULL,
order_id int(5) UNSIGNED NULL,
product_id int(3) UNSIGNED NOT NULL,
quantity int(3) UNSIGNED NOT NULL,
currency varchar(100) DEFAULT NULL,
price decimal(5,2) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

ALTER TABLE smf_product_order_item
ADD PRIMARY KEY (id);

ALTER TABLE smf_product_order_item
MODIFY id int(6) UNSIGNED NOT NULL AUTO_INCREMENT;
COMMIT;

In the Table 3 above, order_id I created is NULL default. It is the key field for our trick shopping online.

product_id will be taken from Table 1.

Lets do Gii for all the above tables.

2. Process flow:
2. 1. We show product to be sold.

For icons you can get it from https://fontawesome.com/v4.7.0/icons/

Controller to displat it as below

public function actionShop()
{
    $searchModel = new StandardPriceSearch();
    $dataProvider = $searchModel->search(Yii::$app->request->queryParams);

    return $this->render('shop', [
        'searchModel' => $searchModel,
        'dataProvider' => $dataProvider,
    ]);
}
public function actionLists() {
    $out = [];
    if (isset($_POST['depdrop_parents'])) {
        $parents = $_POST['depdrop_parents'];
        if ($parents != null) {
            $product_type = (int)$parents[0];
            $out = StandardPrice::find()
                    ->where(['product_type'=>$product_type])
                    ->select(['id'=>'id', 'name'=>'id']) //'id' will be recorded, 'name' will be showed
                    ->asArray()
                    ->all();
              
            return Json::encode(['output'=>$out, 'selected'=>'']);

        }
    }
    return  Json::encode(['output'=>'', 'selected'=>'']);
}

There are some table use in this query, it will limit only certain product available to pick by any user.

My orange cart icon actually is

[
‘format’ => ‘raw’,
‘headerOptions’ => [‘style’ => ‘width:5%’, ‘class’ => ‘text-center’],
‘contentOptions’ => [‘style’ => ‘width:5%’, ‘class’ => ‘text-center’],
‘value’ => function ($model) {
return Html::a(’’,
[’/product-order-item/create’,‘product_id’=>$model->standard_id, ‘price’=>$model->price],
[
‘data-toggle’=>“modal”,
‘data-target’=>"#myModal",
‘data-title’=>“Add to myCard”,
]
);
},
],

If you rigth-click the orange cart icon, it will

‘value’ => function ($model) {
return Html::a(’’,
[’/product-order-item/create’,‘product_id’=>$model->standard_id, ‘price’=>$model->price],
[
‘data-toggle’=>“modal”,
‘data-target’=>"#myModal",
‘data-title’=>“Add to myCard”,
]
);
},

If you not prefer to use Modal it will be like this

‘value’ => function ($model) {
return Html::a(’’,
[’/product-order-item/create’,‘product_id’=>$model->standard_id, ‘price’=>$model->price]
);
},

Icon myCart bottom appear only when we have any item picked. You can make sql to make it.

2.2. Put an item into myCart.
When we click orange icon it will appear like this

It could be like by implementing Modal. If you not experience of modal, just use plain form.

User just key in number of pcs product he/she need. I am hidden other field (order_id, product_id), my actual form is like this

<?= $model->standards->standardPrice->product_type.' '. $model->standards->title.' '.$model->standards->standardPrice->currency.' '.$model->standards->standardPrice->price; ?>
<?php $form = ActiveForm::begin([ 'options'=>['onsubmit' => "myButton.disabled = true; return true;"] ]); ?>
    <?= $form->field($model, 'order_id')->hiddenInput()->label(false) ?>

    <?= $form->field($model, 'product_id')->hiddenInput()->label(false) ?>

    <?= $form->field($model, 'currency')->hiddenInput(['value'=>'SGD'])->label(false) ?>

    <?= $form->field($model, 'price')->hiddenInput(['value'=>$model->price])->label(false) ?>

    <?= $form->field($model, 'quantity')->textInput(['placeholder'=>'Type how many pcs'])->label('Pcs Request') ?>
</div>

<div class="form-group">
    <?= Html::submitButton('<i class="fa fa-send fa-lg fa-fw" aria-hidden="true" style="color:white"></i> Submit', ['class' => 'btn btn-info', 'name'=>'myButton']) ?>
</div>

<?php ActiveForm::end(); ?>

Controller for this action

public function actionCreate() { $model = new ProductOrderItem();
    if ($model->load(Yii::$app->request->post())) {
        
        $model->price = $model->quantity * $model->price;
        $model->save();

        return $this->redirect(['standard-price/shop']);
    }
    else{
        $model->product_id = $_GET['product_id'];
        $model->price = $_GET['price'];
    }

    return $this->renderAjax('create', [
        'model' => $model,
    ]);
}

These lines

$model->product_id = $_GET[‘product_id’];
$model->price = $_GET[‘price’];

to use as default value for the fields. Then we could hide the field in the form ($form->field($model, ‘product_id’)->hiddenInput()->label(false)).

If you click Submit, our Table 3 will be inserted.

You can see that even in the Item List the price per unit is SGD10, if I typed 3pcs the price the above Table 3 is 30. In the controller I applied $model->price = $model->quantity * $model->price before we do $model->save();

Please see that only field order_id NULL.

2.3. myCart

If we click myCart icon within the Item List page, we’ll see

There two icon in rightest side of myCart, pencil and trash bin. Those just update and delete as usual from our Gii of Table 3.

Controller to view mycart like below:

public function actionCart() { $query = Yii::$app->getDb()->createCommand(' SELECT smf_product_order_item.id, smf_product_order_item.currency, smf_product_order_item.price as price, smf_product_order_item.quantity, standards.title as title, smf_product_pricing.price as unit FROM smf_product_order_item LEFT JOIN standards ON standards.stdid = smf_product_order_item.product_id LEFT JOIN smf_product_pricing ON standards.stdid = smf_product_pricing.standard_id WHERE smf_product_order_item.postedby = '.Yii::$app->user->id.' AND DAY(smf_product_order_item.created_at) = "'.date('d').'" AND smf_product_order_item.order_id IS NULL ') ->queryAll();
    return $this->render('cart', [
        'model' => $query,
    ]);
}

Please apologize me if I can not inform detail of table standards, you can use your own table for detail of the product.

A new icon is blue button for attach payment and check out. This is very simple online shop and we use bank transfer to complete our transaction. If you click this button, will appear form to upload.

the actual code of the button is

<?= Html::a('Attach payment and check out?', ['/product-order/create1', 'user_id'=>Yii::$app->user->id], [ 'class' => 'btn btn-info', 'data-toggle'=>"modal", 'data-target'=>"#myModal", 'data-title'=>"Upload Transfer Receipt", ] )?>

I have modidy actionCreate1 as follows

public function actionCreate1() { $model = new ProductOrder();
    if ($model->load(Yii::$app->request->post())) {
        //save image
        Yii::setAlias('newsfolder', dirname(dirname(__DIR__)) . '/frontend/web/images/selling');
        $model->foto = UploadedFile::getInstance($model,'foto');

        $filename = rand(0,9999).' - Product Order - Payment Receipt';

        $model->foto->saveAs( Yii::getAlias('@newsfolder/').$filename.'.'.$model->foto->extension );
        $model->foto =  $filename.'.'.$model->foto->extension;

        $model->save();

        $imagine = Image::getImagine();
        $image = $imagine->open(Yii::getAlias('@newsfolder/'.$model->foto));
        $image->save(Yii::getAlias('@newsfolder/'.$model->foto, ['quality' => 40]));
        
       //update 
        $query = Yii::$app->getDb()->createCommand('
            UPDATE smf_product_order_item
            SET order_id = '.$model->id.'
            WHERE postedby = '.Yii::$app->user->id.'
            AND DAY(created_at) = "'.date('d').'"
            AND order_id IS NULL
        ')->execute();

        //send email to buyer
        $email = \Yii::$app->mailer->compose()
        ->setTo([Yii::$app->user->identity->email => Yii::$app->user->identity->profile->first_name.' '.Yii::$app->user->identity->profile->last_name]) 
        ->setFrom([\Yii::$app->params['adminEmail'] => \Yii::$app->params['nickName'] .' \'s Server'])
        ->setSubject('Your Order #'.sprintf('%04d', $model->id).' at '.\Yii::$app->params['nickName'].' Shop.')
        ->setHtmlBody('Dear '.Yii::$app->user->identity->profile->first_name.' '.Yii::$app->user->identity->profile->last_name.' 
            <br><br>Thank you for your payment made via bank transfer received on '.date('Y-m-d H:i:s').' 
            <br><br>We will revert to you if necessary.
            <br><br>Best Regards.
            <br><br><br>'.\Yii::$app->params['nickName'].' Office Admin'
        )->send();         

        Yii::$app->session->setFlash('success', 'Thank you. Your order and transfer receipt has received by the server.');

        return $this->redirect(['view', 'id' => $model->id, 'user_id'=>Yii::$app->user->id]);
    }

    return $this->renderAjax('create1', [
        'model' => $model,
    ]);
}

</code

I will not explain about saving image, assume you have familiar with it.

The trick is lie in the above $query. We must do it because when we put any item into Table 3, order_id has NULL by default. By doing this trick, we entried order_id into the table.

When our form executed it will send notification email to user.

This our Attache payment form

3. End Result
If our order successful, will show this page

If we click Attachment tab in the above image, it will show just our uploaded file.

Thats it…wish you luck.

4 Likes