📜 ⬆️ ⬇️

Extend platform functionality for ReadyScript online stores

Today, each customer wants to see unique chips in his online store. These can be interesting cumulative discounts, referral programs, non-standard filters for searching for certain products, etc. All this requires individual improvements in CMS functionality. In this article we will describe what features ReadyScript offers for creating customized solutions.



Like many CMS that support automatic updates, ReadyScript does not allow you to grossly interfere with the code of standard modules and the kernel; such changes will be reversed the next time the system is updated. New functions should be introduced into the system through new files. For this purpose, appropriate mechanisms are provided for in the CMS, which will be discussed below.

1. Event handling


Event system - a tool that allows you to change the standard course of the system by installing handlers for various system events. The result of the handlers can be taken into account by the system and adjust the overall progress of the program. Consider the technical part of the event:
')
As soon as the entry point script index.php gets control, it looks for a Config / MyHandlers or Config / Handlers class for each module. If one of these classes is found, then the init method is called, in which each module must subscribe to events. All event handlers are also usually described in the same class in which the subscription occurs. Thus, the module has a single place in which all its “external” activity is visible.

After forming the list of subscribers, the script continues its execution, during which it generates various events that are processed by the modules.

Calling events in ReadyScript occurs at key points in the system, event names, as a rule, consist of a prefix and a variable part. The variable part usually carries the clarifying meaning of the event. For example, all write operations to the database in ReadyScript occur through ORM objects, respectively, there is an event in the system that is called before the data of the ORM object is written. The name of such events is formed as follows:

orm.beforewrite. <short name of the ORM object> , where:

This event receives parameters in the form of an array, the keys of which are:

If the event handler is called inside the handler, the object will not be saved. Let's write an example of the code that will stop updating the product, and display an error: “I do not want to update the product!”.

First you need to create a simple module with the following structure:

test //   config //    file.inc.php //   handlers.inc.php //   


The file file.inc.php may be as follows:

 <?php namespace Test\Config; /** *    */ class File extends \RS\Orm\ConfigObject { /** *    - * @return array */ public static function getDefaultValues() { return array( 'name' => '', 'description' => ' ', 'version' => '1.0.0.0', 'author' => 'ReadyScript lab.' ); } } 


The module should be placed in the / modules folder, installed on the system and enabled in the section Website -> Configuring Modules.
An example of the file handlers.inc.php, which intercepts the save event:

 <?php /** *     Test. *      /modules/test/config/handlers.inc.php */ namespace Test\Config; class Handlers extends \RS\Event\HandlerAbstract { function init() { $this->bind('orm.beforewrite.catalog-product'); } /** *   " ". *      . *         (  ). *      Handlers,     . * * @param mixed $params -   * @param \RS\Event\Event $event -    * @return void */ public static function ormBeforewriteCatalogProduct(array $params, \RS\Event\Event $event) { if ($params['flag'] == \RS\Orm\AbstractObject::UPDATE_FLAG) { //    /** *    ORM  * @var \Catalog\Model\Orm\Product */ $product = $params['orm']; $product->addError('   !'); $event->stopPropagation(); } } } 


This module will block the ability to save goods in the entire system. Similarly, you can intercept the events of saving the order, the user, and all other objects in the system, since all of them are ORM objects.

“ Is it possible to expand with the help of events, for example, the product card page in the administrative panel and add a column to the table of products in the database? ". Answer: it is possible. Below I will tell you how.

Since all interaction with the database in the system occurs through ORM objects, it will be sufficient to set the handler for the initialization event of the ORM object, and add additional properties to the object in the handler. Let me remind you that all properties of objects are set during their initial initialization. Initialization of one class of objects occurs only once during the execution of the PHP script.

The name of the initialization event of the ORM object is constructed as follows:
orm.init. <short name of the ORM object>

As a parameter, an ORM object is initialized to the event. An example of a handler code expanding the product card:
 namespace Test\Config; class Handlers extends \RS\Event\HandlerAbstract { function init() { $this->bind('orm.init.catalog-product'); } /** *   " ORM  ". *        --> .   ->  * * @param \Catalog\Model\Orm\Product * @return void */ public static function ormInitCatalogProduct(\Catalog\Model\Orm\Product $orm_product) { $orm_product->getPropertyIterator()->append(array( //    ' ', //.      'test_property' => new \RS\Orm\Type\Integer(array( // .     INT 'maxLength' => 1, //      INT(1) 'description' => ' ', //  'checkboxView' => array(1,0), //1 -   checkbox, 0 -   //  : //-       . .  \RS\Orm\Type\Integer )) )); } } 


After adding such a handler to the system, you need to reinstall the module “product catalog” (via the administrative panel, section Website-> Module Settings-> Product Catalog) in order for ReadyScript to add a new column to the database table of the \ Catalog \ Model \ Orm \ Product object .

In the product card, a new field will be located on a separate tab and look like this:



Consider another example of event system capabilities. Suppose that a task has arisen to add an item to the menu of actions on a single product, which is located in the section “product catalog” in the administrative panel. To solve the problem, it is necessary to intercept an event that throws a CRUD controller (\ RS \ Controller \ Admin \ Crud) after forming the appearance helper and before calling the action of the controller. Event Name:

controller.exec. <controller short name>. <action name> , where

For example, if the \ Catalog \ Controller \ Admin \ Ctrl controller is called with the Index action, the full name of the event will look like this: controller.exec.catalog-admin-ctrl.index

Below is an example of the event handler:

 <?php namespace Test\Config; class Handlers extends \RS\Event\HandlerAbstract { function init() { $this->bind('controller.exec.catalog-admin-ctrl.index'); } /** *   * * @param \RS\Controller\Admin\Helper\CrudCollection $helper -    .  * @return void */ public static function controllerExecCatalogAdminCtrlIndex(\RS\Controller\Admin\Helper\CrudCollection $helper) { /** * @var \RS\Html\Table\Control - :   */ $table_control = $helper['table']; $columns = $table_control->getTable()->getColumns(); //   foreach($columns as $column) { if ($column instanceof \RS\Html\Table\Type\Actions) { //    // $column -         //      foreach($column->getActions() as $action) { if ($action instanceof \RS\Html\Table\Type\Action\DropDown) { //        //       .  $action->addItem(array( 'title' => ' !', //  'attr' => array( //  //  crud-get,     ajax    'class' => 'crud-get', //crud-get    data-confirm-text,    ,    'data-confirm-text' => '     ()?', //@   ,     , ..       //          . //,   : ?id=@id&do=action,   @id,    id   //   getAdminPattern    /admin/test-example/?do=Action&id=@id '@href' => \RS\Router\Manager::obj()->getAdminPattern('Action', array(':id' => '@id'), 'test-example'), ), )); } } } } } } 


The result of the action of this code will be the following item in the menu:



A complete list of events in ReadyScript with descriptions can be found in the official documentation here .

2. Overload routes


Overloading routes allows you to transfer specific addresses (URLs) of a site to a non-native controller for processing.
Let's say we have a need to make changes to the checkout controller. How to do it better?

To answer the question, consider the whole situation. Control of the controller passes the route. It is he who establishes the connection between the URL / checkout / ... and the \ Shop \ Controller \ Front \ Checkout controller. Other modules and templates use the id of this route (shop-front-checkout) to form links to checkout. The route id is not a short controller name , since if a route does not explicitly specify a handler controller to which control will pass, then a controller is searched for, whose short name is equal to the route id.

Accordingly, the solution to our problem would be to create a route with the same id, processing the same URL, but which will transfer control to another controller. And already in another controller, we can implement anything.

There is a task - to disable the route registered by another module and create a route with the same id with its own module. In this we will be helped by the possibility of the event subsystem to set the priority to the event handler.

Since all routes are entered into the system using the getroute event, it is enough to set the priority of the handler in our module so that it will be called at the very end. The rule will work here: when adding two routes with the same id, the last one remains in the system. Consider the code:

 <?php namespace Test\Config; class Handlers extends \RS\Event\HandlerAbstract { function init() { $this->bind('getroute', null, //callback_class -   $this null, //callback_method -       0 //.   ,    .  - - 10 ); } /** *     */ public static function getRoute(array $routes) { //    $routes[] = new \RS\Router\Route( 'shop-front-checkout', //ID  array('/checkout/{Act}/', '/checkout/'), //  URL array('controller' => 'test-front-examplecontroller'), // -.      ' ' //   .  ); return $routes; } } 


The handler given above will send all requests to the controller with the class \ Test \ Controller \ Front \ ExampleController, which you can inherit from \ Shop \ Controller \ Front \ Checkout, and overload any selected methods, or implement the controller completely from scratch .

3. Replacing standard event handlers


If there is a disagreement with the way a module handles events, ReadyScript allows you to overload the "alien" event-handling file. As mentioned above, during the initialization of the event system, the modules are first looking for the MyHandlers class, and then the Handlers, to call the first found init method.

It is enough to declare a module of another module in the namespace \ MODULE_NAME \ Config class MyHandlers, in order to specify its own event handlers in it.

If global changes are not required, you can create the MyHandlers class inherited from Handlers and overload only some methods.

4. Class substitution (NOT recommended method)


All functionality in ReadyScript is implemented in classes. All classes of modules and kernels are loaded using autoload. The following condition is set in the script connection rules: first, in the folder corresponding to the class namespace, the files are searched for the name CLASSA.my.inc.php and if this does not exist, then the search and attachment of the file NAME CLASSA.inc.php is performed

All classes present in the distribution have the extension .inc.php, respectively, any files with the extension .my.inc.php will not be overwritten during the upgrade, they can be used to implement the modified functionality of the standard classes.

However, this method is NOT recommended, but developers should be aware of it. When upgrading to “original” classes, methods that may use other modules may change, which in general may affect the stability of the system.

5. Possibilities of themes


Expansion of functionality is not always associated with the server side, and can often affect only the frontend, for example, if you need to add your own JavaScript to the product card page.

For the appearance of the site meets the theme of the design. The design theme has the ability to overload the default module templates, for this is the moduleview folder. To reload the product card template /modules/catalog/view/product.tpl, just copy it in the following path /templates/{__ }/moduleview/catalog/product.tpl, then you can edit the new file. It is worth noting that all CSS and JS files are connected in templates, this allows you to overload the required template and prescribe new constructions for connecting styles and scripts in new ways.

Changes in the standard templates will be overwritten during the centralized system update process, so it is recommended to create your own theme beforehand (by cloning the contents of the folder with one of the standard themes) in order to modify it further.

Conclusion


The capabilities of the ReadyScript platform allow developers to embody the most sophisticated ideas of customers. The system architecture pushes for the expansion of the functionality of the system with the help of additional modules, which later allows you to reuse the written code.

Source: https://habr.com/ru/post/235647/


All Articles