Routes Manager

Erstellt am: Tuesday 18 September 2018  |  Letzte Änderung am: Monday 24 September 2018

In this article we take it a step further and write a plugin based on ItemManager, that automatically creates new routes when a new product category is created or updated within the ItemManager interface.

Sometimes it is required to be able to create one or more new product categories while the application deployments already in operation. In order to automatically include a subsequently created category in the list of our routes, an extended storage mechanism must be implemented, which monitors the saving of the categories and intervene in the running process if necessary. Since different categories are managed in the ItemManager, the product categories should be clearly identified as such, so that they can be entered into the routing list.

As already mentioned in a previous article, ItemManager provides the ability that you may hook into in order to modify the behavior of the IM admin methods. We will use this ability to write the Routes Manager plugin that will take over the task of managing (creating, updating, deleting) our routes.

Requirements

  • ItemManager versions supported 2.4.5+
  • PHP 7+

Preparation

All right, let's get down to business. First, open the file /data/imanager/settings/config.php and change the variable $this->injectActions to true. If the file does not yet exist, copy it from the directory /plugins/imanager/lib/inc/ and change the variable as described. This unlocks the function injection in ItemManager.

Create directory structure as shown below:

plugins/
|
+ im_routes_manager.php
|
+ im_routes_manager/
   |
   + config.php
   |
   + Routes.php
   |
   + category-form.tpl
   |
   + lang/
      |
      + en_US.php
  • im_routes_manager.php —  This is the entry file, where we will initialize the plugin and define our RoutesManager class.
  • config.php — This is the file where we will enter the configuration parameters like the route category ID, etc.
  • Routes.php — This file will contain the Routes class (Just copy it from here).
  • category-form.tpl — This file contains our new replacement template for the category editor in IM admin.
  • en_US.php — The English language pack.

Implementation

Next, copy the plugin skeleton at the bottom of Hooking into the ItemManager backend methods page, and paste the code into the im_routes_manager.php file. However, we should extend it as follows:

<?php

register_plugin(
    basename(__FILE__, '.php'),
    'IM Routes Manager',
    '0.1',
    'J.E',
    'https://ehret-studio.com',
    'An ItemManager backend extension that automatically creates new routes.',
    null,
    null
);

add_action('ImActivated', 'im_action');

function im_action($manager)
{
    if(!class_exists('RoutesManager'))
    {
        class RoutesManager extends Admin
        {
            /**
             * @var $routes - Routes
             */
            private $routes;

            /**
             * @var $config - RoutesManager config parameters
             */
            private $config;

            /**
             * RoutesManager constructor.
             */
            public function __construct()
            {
                parent::__construct();
                $this->thisfile = basename(__FILE__, '.php');
                $config = new StdClass;
                i18n_merge($this->thisfile) || i18n_merge($this->thisfile, 'en_US');

                require GSPLUGINPATH."$this->thisfile/Routes.php";
                require GSPLUGINPATH."$this->thisfile/config.php";

                $this->config = $config;
                $this->routes = new Routes($this->config->routesCategoryId);
            }


            /**
             * This is the IM method for rendering the category editor,
             * that we hook into in order to override template to change
             * the markup it generate.
             *
             * @return bool
             */
            protected function buildCategoryDetailsEditor()
            {
                if(!$this->routes) {
                    MsgReporter::setClause('routes_not_found', array(), true, $this->thisfile);
                    return false;
                }

                $settings = $this->tpl->getTemplates('detailscategory');
                $form = $this->tpl->getTemplate('form', $settings);

                ob_start();
                include $this->thisfile.'/category-form.tpl';
                $buffer = ob_get_clean();

                $id = isset($this->input['categorydetails']) ? $this->input['categorydetails'] : null;
                if(!$id) {
                    $id = isset($this->input['id']) ? $this->input['id'] : null;
                    if(!$id) return false;
                }
                $category = $this->manager->getCategoryMapper()->getCategory($id);
                if(!$category) {
                    MsgReporter::setClause('err_category_id_unknown', array());
                    return false;
                }

                $route = $this->routes->get($this->config->routeName);
                $checked = null;
                if($route && in_array($category->id, $route['value'])) {
                    $checked = true;
                }
                $buffer = $this->tpl->render($buffer, array(
                    'pc-checked' => ($checked) ? ' checked' : '')
                );
                $form->set('content', $buffer);

                return parent::buildCategoryDetailsEditor();
            }


            /**
             * This is the IM admin method that we hook into in order
             * to modify its behavior.
             *
             * @param $method
             * @param $args
             *
             * @return mixed
             */
            protected function callModelMethod($method, $args)
            {
                /**
                 * Extends the updateCategory method
                 */
                if($method == 'updateCategory')
                {
                    $post = $args[0];
                    $refresh = $args[1];

                    $result = $this->manager->{$method}($post, $refresh);

                    if($result) {

                        $category = $this->manager->getCategoryMapper()->getCategory($post['id']);
                        $route = $this->routes->get($this->config->routeName);

                        // "Is that a product category?" checked
                        if((isset($post['product_category']) && $post['product_category'])) {

                            // Create route if it does not exist
                            if(!$route) {
                                $route = array(
                                    'name' => $this->config->routeName,
                                    'type' => 'Product Categories',
                                    'value' => array()
                                );
                            }
                            if(!in_array($category->id, $route['value'])) {
                                $route['value'][] = $category->id;
                                $this->routes->set($this->config->routeName, $route);
                                $this->routes->save();
                            }

                        } else {
                            if($route && in_array($category->id, $route['value'])) {
                                $key = array_search($category->id, $route['value']);
                                unset($route['value'][$key]);
                                $values = array_values($route['value']);
                                $route['value'] = $values;
                                $this->routes->set($this->config->routeName, $route);
                                $this->routes->save();
                            }
                        }
                    }
                    return $result;
                /**
                 * Extends the deleteCategory method
                 */
                } elseif($method == 'deleteCategory')
                {
                    $category_id = $args[0];
                    $refresh = $args[1];

                    $category = $this->manager->getCategoryMapper()->getCategory($category_id);
                    $route = $this->routes->get($this->config->routeName);

                    $result = $this->manager->{$method}($category_id, $refresh);

                    if($result && $route && in_array($category->id, $route['value'])) {
                        $key = array_search($category->id, $route['value']);
                        unset($route['value'][$key]);
                        $values = array_values($route['value']);
                        $route['value'] = $values;
                        $this->routes->set($this->config->routeName, $route);
                        $this->routes->save();
                    }
                    return $result;
                }
                // If none is the case, invoke default method
                return parent::callModelMethod($method, $args);
            }
        }

        $routesManager = new RoutesManager;
        $manager->setAdmin($routesManager);
    }
}

Okay, let's go into the details and explain a number of specific areas:

...
add_action('ImActivated', 'im_action');

function im_action($manager)
{
...

... the plugin is called every time ItemManager is loaded. We extend the IM Admin class by modifying its methods to change their behavior:

...
class RoutesManager extends Admin
{
...
$routesManager = new RoutesManager;
$manager->setAdmin($routesManager);
...

In particular, we change the behavior of the buildCategoryDetailsEditor() method by using a different template to display the category editor markup, with an additional checkbox:

We also change the behavior of the updateCategory() and deleteCategory() methods by verifying that the Is that a product category? checkbox is checked. If this is the case, we store the ID of this category in the routes list.

This is how our replacement template category-form.tpl looks like:

<div class="manager-wrapper">
    <form class="largeform" action="load.php?id=imanager&category&categoryupdate" method="post" accept-charset="utf-8">
        <div>
            <div id="cat-details">
                <h3 class="menuglava">[[lang/edit_category]]</h3>
                <p>[[lang/edit_category_info]]</p>
                <div class="fieldarea">
                    <label for="catid" class="im-left">[[lang/category_id]]</label>
                    [[infotext]]
                    <p id="catid" class="im-cat-info">[[catid]]</p>
                </div>

                <div class="fieldarea">
                    <label for="catname" >[[lang/category_name]]</label>
                    [[infotext]]
                    <p><input id="catname" class="text-fields-left text" name="name" type="text" value="[[catname]]"></p>
                </div>

                <div class="fieldarea">
                    <label for="catslug" >[[lang/category_slug]]</label>
                    [[infotext]]
                    <p><input id="catslug" class="text-fields-left text" name="slug" type="text" value="[[catslug]]"></p>
                </div>

                <div class="fieldarea">
                    <label for="catposition" >[[lang/category_position]]</label>
                    [[infotext]]
                    <p><input id="catposition" class="number-fields-left number" name="position" type="number" value="[[catposition]]"></p>
                </div>

                <div class="fieldarea">
                    <label for="product-category" >Is that a product category?</label>
                    <p class="field-info"><i class="fa fa-info-circle"></i> Activate the checkbox if this is a product category.</p>
                    <p><input id="product-category" class="checkbox" name="product_category" value="1" type="checkbox"[[pc-checked]]></p>
                </div>

                <div class="fieldarea">
                    <label for="catcreated" >[[lang/category_created]]</label>
                    [[infotext]]
                    <p class="im-cat-info">[[created]]</p>
                </div>

                <div class="fieldarea">
                    <label for="catcreated" >[[lang/category_updated]]</label>
                    [[infotext]]
                    <p class="im-cat-info">[[updated]]</p>
                </div>

                <input type="hidden" value="[[catid]]" name="id">
            </div>
            <p class="im-buttonwrapper"><span><input class="submit" type="submit" name="category_save" value="[[lang/label_save_settings]]"></span></p>
        </div>
    </form>
</div>

In config.php, add the following params (Also note, that you need to adjust the $config->routesCategoryId variable because your Routes category probably has a different ID):

<?php if(!defined('IN_GS')){ die('you cannot load this page directly.'); }

/**
 * Your IM Routes category id
 */
$config->routesCategoryId = 4;

/**
 * ASCII no special characters or spaces allowed
 */
$config->routeName = 'categories';

/**
 * Short title for the route type
 */
$config->routeType = 'Product Categories';

Create en_US.php language Pack:

<?php
$i18n = array(
	'routes_not_found' => 'Routes class not found'
);

So, that's it, you can start with testing. In the frontend you can use the code I already showed here, but you shouldn't include the routes.php file anymore, because the Routes class is already embedded by the RoutesManager plugin.

Autor: Bigin  |  Tags:  FrameworkPHPGetSimpleDevelopmentItemManager