Ready to build an online shop for MODX Revolution

Often, when the developer selects the engine to another shop, he usually evaluates this question based on several criteria:
the
    the
  • Paid/free (if paid, how much).
  • the
  • Which functionality is out of the box.
  • the
  • How easy it is to screw some kind of a functionality.
  • the
  • How much it will pull goods to hosting and not go broke.
  • the
  • How flexible security policies to ensure joint work of the different departments.
  • the
  • What payment systems are supported.

Under the cut I talk about the new ready build an online store that was developed based on these criteria, I think, may make people think even experienced developers.

At the end of the video with a brief overview of the engine and the two installation methods

Important! Forgot to say: who are too lazy to watch the video, but will deploy the Assembly, the username/password to admin default: admin/admin.


Demo site.


Before you read any further, I advise you to look demo version.

I must say that deploying this Assembly, you will immediately get that this website. That is, once there is a model directory, registration/authorization through social networks, payment via ROBOKASSA, etc. (of course in your copy need to specify in ROBOKASSA config your data and bind the website to the social networks).

the Basis of the engine (and quite a large backstory)


The basis was taken the framework MODX Revolution. Just take your time to spit and close the page. It's not exactly the MODX with which you may had to meet. I work with MODX from the beginning of 2009 year, and you know it backwards and forwards. And Yes, I like many faced with a number of its disadvantages (such as templates and chunks in the database, brakes, etc.). Plus, before I met MODX worked a lot with different samopisny and other engines, and MODX-e I left precisely because of its flexibility. Yeah, I don't like it, but it is easily much to change, while not touching the kernel. In the process I had several components that add to or change some of the functionality of MODX. Here are a couple most important ones:
phpTemplates — enables static MODX-templates call as usual php files.
modxSmarty — Connects to the front of the Smarty template engine and complements it with some buns, providing a seamless experience by MODX-om.
shopModx — module for developing Internet-shops.

In the end MODX becomes not only a standardization but also a much greater performance. Sites with tens of thousands of work documents with a response of 0.02 — 0.6 seconds. Plus, you can almost completely skip the syntax for MODX, and if you know how to program in php and Smarty know — here in development you have no problems will arise.

But one of the most important things in MODX-e which definitely keeps my chain is a system of packages (modules for MODX-a). It really is cool. I even wrote module that allows you to create your own package repository. This is especially useful different web studios and active developers. The most delicious is that packaging can not only separate modules, but in General anything on the website, at least entirely, though separately, though the whole website in General. So there was a picture of MODX sites. Initially it was implemented at the modxcloud.com (official hosting from the developers of MODX), but absolutely no documentation and any releases they had posted a script vapor that was intended to ensure that anyone could take a snapshot of your website and throw him on modxcloud.com. Thus feedback would not implied (that is, to take pictures with modxcloud.com and deploy on any hosting). I won't go into details, but I got this vapor, modified it and added another script (import.php). Now with this script you can take pictures of websites and deploy them on top of the website. Download my vapor from official repository. And that's just with this vapor I took a course not only on individual modules, but also ready to build sites.
what's the point of these assemblies?

The point is that when the project uses several individual components that together should give some kind of expected result, it is important not only their presence, but fine tuning to provide the best effect + maximum flexibility. And it is clear that this is necessary not only to know them very well, but to have the experience, know how to do, what pitfalls there are etc. But if you give a developer a ready-made website, where everything is installed and configured, the ceiling of the entry and the amount of work decrease significantly.
This build just is Internet-based store and my standard modules, providing better performance, flexibility and manageability.

What is already there in this Assembly?


the
    the
  • Added component Billing. This module tied everything to do with orders, payment, etc.
  • the
  • Basket ceased to exist separately. Now the Cart is not an Order (Order). Now not even the bookings are stored in a database that at least allows you to see who and what they are interested in, as well as to determine the actual percentage of conversion and to identify possible errors.
  • the
  • Component Basket (Basket) remained, but almost everything to do with by the orders, transferred to Billing. Basket and then there will be a separate module, and Billing-e will be only the necessary minimum of logic. The calculation that the mechanism of ordering, payment, etc. can be implemented in any third-party modules that will interact with the billing system.
  • the
  • is Added and converted into a new default template using bootstrap. A lot ajaxouch buns and a full JS API.
  • the
  • Added spreadsheet editor documents.
  • the
  • Added control orders.
  • the
  • Added the user profile, registration, password change, password recovery, etc.
  • the
  • is Configured to check through the Login, change/password recovery, etc.
  • the
  • Added module modHybridAuth (authorization through social networks). While clearly checked Twitter, Facebook and Google, but have other work.
  • the
  • service charge Robokassa.
  • the
  • Configured security policies:
    the
      the
    • Content Manager;
    • the
    • Administrator;
    • the
    • store Manager;
    • the
    • Advanced store Manager.



What to do with this website after installation?


Make a copy of the template and change it anything. The templating Smarty, the input data arrays, all of the processors on classes. That is, without touching the kernel, it is possible to alter the site as you like.

Example of how to add another payment system

Here we have the payment through ROBOKASSA, and the task is to fasten still any method of payment. Let's see how it's done.

This is the base processor for any type of payment.
<?php

/*
Abstract class for payment.
It cannot be called directly, to avoid the injection of charge. 
This class must extend another class-specific payment system
to use methods of check of payment of the payment system itself
*/

abstract class extends modWebPaymentsCreateProcessor modObjectCreateProcessor{
public $classKey = 'Payment';

protected $BillingProcessorsPath;

public function checkPermissions() {

// Check the signature payment system
$ok = $this->checkSignature();
if($ok !== true){
$this->error($ok);
return false;
}

return parent::checkPermissions();
}

public function initialize(){

$this->BillingProcessorsPath = MODX_CORE_PATH . 'components/billing/processors/';

$this->setDefaultProperties(array(
'currency_id' => $this- > modx- > getOption('shopmodx.default_currency'),
));

if(!$this->getProperty('paysystem_id')){
return $this->error("was Not received ID payment system");
}

return parent::initialize();
}

public function beforeSet(){

$this->setProperties(array(
"createdby" => $this- > modx->user->id ? $this- > modx->user->id : null,
"date" = > time(),
));

return parent::beforeSet();
}

public function beforeSave(){
if(
!$currency_id = (int)$this->getProperty('currency_id')

OR ! $currency instanceof ShopmodxResourceCurrency
){
return $this->error("Not been received by the object currency");
}

if(
!$paysystem_id = (int)$this->getProperty('paysystem_id')
OR !$paysystem = $this- > modx- > getObject('Paysystem', $paysystem_id)
OR ! $paysystem Paysystem instanceof
){
return $this->error("Not been received by the facility payment system");
}

// Check if specified account of the payment system, it is necessary to ensure that 
// he's still not listed in the billing
if($paysys_invoice_id = $this->object->get('paysys_invoice_id')){
if($this- > modx- > getCount($this- > classKey, array(
'paysys_invoice_id' => $paysys_invoice_id,
'paysystem_id' => $paysystem_id,
))){
return $this->error("This account already created in the system.");
}
}

$this->object->addOne($currency);
$this->object->addOne($paysystem);

return parent::beforeSave();
}

/*
It is necessary to prescribe the method in which validation will be performed 
signature from the server of the payment system
*/
abstract protected function checkSignature();

protected function log($msg, $level = null){
if($level === null){
$level = xPDO::LOG_LEVEL_INFO;
}
$this- > modx- > log($level, "[Basket - ".__CLASS__."] {$msg}");
$this- > modx- > log($level, print_r($this->getProperties(), true));
return $msg;
}

protected function error($msg){
return $this->log($msg, xPDO::LOG_LEVEL_ERROR);
}

/*
Logichem all the errors of the processor, just in case
*/
public function failure($msg = ",$object = null) {
$this->error($msg);
if(!empty($this->object) && is_object($this- > object)){
$this- > error(print_r($this->object->toArray(), true));
}
return parent::failure($msg,$object);
}

public function cleanup() {
/*
// If the payment is successful, then update the order status
*/
if($order_id = $this->object->get('order_id')){
$this- > modx- > runProcessor('mgr/orders/status/pay', array(
'order_id' = > $order_id,
), array(
'processors_path' => $this->BillingProcessorsPath, 
));
// Just in case reset the error counter, if suddenly called
// the CPU was error
$this- > modx->error->reset();
}

return $this- > success($this->getSuccessMessage(), $this->object);
}

protected function getSuccessMessage(){
return ";
}
}

return 'modWebPaymentsCreateProcessor';


It is abstract and cannot be called directly, as each payment system and its mechanisms for verification of payment. But this class already provides all the necessary logic, and extending the processor waits for only one thing: confirmation of payment and installation amount and other payment details.

But the expanding processor specifically for ROBOKASSA:
<?php
/*
Posting a payment from ROBOKASSA
*/

require_once dirname(dirname(__FILE__)). '/create.class.php';

class modWebPaymentsRobokassaCreateProcessor extends modWebPaymentsCreateProcessor{

public function initialize(){

$this->setProperties(array(
"paysystem_id" => $this- > modx- > getOption('robokassa.bill_serv_id'),
));

return parent::initialize();
}

/*
Check the signature with ROBOKASSA
*/
protected function checkSignature(){

$mrh_pass2 = $this- > modx- > getOption('robokassa.mrh_pass2');

// The parameters passed in the request from ROBOKASSA
$crc = mb_strtoupper($this->getProperty('SignatureValue'));
$out_sum = $this->getProperty('OutSum');
$inv_id = $this->getProperty('InvId');
$shp_aid = $this->getProperty('shp_aid'); 
$shp_order = $this->getProperty('shp_order', null);
$shp_trff = $this->getProperty('shp_trff');
$shp_uid = $this->getProperty('shp_uid');

$my_crc = mb_strtoupper(md5("{$out_sum}:{$inv_id}:{$mrh_pass2}:shp_aid={$shp_aid}:shp_order={$shp_order}:shp_trff={$shp_trff}:shp_uid={$shp_uid}"));

$this- > modx- > log(xPDO::LOG_LEVEL_INFO, "[Robokassa robokassa.payResult]", print_r($_REQUEST, true));

// check correctness of the signature
if ($my_crc !=$crc){
$error = "[Robokassa robokassa.payResult] - Wrong signature. Received: '{$crc}'. Should be: '{$my_crc}'";
$this- > modx- > log(xPDO::LOG_LEVEL_ERROR, $error);
return "bad sign";
} 

// else
$this->setProperties(array(
"sum" => $out_sum, 
"order_id" => $shp_order, 
"owner" => $shp_uid,
"paysys_invoice_id" => $inv_id,
));

return true;
}

protected function getSuccessMessage(){
return 'OK'.$this->getProperty('InvId');
} 
}


As you can see, it's only 60 lines of code. But the result will not only be held to pay taking into account who paid what, how much, etc., but will also automatically change the order status to Paid. And here to fasten still any method of payment is only a few tens of lines.

Results


In the end, it turned out actually really not a bad engine. I must say that apart from the flexibility, it's also very not bad. Just recently stumbled upon a thread where people argued that even 40 000 products already annoying not sickly their stores. I did shopping on shopModx with tens of thousands of products without any special tricks, and everything works fine. And even if the goods are hundreds of thousands (I already did one 150 000 items), with slight modifications the shop and pull so much.

And most importantly, this build is absolutely free! Of course we are always open for the reception of donation from grateful developers, but de facto the engine is fully free.

And finally, a video with a brief overview of the engine and the two installation methods.


the

UPD:
One of the new plushies Assembly — basket storage in the database. Or rather the basket as it ceased to be an independent entity, and turned into a display of the new order. The new Order is just not placed the Order.

clickable


A little more than sign for the order status:

New. as soon As the user tries to add a product to the cart, if the order for it has not yet been created, creates a new order and the goods are immediately added to this order. All orders can be seen immediately, even if the user is not logged and nothing more is done.
This allows the marketing Department to more clearly see the life of the store, to calculate the conversion, to evaluate the possible causes of the behavior of users, etc.

Feature. If the user created an application (that is, place your order, stating your address and other information), then order status is changed to Issued. From this point, the Manager can accept the order. (Yes, you can buy new work and different scenarios are possible. Now logic embedded such that the Manager only sees new and their orders. Once the Manager took the order, another Manager will not be able to accept it. If the Manager is right, he doesn't even see contact information not of their orders).



Paid. If the user alone pays for the order on the website, the order status is automatically changed to Paid.

Then a few more model status, type, paid, etc.


Notifications about new orders coming in the mail. (Specifically there is a group of users, each of which receives notifications).

UPD2:
Here the load did the test loadimpact.com.
The test is free and it is not known where (shows download to seconds), but anyone can call the site and verify that there is not 5 seconds. But the schedule stable that on one that on 50 clients. And even 50 clients CPU was far from full load, giving often 10-25%, and sometimes only 50-70%. (hosting digitalocean.com for $10).



UPD3: Images to this comment.








UPD4: Yesterday we held a webinar on ShopModxBox, and although the recording quality was not very, post it too (for General information).
Article based on information from habrahabr.ru

Комментарии

Популярные сообщения из этого блога

Why I left Google Zurich

2000 3000 icons ready — become a sponsor! (the table of orders)

New web-interface for statistics and listen to the calls for IP PBX Asterisk