piotrpolak/pepiscms

View on GitHub
pepiscms/modules/development/libraries/ModuleGenerator.php

Summary

Maintainability
F
4 days
Test Coverage
<?php

/**
 * PepisCMS
 *
 * Simple content management system
 *
 * @package             PepisCMS
 * @author              Piotr Polak
 * @copyright           Copyright (c) 2007-2018, Piotr Polak
 * @license             See license.txt
 * @link                http://www.polak.ro/
 */

defined('BASEPATH') or exit('No direct script access allowed');

/**
 * An utility for generating CRUD modules.
 *
 * @since 1.0.0
 */
class ModuleGenerator extends ContainerAware
{
    /**
     * @var \PiotrPolak\PepisCMS\Modulerunner\ModuleLocatorInterface
     */
    private $moduleLocator;

    /**
     * Module_generator constructor.
     * @param null $params
     */
    public function __construct($params = null)
    {
        $this->moduleLocator = new \PiotrPolak\PepisCMS\Modulerunner\ModuleLocator();
    }

    /**
     * Creates and installs user space module
     *
     * @param $module_database_table_name
     * @param $module_name
     * @param bool $auto_install
     * @param bool $parse_database_schema
     * @param bool $database_group
     * @param bool $translations
     * @param bool $generate_public_controller
     * @param bool $is_crud
     * @param bool $generate_security_policy
     * @return bool
     * @throws ReflectionException
     */
    public function makeUserSpaceModule($module_database_table_name,
                                        $module_name,
                                        $auto_install = true,
                                        $parse_database_schema = true,
                                        $database_group = false,
                                        $translations = false,
                                        $generate_public_controller = true,
                                        $is_crud = true,
                                        $generate_security_policy = false)
    {
        $this->load->library('SecurityPolicy');
        $this->load->library('SecurityPolicyBuilder');
        $this->load->moduleLibrary('translator', 'LanguageHelper');
        $this->load->helper('inflector');
        $this->load->library('Cachedobjectmanager');

        $definition = $this->getDefinition($module_database_table_name, $parse_database_schema, $database_group);

        $template_base_path = APPPATH . '../resources/module_template/';

        $module_name_singular = singular($module_name);
        $module_name_lower_case = strtolower($module_name);

        $label_field_name = 'id';
        $image_field_name = false;
        $description_field_name = false;
        $order_field_name = false;
        $created_at_field_name = false;
        $updated_at_field_name = false;
        $filters_element = '';
        $translations = $this->makeSureTranslationsAreNotEmpty($translations);


        // Building directory structure
        $directory = $this->makeDirectories($translations, $module_name_lower_case);

        // Used for builder, contains only valid table fields
        $list_of_fields = array();
        // Raw Datagrid & Formbuilder definition output
        $definition_output = 'CrudDefinitionBuilder::create()';
        // Raw Language definition output
        $language_pairs = array();

        $module_model_name = ucfirst($module_name_singular) . '_model';

        if ($parse_database_schema) {
            // Getting constants to be used instead of their numerical values
            $refl = new ReflectionClass('DataGrid');
            $datagrid_constants = array_flip($refl->getConstants());

            // Getting constants to be used instead of their numerical values
            $refl = new ReflectionClass('FormBuilder');
            $formbuilder_constants = array_flip($refl->getConstants());


            if ($definition) {
                // NOTE this also includes FKs that are not writable!!!
                $available_field_names = array_keys($definition);

                $image_field_name = $this->getImageFieldName($available_field_names);
                $label_field_name = $this->getLabelFieldName($available_field_names);
                $description_field_name = $this->getDescriptionFieldName($available_field_names, $label_field_name);
                $order_field_name = $this->getOrderFieldName($available_field_names, $definition);
                $created_at_field_name = $this->getCreatedAtFieldName($available_field_names, $definition);
                $updated_at_field_name = $this->getUpdatedAtFieldName($available_field_names, $definition);

                $was_last_field_of_upload_type = false;

                $definition_output .= "\n";

                $tabs = "            ";
                foreach ($definition as $key => $value) {
                    // Skip ID fields
                    if ($key == 'id') {
                        continue;
                    }
                    $value = $this->hideMetadataField($key, $label_field_name, $value, $description_field_name);
                    $value = $this->hidePasswordField($value);
                    $value = $this->hideOrderField($key, $order_field_name, $value);
                    $value = $this->makeTimestampStatisticsDate($key, $updated_at_field_name, $created_at_field_name, $value);
                    $value = $this->setDefaultOnForCheckboxFields($value, $key);

                    $is_field_of_upload_type = in_array($value['input_type'], array(FormBuilder::IMAGE, FormBuilder::FILE));

                    // Only for table fields
                    if (!isset($value['foreign_key_table']) || (isset($value['foreign_key_relationship_type'])
                            && $value['foreign_key_relationship_type'] != FormBuilder::FOREIGN_KEY_MANY_TO_MANY)) {
                        $list_of_fields[] = $key;
                    }

                    // Generating line
                    $language_pairs[$module_name . '_' . $key] = $this->generateLanguageLabel($key);

                    if ($is_field_of_upload_type != $was_last_field_of_upload_type) {
                        $definition_output .= $tabs . '->withLineBreak()' . "\n\n";
                    }

                    $key_representation = $this->getCrudDefinitionLabelKeyRepresentation($key, $list_of_fields, $module_model_name);
                    $definition_output .= $tabs . '->withField(' . $key_representation . ')' . "\n";

                    $definition_output .= $this->generateCall($value, $datagrid_constants, $formbuilder_constants, $tabs);
                    $filters_element .= $this->generateFilterElement($value, $key);

                    // Adding SEO friendly callback for images and files
                    if ($value['input_type'] == FormBuilder::IMAGE || $value['input_type'] == FormBuilder::FILE) {
                        $definition_output .= $tabs . '    ' . $this->generateBuilderMethodCall('upload_complete_callback', 'array($this, \'_fb_callback_make_filename_seo_friendly\')') . "\n";
                    }

                    // Adding values and filter values for checkboxes to look human friendly
                    if ($value['input_type'] == FormBuilder::CHECKBOX) {
                        $definition_output .= $tabs . '    ' . $this->generateBuilderMethodCall('values', 'array(0 => $this->lang->line(\'global_dialog_no\'), 1 =>  $this->lang->line(\'global_dialog_yes\'))') . "\n"; // Only needed if you change input type to FormBuilder::SELECTBOX
                        $definition_output .= $tabs . '    ' . $this->generateBuilderMethodCall('filter_values', 'array(0 => $this->lang->line(\'global_dialog_no\'), 1 =>  $this->lang->line(\'global_dialog_yes\'))') . "\n";
                    }

                    // Setting default value for a timestamp
                    if ($value['input_type'] == FormBuilder::TIMESTAMP && !isset($definition[$key]['input_default_value'])) {
                        $definition_output .= $tabs . '    ' . $this->generateBuilderMethodCall('input_default_value', 'date(\'Y-m-d H:i:s\')') . "\n";
                    }

                    // Setting default value for a date
                    if ($value['input_type'] == FormBuilder::DATE && !isset($definition[$key]['input_default_value'])) {
                        $definition_output .= $tabs . '    ' . $this->generateBuilderMethodCall('input_default_value', 'date(\'Y-m-d\')') . "\n";
                    }

                    // Order field - hide and set default value
                    if ($key == $order_field_name && !isset($definition[$key]['input_default_value'])) {
                        $definition_output .= $tabs . '    ' . $this->generateBuilderMethodCall('input_default_value', 'time()') . "\n";
                    }

                    $definition_output .= $tabs . '->end()' . "\n";


                    $was_last_field_of_upload_type = $is_field_of_upload_type;
                }
            }

            $definition_output .= $tabs . '->withImplicitTranslations($module_name, $this->lang)' . "\n";
            $definition_output .= $tabs . '->build();' . "\n";

            //die( $definition_output );
        } else {
            $definition_output .= ';';
        }

        // Variables passed to pattern compiler
        $module_label = ucfirst(str_replace('_', ' ', $module_name));
        $data = $this->prepareReplacementTokens($module_database_table_name, $module_name, $module_label,
            $module_name_singular, $definition_output, $label_field_name, $list_of_fields,
            $image_field_name, $description_field_name, $order_field_name, $updated_at_field_name, $filters_element,
            $module_model_name);

        $this->buildTranslations($module_name, $translations, $module_label, $language_pairs, $directory, $module_name_lower_case);
        $this->generateOrRegenerateModel($directory, $module_name_lower_case, $module_name_singular, $template_base_path, $data);
        $this->generateModuleDescriptor($directory, $module_name_lower_case, $template_base_path, $data);
        $this->generateCrudStuffIfNecessary($is_crud, $directory, $template_base_path, $data, $module_name_lower_case);
        $this->generatePublicStuffIfNeccesary($generate_public_controller, $directory, $module_name_lower_case, $template_base_path, $data);
        $this->generateSecurityPolicyIfNeccesary($module_name, $generate_security_policy, $module_name_singular);
        $this->copyIcons($directory, $template_base_path);
        $this->doAutoinstallIfNeccesary($module_name, $auto_install);

        return true;
    }

    /**
     * @param $key
     * @param $value
     * @return string
     */
    private function generateBuilderMethodCall($key, $value)
    {
        $map = array(
            'foreign_key_field' => 'withForeignKeyIdField'
        );

        if (isset($map[$key])) {
            $method = $map[$key];
        } else {
            $method = 'with' . ucfirst(camelize($key));
        }
        return '->' . $method . '(' . $value . ')';
    }

    /**
     * @param $possible_image_field_names
     * @param $available_field_names
     * @return string|bool
     */
    private function getImageFieldNameExact($possible_image_field_names, $available_field_names)
    {
        $image_field_name = false;
        foreach ($possible_image_field_names as $possible_image_field_name) {
            if (in_array($possible_image_field_name, $available_field_names)) {
                $image_field_name = $possible_image_field_name;
                break;
            }
        }
        return $image_field_name;
    }

    /**
     * @param $available_field_names
     * @param $possible_image_field_names
     * @return string|bool
     */
    private function getImageFieldNameBestMatch($available_field_names, $possible_image_field_names)
    {
        foreach ($available_field_names as $available_field_name) {
            foreach ($possible_image_field_names as $possible_image_field_name) {
                if (strpos($available_field_name, $possible_image_field_name) !== false) {
                    return $available_field_name;
                }
            }
        }
        return false;
    }

    /**
     * @param $available_field_names
     * @return string|bool
     */
    private function getLabelFieldName($available_field_names)
    {
        $possible_label_field_names = array('name', 'label', 'title', 'first_name', 'last_name', 'firstName', 'lastName', 'message', 'question', 'answer', 'code');

        foreach ($possible_label_field_names as $possible_label_field_name) {
            if (in_array($possible_label_field_name, $available_field_names)) {
                return $possible_label_field_name;
            }
        }
        return false;
    }

    /**
     * @param $available_field_names
     * @param $label_field_name
     * @return string|bool
     */
    private function getDescriptionFieldName($available_field_names, $label_field_name)
    {
        $possible_description_field_names = array('description', 'desc', 'lead', 'introduction', 'intro', 'answer',
            'message', 'code', 'address', 'street_address', 'state', 'voievodship', 'city', 'street');

        foreach ($possible_description_field_names as $possible_description_field_name) {
            if (in_array($possible_description_field_name, $available_field_names)
                && $possible_description_field_name !== $label_field_name) {
                return $possible_description_field_name;
            }
        }
        return false;
    }

    /**
     * @param $available_field_names
     * @param $definition
     * @return string|bool
     */
    private function getOrderFieldName($available_field_names, $definition)
    {
        $possible_order_field_names = array('item_order', 'position', 'pos');

        foreach ($possible_order_field_names as $possible_order_field_name) {
            if (in_array($possible_order_field_name, $available_field_names)) {
                // Numeric type check
                if (strpos($definition[$possible_order_field_name]['validation_rules'], 'numeric') >= 0) {
                    return $possible_order_field_name;
                }
            }
        }
        return false;
    }

    /**
     * @param $available_field_names
     * @param $definition
     * @return string|bool
     */
    private function getCreatedAtFieldName($available_field_names, $definition)
    {
        foreach ($available_field_names as $available_field_name) {
            if (strpos($available_field_name, 'create') !== false) {
                // Input type check
                if ($definition[$available_field_name]['input_type'] == FormBuilder::TIMESTAMP) {
                    return $available_field_name;
                }
            }
        }

        return false;
    }

    /**
     * @param $available_field_names
     * @param $definition
     * @return string|bool
     */
    private function getUpdatedAtFieldName($available_field_names, $definition)
    {
        foreach ($available_field_names as $available_field_name) {
            if (strpos($available_field_name, 'update') !== false) {
                // Input type check
                if ($definition[$available_field_name]['input_type'] == FormBuilder::TIMESTAMP) {
                    return $available_field_name;
                }
            }
        }

        return false;
    }

    /**
     * @param $translations
     * @param $module_name_lower_case
     * @return string
     */
    private function makeDirectories($translations, $module_name_lower_case)
    {
        $directory = INSTALLATIONPATH . 'modules/' . $module_name_lower_case . '/';
        @mkdir($directory);
        @mkdir($directory . 'models');
        @mkdir($directory . 'controllers');
        @mkdir($directory . 'views');
        @mkdir($directory . 'resources');
        @mkdir($directory . 'language');

        // Building translations directory structure
        foreach ($translations as $translation) {
            @mkdir($directory . 'language/' . $translation);
        }
        return $directory;
    }

    /**
     * @param $directory
     * @param $template_base_path
     */
    private function copyIcons($directory, $template_base_path)
    {
        // Copy 16px icon
        if (!file_exists($directory . 'resources/icon_16.png')) {
            copy($template_base_path . 'resources/icon_16.png', $directory . 'resources/icon_16.png');
        }

        // Copy 32px icon
        if (!file_exists($directory . 'resources/icon_32.png')) {
            copy($template_base_path . 'resources/icon_32.png', $directory . 'resources/icon_32.png');
        }
    }

    private function cleanupCache()
    {
        $this->auth->refreshSession();
        $this->cachedobjectmanager->cleanup();
        $this->db->cache_delete_all();
        ModuleRunner::flushCache();
    }

    /**
     * @param $module_name
     * @param $module_name_singular
     * @param $policy_save_path
     * @throws ReflectionException
     */
    private function generateSecurityPolicy($module_name, $module_name_singular, $policy_save_path)
    {
        $method_default_access = array(
            'index' => 'READ',
            'edit' => 'WRITE',
            'preview' => 'READ',
            'revisionrestorefield' => 'FULL_CONTROL',
            'revision' => 'READ',
            'revisions' => 'READ',
            'export' => 'FULL_CONTROL',
            'import' => 'FULL_CONTROL',
            'move' => 'WRITE',
            'delete' => 'WRITE',
            'star' => 'WRITE',
        );

        $controllers = $this->securitypolicy->describeModuleControllers($module_name);

        if (isset($controllers[0]->methods)) {
            // Preparing description
            $policy_entries = array();
            foreach ($controllers[0]->methods as $method) {
                $policy_entries[] = array(
                    'controller' => $module_name,
                    'method' => $method->name,
                    'entity' => $module_name_singular,
                    'access' => isset($method_default_access[$method->name]) ? $method_default_access[$method->name] : 'NONE'
                );
            }

            // Generate and write XML file
            $xml = $this->securitypolicybuilder->build($module_name, $policy_entries);
            file_put_contents($policy_save_path, $xml);
        }
    }

    /**
     * @param $directory
     * @param $template_base_path
     * @param $data
     */
    private function generatePublicItemView($directory, $template_base_path, $data)
    {
        $file_view_index = $directory . 'views/public/item.php';
        if (!file_exists($file_view_index)) {
            file_put_contents($file_view_index,
                PatternCompiler::compile(file_get_contents($template_base_path . 'views/public/item.php'), $data));
        }
    }

    /**
     * @param $directory
     * @param $template_base_path
     * @param $data
     */
    private function generatePublicIndexView($directory, $template_base_path, $data)
    {
        $file_view_index = $directory . 'views/public/index.php';
        if (!file_exists($file_view_index)) {
            file_put_contents($file_view_index,
                PatternCompiler::compile(file_get_contents($template_base_path . 'views/public/index.php'), $data));
        }
    }

    /**
     * @param $directory
     * @param $module_name_lower_case
     * @param $template_base_path
     * @param $data
     */
    private function generatePublicController($directory, $module_name_lower_case, $template_base_path, $data)
    {
        @mkdir($directory . 'views/public');
        $file_controller = $directory . $this->moduleLocator->getPublicControllerPath($module_name_lower_case);
        if (!file_exists($file_controller)) {
            file_put_contents($file_controller,
                PatternCompiler::compile(file_get_contents($template_base_path . '_controller.php'), $data));
        }
    }

    /**
     * @param $directory
     * @param $template_base_path
     * @param $data
     */
    private function generateAdminNonCrudAdminView($directory, $template_base_path, $data)
    {
        @mkdir($directory . 'views/admin');
        $file_view_index = $directory . 'views/admin/index.php';
        if (!file_exists($file_view_index)) {
            file_put_contents($file_view_index,
                PatternCompiler::compile(file_get_contents($template_base_path . 'views/admin/index_no_crud.php'), $data));
        }
    }

    /**
     * @param $directory
     * @param $module_name_lower_case
     * @param $template_base_path
     * @param $data
     */
    private function generateModuleDescriptor($directory, $module_name_lower_case, $template_base_path, $data)
    {
        $file_descriptor = $directory . $this->moduleLocator->getDescriptorPath($module_name_lower_case);
        if (!file_exists($file_descriptor)) {
            file_put_contents($file_descriptor,
                PatternCompiler::compile(file_get_contents($template_base_path . '_descriptor.php'), $data));
        }
    }

    /**
     * @param $file_model_path
     * @param $data
     * @return string
     */
    private function regenerateSetAcceptedFieldsForExistingModel($file_model_path, $data)
    {
        // Replace acceptable fields
        $model_file_contents_exploded = file($file_model_path, FILE_IGNORE_NEW_LINES);
        if (count($model_file_contents_exploded) > 0) {
            foreach ($model_file_contents_exploded as &$model_file_contents_exploded_item) {
                if (strpos($model_file_contents_exploded_item, 'setAcceptedPostFields') !== false
                    && strpos($model_file_contents_exploded_item, ';') !== false) {
                    $model_file_contents_exploded_item = '        $this->setAcceptedPostFields(array(' . $data['coma_separated_list_of_fields'] . ')); /* line generated at ' . date('Y-m-d H:i:s') . ' */';
                }
            }
            file_put_contents($file_model_path, implode("\n", $model_file_contents_exploded));
        }
    }

    /**
     * @param $translation_file_path
     * @param $language_pairs
     * @return mixed
     */
    private function mergeLanguageTranslationPairs($translation_file_path, $language_pairs)
    {
        // Merging existing translations with the new pairs
        if (file_exists($translation_file_path)) {
            $existing_language_pairs = $this->languagehelper->getLanguageByPath($translation_file_path);
            if (count($existing_language_pairs) > 0) {
                foreach ($existing_language_pairs as $key => $value) {
                    $language_pairs[$key] = $value;
                }
            }
        }
        return $language_pairs;
    }

    /**
     * @param $module_name
     * @param $translations
     * @param $module_label
     * @param $language_pairs
     * @param $directory
     * @param $module_name_lower_case
     */
    private function buildTranslations($module_name, $translations, $module_label, $language_pairs, $directory, $module_name_lower_case)
    {
        // Some default language data
        $language_pairs[$module_name . '_module_name'] = $module_label;
        $language_pairs[$module_name . '_add'] = 'Add a new element';

        // Building and writing translation file
        foreach ($translations as $translation) {
            $translation_file_path = $directory . 'language/' . $translation . '/' . $module_name_lower_case . '_lang.php';
            $language_pairs = $this->mergeLanguageTranslationPairs($translation_file_path, $language_pairs);

            // Serializing translations
            $this->languagehelper->dumpFile($translation_file_path, $language_pairs);
        }
    }

    /**
     * @param $is_crud
     * @param $template_base_path
     * @param $file_admin_controller
     * @param $data
     */
    private function generateAdminController($is_crud, $template_base_path, $file_admin_controller, $data)
    {
        if ($is_crud) {
            $template_file_admin_controller_path = $template_base_path . '_admin_controller.php';
        } else {
            $template_file_admin_controller_path = $template_base_path . '_admin_controller_non_crud.php';
        }
        file_put_contents($file_admin_controller, PatternCompiler::compile(file_get_contents($template_file_admin_controller_path), $data));
    }

    /**
     * @param $module_database_table_name
     * @param $module_name
     * @param $module_label
     * @param $module_name_singular
     * @param $definition_output
     * @param $label_field_name
     * @param $list_of_fields
     * @param $image_field_name
     * @param $description_field_name
     * @param $order_field_name
     * @param $updated_at_field_name
     * @param $filters_element
     * @param $module_model_name
     * @return array
     */
    private function prepareReplacementTokens($module_database_table_name,
                                              $module_name,
                                              $module_label,
                                              $module_name_singular,
                                              $definition_output,
                                              $label_field_name,
                                              $list_of_fields,
                                              $image_field_name,
                                              $description_field_name,
                                              $order_field_name,
                                              $updated_at_field_name,
                                              $filters_element,
                                              $module_model_name)
    {
        $data = array(
            'module_name' => $module_name,
            'module_databse_table_name' => $module_database_table_name,
            'module_class_name' => ucfirst($module_name),
            'module_label' => $module_label,
            'model_class_name' => $module_model_name,
            'mudule_singular_name' => $module_name_singular,
            'definition_output' => $definition_output,
            'label_field_name' => $label_field_name,
            'fields_list_output' => $this->generateFieldsListOutputDefinition($list_of_fields),
            'coma_separated_list_of_fields' => $this->generateFieldsListOutputModelUsageDefinition($list_of_fields),
            'author' => $this->auth->getUserEmail(),
            'date' => date('Y-m-d'),
            'image_meta_code_element' => $image_field_name ? '$this->setMetaImageField(\'' . $image_field_name . '\', $this->uploads_base_path);' : '',
            'description_meta_code_element' => $description_field_name ? '$this->setMetaDescriptionPattern(\'{' . $description_field_name . '}\', array($this, \'_fb_format_meta_description\'));' : '',
            'order_meta_code_element' => $order_field_name ? '$this->setOrderable(true, \'' . $order_field_name . '\');' : '$this->setOrderable(false);',
            'updated_at_code_element' => $updated_at_field_name ? '$data_array[\'' . $updated_at_field_name . '\'] = date(\'Y-m-d H:i:s\');' : '',
            'filters_element' => $filters_element,
        );
        return $data;
    }

    /**
     * @param $available_field_names
     * @return bool|string
     */
    private function getImageFieldName($available_field_names)
    {
        $possible_image_field_names = array('image', 'img', 'picture', 'image_path', 'img_path', 'picture_path', 'thumb');
        $image_field_name = $this->getImageFieldNameExact($possible_image_field_names, $available_field_names);
        if (!$image_field_name) {
            $image_field_name = $this->getImageFieldNameBestMatch($available_field_names, $possible_image_field_names);
        }
        return $image_field_name;
    }

    /**
     * @param $module_model_name
     * @param $key
     * @return string
     */
    private function getFieldModelConstantFullName($module_model_name, $key)
    {
        return $module_model_name . '::' . $this->getFieldModelConstantShortName($key);
    }

    /**
     * @param $key
     * @return string
     */
    private function getFieldModelConstantShortName($key)
    {
        return strtoupper($key) . '_FIELD_NAME';
    }

    /**
     * @param $coma_separated_list_of_fields
     * @return string
     */
    private function generateFieldsListOutputDefinition($coma_separated_list_of_fields)
    {
        $output = '';
        foreach ($coma_separated_list_of_fields as $field_name) {
            $output .= "\t" . 'const ' . $this->getFieldModelConstantShortName($field_name) . " = '" . $field_name . "';\n";
        }
        return $output;
    }

    /**
     * @param $coma_separated_list_of_fields
     * @return string
     */
    private function generateFieldsListOutputModelUsageDefinition($coma_separated_list_of_fields)
    {
        $keys = array();
        foreach ($coma_separated_list_of_fields as $field_name) {
            $keys[] = 'self::' . $this->getFieldModelConstantShortName($field_name);
        }
        return implode(",\n\t\t\t\t\t", $keys);
    }

    /**
     * @param $key
     * @param $list_of_fields
     * @param $module_model_name
     * @return string
     */
    private function getCrudDefinitionLabelKeyRepresentation($key, $list_of_fields, $module_model_name)
    {
        if (in_array($key, $list_of_fields)) {
            $key_constant_name = $this->getFieldModelConstantFullName($module_model_name, $key);
        } else {
            $key_constant_name = "'" . $key . "'";
        }
        return $key_constant_name;
    }

    /**
     * @param $key
     * @param $label_field_name
     * @param $value
     * @param $description_field_name
     * @return mixed
     */
    private function hideMetadataField($key, $label_field_name, $value, $description_field_name)
    {
        // Do not show label field
        if ($key == $label_field_name) {
            $value['show_in_grid'] = false;
        }

        // Do not show description field
        if ($key == $description_field_name) {
            $value['show_in_grid'] = false;
        }
        return $value;
    }

    /**
     * @param $value
     * @return mixed
     */
    private function hidePasswordField($value)
    {
        // Do not show password fields
        if ($value['input_type'] == FormBuilder::PASSWORD) {
            $value['show_in_grid'] = false;
        }
        return $value;
    }

    /**
     * @param $key
     * @param $order_field_name
     * @param $value
     * @return mixed
     */
    private function hideOrderField($key, $order_field_name, $value)
    {
        // Order field - hide and set default value
        if ($key == $order_field_name) {
            $value['show_in_grid'] = false;
            $value['input_type'] = FormBuilder::HIDDEN;
        }
        return $value;
    }

    /**
     * @param $key
     * @param $updated_at_field_name
     * @param $created_at_field_name
     * @param $value
     * @return mixed
     */
    private function makeTimestampStatisticsDate($key, $updated_at_field_name, $created_at_field_name, $value)
    {
        // Make the time marking fields non editable on purpose
        if ($key == $updated_at_field_name || $key == $created_at_field_name) {
            $value['input_is_editable'] = false;
        }
        return $value;
    }

    /**
     * @param $value
     * @param $key
     * @return mixed
     */
    private function setDefaultOnForCheckboxFields($value, $key)
    {
        // Default ON checkbox fields
        $boolean_default_true_field_names = array('is_active', 'is_enabled', 'is_on');
        // Default ON checkbox fields
        if ($value['input_type'] == FormBuilder::CHECKBOX && !isset($value['input_default_value'])
            && in_array($key, $boolean_default_true_field_names)) {
            $value['input_default_value'] = 1;
        }
        return $value;
    }

    /**
     * @param $key
     * @return null|string|string[]
     */
    private function generateLanguageLabel($key)
    {
        // Generating label, removing _id if present, for FKs
        $language_label = $key;
        $language_label = preg_replace('/' . preg_quote('_id', '/') . '$/', '', $language_label);
        $language_label = ucfirst(trim(str_replace('_', ' ', $language_label)));
        return $language_label;
    }

    /**
     * @param $value
     * @param $key
     * @return string
     */
    private function generateFilterElement($value, $key)
    {
        $filters_element = '';
        foreach ($value as $v_key => $v_value) {
            if ($v_key == 'filter_type') {
                // for date filters we define extra filters
                if ($v_value == DataGrid::FILTER_DATE) {
                    $filters_element .=
                        '        $this->datagrid->addFilter($this->lang->line($module_name.\'_' . $key . '\').\' (\'.$this->lang->line(\'crud_label_from\').\')\', \'' . $key . '\', DataGrid::FILTER_DATE, false, DataGrid::FILTER_CONDITION_GREATER_OR_EQUAL);
        $this->datagrid->addFilter($this->lang->line($module_name.\'_' . $key . '\').\' (\'.$this->lang->line(\'crud_label_to\').\')\', \'' . $key . '\', DataGrid::FILTER_DATE, false, DataGrid::FILTER_CONDITION_LESS_OR_EQUAL);
';
                    continue;
                }
            }
        }
        return $filters_element;
    }

    /**
     * @param $value
     * @param $datagrid_constants
     * @param $formbuilder_constants
     * @param $tabs
     * @return string
     */
    private function generateCall($value, $datagrid_constants, $formbuilder_constants, $tabs)
    {
        $definition_output = '';
        foreach ($value as $v_key => $v_value) {
            if ($v_key == 'filter_type') {
                // for date filters we define extra filters
                if ($v_value == DataGrid::FILTER_DATE) {
                    continue;
                }

                // else
                $v_value = 'DataGrid::' . $datagrid_constants[$v_value];
            } // For these fields we want to keep constansts instead of numerical values
            elseif ($v_key == 'input_type' || $v_key == 'foreign_key_relationship_type') {
                $v_value = 'FormBuilder::' . $formbuilder_constants[$v_value];
            } // To keep the uploads path in a single place
            elseif ($v_key == 'upload_path' || $v_key == 'upload_display_path') {
                $v_value = '$this->uploads_base_path';
            } // Resolve boolan variables
            elseif (is_bool($v_value)) {
                $v_value = ($v_value ? 'true' : 'false');
            } // Wrap non numeric values
            elseif (!is_numeric($v_value)) {
                $v_value = '\'' . str_replace('\'', '\\\'', $v_value) . '\'';
            }

            $definition_output .= $tabs . '    ' . $this->generateBuilderMethodCall($v_key, $v_value) . "\n";
        }
        return $definition_output;
    }

    /**
     * @param $module_database_table_name
     * @param $parse_database_schema
     * @param $database_group
     * @return bool
     * @throws Exception
     */
    private function getDefinition($module_database_table_name, $parse_database_schema, $database_group)
    {
        $definition = false;

        if ($parse_database_schema) {
            $this->load->moduleLibrary('crud', 'TableUtility', array('database_group' => $database_group));

            if (!$this->tableutility->tableExists($module_database_table_name)) {
                throw new \Exception('Specified table does not exist for table ' . $module_database_table_name);
            }

            $definition = $this->tableutility->getDefinitionFromTable($module_database_table_name);
            if (!$definition) {
                throw new \Exception('Parsed table definition is empty for table ' . $module_database_table_name);
            }

            $definition = $this->tableutility->orderFieldsByImportance($definition);
        }
        return $definition;
    }

    /**
     * @param $generate_public_controller
     * @param $directory
     * @param $module_name_lower_case
     * @param $template_base_path
     * @param array $data
     */
    private function generatePublicStuffIfNeccesary($generate_public_controller, $directory, $module_name_lower_case, $template_base_path, array $data)
    {
        if ($generate_public_controller) {
            $this->generatePublicController($directory, $module_name_lower_case, $template_base_path, $data);
            $this->generatePublicIndexView($directory, $template_base_path, $data);
            $this->generatePublicItemView($directory, $template_base_path, $data);
        }
    }

    /**
     * @param $is_crud
     * @param $directory
     * @param $template_base_path
     * @param array $data
     * @param $module_name_lower_case
     */
    private function generateCrudStuffIfNecessary($is_crud, $directory, $template_base_path, array $data, $module_name_lower_case)
    {
        // Making admin controller
        $file_admin_controller = $directory . $this->moduleLocator->getAdminControllerPath($module_name_lower_case);
        if (!file_exists($file_admin_controller)) {
            $this->generateAdminController($is_crud, $template_base_path, $file_admin_controller, $data);
        }

        if (!$is_crud) {
            $this->generateAdminNonCrudAdminView($directory, $template_base_path, $data);
        }
    }

    /**
     * @param $module_name
     * @param $generate_security_policy
     * @param $module_name_singular
     * @throws ReflectionException
     */
    private function generateSecurityPolicyIfNeccesary($module_name, $generate_security_policy, $module_name_singular)
    {
        if ($generate_security_policy) {
            $policy_save_path = SecurityPolicy::getModulePolicyPath($module_name);
            if (!file_exists($policy_save_path)) {
                $this->generateSecurityPolicy($module_name, $module_name_singular, $policy_save_path);
            }
        }
    }

    /**
     * @param $module_name
     * @param $auto_install
     */
    private function doAutoinstallIfNeccesary($module_name, $auto_install)
    {
        if ($auto_install) {
            $this->Module_model->install($module_name, true, false);
            $this->cleanupCache();
        }
    }

    /**
     * @param $directory
     * @param $module_name_lower_case
     * @param $module_name_singular
     * @param $template_base_path
     * @param array $data
     */
    private function generateOrRegenerateModel($directory, $module_name_lower_case, $module_name_singular, $template_base_path, array $data)
    {
        // Building and writing model
        $file_model_path = $directory . $this->moduleLocator->getModelPath($module_name_lower_case, $module_name_singular . '_model');
        if (!file_exists($file_model_path)) {
            file_put_contents($file_model_path, PatternCompiler::compile(file_get_contents($template_base_path . '_model.php'), $data));
        } else {
            $this->regenerateSetAcceptedFieldsForExistingModel($file_model_path, $data);
        }
    }

    /**
     * @param $translations
     * @return array
     */
    private function makeSureTranslationsAreNotEmpty($translations)
    {
        // Setting default translations when no translations are selected
        if (!$translations || count($translations) == 0) {
            return array('polish', 'english');
        }
        return $translations;
    }
}