Your IP : 216.73.216.79


Current Path : /var/www/html/jkm/backend/modules/mmngr/controllers/
Upload File :
Current File : /var/www/html/jkm/backend/modules/mmngr/controllers/ModuleGeneratorController.php

<?php
namespace backend\modules\mmngr\controllers;

use Yii;
use yii\web\Controller;


/**
 * Module for import external module trough zip file.
 */
class ModuleGeneratorController extends Controller
{

    /**
     * Template path
     */
    const TEMPLATE_GII = 'dynaweb';

    public function actionIndex()
    {
        return $this->render('index', []);
    }

    /**
     * Generates the code based on the current user input and the specified code template files.
     */
    public function actionGenerate()
    {
        $post = Yii::$app->request->post();

        $module_id    = $post['moduleid'];
        $module_name  = $post['name'];
        $module_icon  = $post['icon'];
        $module_version  = $post['version'];
        $module_author   = $post['author'];
        $module_email = $post['email'];
        $model_ns     = "backend\\modules\\{$module_id}\\models";
        $module_class = "backend\\modules\\{$module_id}\\Module";
        $controller_class = "backend\\modules\\{$module_id}\\controllers";
        $module_description  = $post['description'];


        if(empty($module_id)) {
            Yii::$app->session->addFlash('log', 'Empty module, id, module id is required.');
        }

        if($this->createModule($module_id, $module_class)) {
            Yii::$app->session->addFlash('log', 'Generating Module Success');
        }

        //create table and output tablename
        $tablename = $this->createTable($module_id, [
            'name' => $post['field_name'],
            'type' => $post['field_type'],
            'length' => $post['field_length']
        ]);
        
        // create model        
        if($this->createModel($tablename, $model_ns, ucfirst($module_id))) {
            Yii::$app->session->addFlash('log', 'Generating Model Success ');
        };


        // create crud 
        if($this->createCrud(
            $controller_class,
            ucfirst($module_id) . "Controller", //controller name
            $model_ns . "\\" . ucfirst($module_id), // model name,
            $module_id
        )) {
            Yii::$app->session->addFlash('log', 'Generating Crud Success');
        };
        
        // create menu
        if($this->createMenu($module_name, $module_id, $module_icon)) {
            Yii::$app->session->addFlash('log', 'Generating Menu Success');
        };

        if($this->assignModule($module_name, $module_id, $module_version, $module_author, $module_email, $module_description)) {
            Yii::$app->session->addFlash('log', 'Assigning Menu Success');
        };

        $this->redirect('view');
    }

    /***
     * view model generation status
     * 
     **/
    public function actionView() {
        return $this->render('view');
    }

    /**
     * Create Module
     */
    private function createModule($module_id, $module_class)
    {   

        $parameter = [
            '--interactive='           . '0',
            '--overwrite='             . '1',
            '--moduleID='     . '"' . $module_id . '"',
            '--moduleClass='  . '"' . $module_class . '"',
        ];

        $full_parameters = implode(' ', $parameter);

        $output = $this->shellCommand('yii gii/module', $full_parameters);
        
        if(strpos($output, 'Files were generated successfully!') > 0) {
            return true;
        } else {
            Yii::$app->session->addFlash('log', $output);
        }

        return false;
    }

    private function assignModule($module_name, $module_id, $module_version, $module_author, $module_email, $module_description)
    {   
        try {
            $current_date = date('Y-m-d H:i:s');
            // add parent menu
            Yii::$app->db->createCommand(
            <<<SQL
            INSERT INTO `module_import` (`id`, `module_id`, `name`, `version`, `class`, `params`, `routes`, `author`, `email`, `licence`, `description`, `file_content`, `image_path`, `data`, `homepage`, `created`) VALUES (NULL, '{$module_id}', '{$module_name}', '{$module_version}', 'backend\\\modules\\\\$module_id\\\\Module', NULL, '', '{$module_author}', '{$module_email}', '', '{$module_description}', '', '', '', '', '{$current_date}');
            SQL
            )
            ->execute()
            ;

            return true;
        } catch(\Throwable $t) {
            Yii::$app->session->addFlash('err', 'Assigning Module error:-' . PHP_EOL );
            Yii::$app->session->addFlash('err', $t->getMessage() . PHP_EOL);
        }
    }

     /**
     * Create Module
     */
    private function createModel($table_name, $namespace, $model_class)
    {
        $parameter = [
            '--interactive='          . '0',
            '--tableName='   . '"' . $table_name . '"',
            '--ns='          . '"' . $namespace . '"',
            '--modelClass='  . '"' . $model_class . '"',
        ];

        $full_parameters = implode(' ', $parameter);

        $output = $this->shellCommand('yii gii/model', $full_parameters);

        if(strpos($output, 'Files were generated successfully!') > 0) {
            return true;
        }

        return false;
    }

    /**
     * Create Module
     */
    private function createCrud($controller_class, $controller_name, $model_class, $module_id)
    {   

        //controler dir
        $controller_dir = str_replace("\\", "/", $controller_class);
        $controller_dir = '..' . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . $controller_dir;
        $view_dir = $this->camelToKebabCase($module_id);

        //create dir if not exist
        if (!is_dir($controller_dir)) {
            mkdir($controller_dir);
        }

        $parameter = [
            '--interactive='           . '0',
            '--template='        . '"' . self::TEMPLATE_GII . '"',
            '--viewPath='        . '"' . "@backend/modules/{$module_id}/views/{$view_dir}" . '"',
            '--controllerClass=' . '"' . $controller_class . '\\' . $controller_name . '"',
            '--modelClass='      . '"' . $model_class . '"'
        ];

        $full_parameters = implode(' ', $parameter);

        $output = $this->shellCommand('yii gii/crud', $full_parameters);

        if(strpos($output, 'done!') > 0) {
            echo 'Crud Generated';
            return true;
        }

        return false;
    }

    /**
     * Create table
     */
    private function createTable($moduleId, $columns)
    {   
        try {
            // create table
            $tablename = $this->snakeCaseFromCamelCase($moduleId);

            $query_table_exist = Yii::$app->db->createCommand("SHOW TABLES LIKE '{$tablename}'")->queryAll();

            if(!empty($query_table_exist)) {
                // Yii::$app->db->createCommand("DROP TABLE {$tablename}")->execute();
                throw new \Exception("This table name is already exists ({$tablename})");
            }

            // create the tables

            //add column
            if(is_array($columns)) {
                $rows = [];
                
                $migrate = new \yii\db\Migration();
                
                //column definition
                $migrate_columns = [];
                // set primary key
                $migrate_columns[$tablename . '_id'] = $migrate->primaryKey(); // {modulename}_id as primary key
                
                //combine field as one row array // $key = 'name/type/length'
                foreach($columns as $key => $column) {
                    $i = 0;
                    foreach($column as $val) {
                        $rows[$i][$key] = $val;
                        $i++;
                    }
                }

                // loop trough row and construct the column based on type
                foreach($rows as $row) {
                    var_dump($row['type']);
                    $migrate_columns[$row['name']] = $this->columnTypeMap($row['type'], $row['length']);
                }

                //run the migrations
                $migrate->createTable($tablename, $migrate_columns);

                return $tablename;
            }

        } catch(\Throwable $t) {
            Yii::$app->session->addFlash('err', 'Database Error:-' . PHP_EOL );
            Yii::$app->session->addFlash('err', $t->getMessage() . PHP_EOL);

            return $this->redirect('view');
        }

    }

     /**
     * run shell
     */
    private function shellCommand($command, $parameters) {
        $shell_comand = '';
         // detect server os
        if (PHP_OS_FAMILY === "Windows") {
            echo "Running on Windows";die;
        } elseif (PHP_OS_FAMILY === "Linux") {
            echo "Running on Linux";
            $shell_comand = "cd ../../ && php {$command} {$parameters}";
        }
        
        // Yii::$app->session->addFlash('log', $shell_comand . PHP_EOL );

        return shell_exec($shell_comand);
    }

    /**
    * Create menu for the module
    */
    private function createMenu($module_name, $module_id, $module_icon) {

    try {
        $module_path = $this->camelToKebabCase($module_id);
        $parent_menu_id = 0;
        
        $query_generated_module_menu = Yii::$app->db->createCommand(
            <<<SQL
            SELECT * FROM backend_menu WHERE menu_name = "Cms Modules"
            SQL
            )
            ->queryOne()
            ;

        if(empty($query_generated_module_menu)) {
            // add parent menu
            Yii::$app->db->createCommand(
            <<<SQL
            INSERT INTO `backend_menu` (`menu_id`, `menu_name`, `menu_link`, `menu_active_route`, `menu_class`, `menu_param`, `menu_status`, `menu_parent_id`, `menu_descr`) VALUES (NULL, 'Cms Modules', '#', '', 'fa fa-maxcdn', '', '1', '0', 'Generated Module from cms');
            SQL
            )
            ->execute()
            ;

            $parent_menu_id = Yii::$app->db->getLastInsertID();

            // map parent menu
            Yii::$app->db->createCommand(
            <<<SQL
            INSERT INTO `backend_role_mapping` (`id`, `role_code`, `menu_id`, `parent_id`, `sort`) VALUES (NULL, 'super-admin', '{$parent_menu_id}', '0', '99');
            SQL
            )
            ->execute()
            ;

            $parent_map_id = Yii::$app->db->getLastInsertID();
        } else {
            $parent_menu_id = $query_generated_module_menu['menu_id'];

            $query_generated_module_menu = Yii::$app->db->createCommand(
            <<<SQL
            SELECT * FROM `backend_role_mapping` WHERE `menu_id` = $parent_menu_id
            SQL
            )
            ->queryOne()
            ;

            $parent_map_id = $query_generated_module_menu['id'];
        }

        // add menu
        Yii::$app->db->createCommand(
            <<<SQL
            INSERT INTO `backend_menu` (`menu_id`, `menu_name`, `menu_link`, `menu_class`, `menu_status`) VALUES (NULL, '{$module_name}', '/{$module_id}/{$module_path}/index', '{$module_icon}', '1');
            SQL
            )
            ->execute()
            ;

        // map child menu to parent menu
        $menu_id = Yii::$app->db->getLastInsertID();

        Yii::$app->db->createCommand(
            <<<SQL
            INSERT INTO `backend_role_mapping` (`id`, `role_code`, `menu_id`, `parent_id`) VALUES (NULL, 'super-admin', '{$menu_id}', '{$parent_map_id}');
            SQL
            )
            ->execute()
            ;

        return true;
    }   
    catch(\Throwable $t) {
        Yii::$app->session->addFlash('err', 'Create Module Menu error:-' . PHP_EOL );
        Yii::$app->session->addFlash('err', $t->getMessage() . PHP_EOL);
    }
        
    }

    /**
    * Column type 
    */
    private function columnTypeMap($type, $length) {
        $migrate = new \yii\db\Migration();
        
        $map =  [
            'string' => $migrate->string($length),
            'text'   => $migrate->text($length),
            'date'   => $migrate->datetime(),
            'int' => $migrate->integer($length),
        ];

        return $map[$type];
    }   

    private function camelToKebabCase($str) {
        // Replace uppercase letters preceded by lowercase letters with a "-" before them
        $kebab = preg_replace('/(?<!^)[A-Z]/', '-\\0', $str);
        // Convert the entire string to lowercase
        return strtolower($kebab);
    }

    private function snakeCaseFromCamelCase($input) {
        return strtolower(preg_replace('/(?<!^)[A-Z]/', '_$0', $input));
    }
  
}