Codeigniter 4 Installation

Below you will find the steps to install Grocery CRUD Enterprise on Codeigniter 4. If you follow these steps carefully, you should be able to successfully install Grocery CRUD Enterprise on your Codeigniter project easily. Keep in mind that this tutorial may require several steps, but it is actively updated to provide the most accurate and up-to-date instructions.

Instead of relying solely on this tutorial, we'd like to draw your attention to the availability of a helpful wizard specially designed to streamline the installation process of Grocery CRUD Enterprise for your specific project πŸš€. This wizard provides a concise, step-by-step tutorial with five easy-to-follow instructions. To access this tool, simply click on the following link: Grocery CRUD Enterprise Installation Wizard. Users are already using it, and their feedback has been overwhelmingly positive ❀️. Enjoy!

Table of Contents

Since currently Codeigniter 4 is suggested to be installed via Composer, we will follow the same approach. If you would like to install Grocery CRUD Enterprise on Codeigniter 4 without composer you can follow this tutorial: Install without composer

Notice: Grocery CRUD Enterprise is a framework-agnostic library. That simply means that it doesn't matter which framework you are using, and it doesn't matter which architecture or tools (e.g. composer) you are using. This tutorial is taking some architecture decisions basically for you. If you need to have the full freedom of what structure to choose, we are suggesting to see the full installation guide here.

Considering that you've already had a composer.json file into your project, run the following command:

composer config repositories.grocery-crud '{"type": "composer", "url": "https://composer.grocerycrud.com/"}' --file composer.json

If the above code succeeds, your composer.json file will look like this:

{
    "name": "codeigniter4/appstarter",
    "type": "project",
    "description": "CodeIgniter4 starter app",
    "homepage": "https://codeigniter.com",
    "license": "MIT",
    "require": {
        "php": "^7.4 || ^8.0",
        "codeigniter4/framework": "^4.0"
    },
    "require-dev": {
        "fakerphp/faker": "^1.9",
        "mikey179/vfsstream": "^1.6",
        "phpunit/phpunit": "^9.1"
    },
    "suggest": {
        "ext-fileinfo": "Improves mime type detection for files"
    },
    "autoload": {
        "exclude-from-classmap": [
            "**/Database/Migrations/**"
        ]
    },
    "autoload-dev": {
        "psr-4": {
            "Tests\\Support\\": "tests/_support"
        }
    },
    "scripts": {
        "test": "phpunit"
    },
    "support": {
        "forum": "http://forum.codeigniter.com/",
        "source": "https://github.com/codeigniter4/CodeIgniter4",
        "slack": "https://codeigniterchat.slack.com"
    },
    "repositories": {
        "grocery-crud": {
            "type": "composer",
            "url": "https://composer.grocerycrud.com/"
        }
    }
}

If the command fails for any reason don't worry too much! You can always copy the section "repositories" from the above code and paste it in your composer.json.

Now you can install the library with the following command:

composer require "grocery-crud/enterprise:^3.1" --prefer-dist

The first time you run the above command, you'll be asked to provide your username and password for the composer package grocery-crud/enterprise. Your username is your email address and your password is the license key for Grocery CRUD Enterprise. You can find your credentials in the My Profile page at the top right avatar icon of user's page.

After entering the correct username and password in the command line, you'll be asked if you want to store your credentials in the auth.json file. I recommend answering Y (yes) to this question, so you won't have to provide the credentials again in the future.

If the command succeeds, you will see something like this:

Installing grocery-crud/enterprise

Now theoretically you've just installed Grocery CRUD. However, there are few more steps in order to make it work.

As Grocery CRUD is a CRUD Generator that also has CSS and JavaScript files we need to make sure that we also have the public assets including in our public folder.

In order to install all your assets to your project. You need to manually copy the content of the folder public to your Codeigniter public folder. More specifically go to : vendor/grocery-crud/enterprise/public and copy the folder vendor to your Codeigniter public folder. For example after the copy of the folder your folder structure will look like this:

β”œβ”€β”€ app
β”œβ”€β”€ public
β”‚   └── vendor
β”‚       └── grocery-crud
β”‚           β”œβ”€β”€ css
β”‚           β”œβ”€β”€ icons
β”‚           β”œβ”€β”€ js
β”‚           └── static
...
β”œβ”€β”€ composer.json
β”œβ”€β”€ composer.lock
β”œβ”€β”€ preload.php
└── vendor

We did currently install Grocery CRUD Enterprise in our project, and we need to create our configuration files in order to make it work! Go to app/Config and create a file with name GroceryCrudEnterprise.php. As the configuration is different than other frameworks we will use a custom one that will look like this (just copy really the code below)

<?php namespace Config;

use CodeIgniter\Config\BaseConfig;

class GroceryCrudEnterprise extends BaseConfig
{
    public function getDefaultConfig() {
        helper('url');

        return [
            // So far 34 languages including: Afrikaans, Arabic, Bengali, Bulgarian, Catalan, Chinese, Czech, Danish,
            // Dutch, English, French, German, Greek, Hindi, Hungarian, Indonesian, Italian, Japanese, Korean,
            // Lithuanian, Mongolian, Norwegian, Persian, Polish, Portuguese, Brazilian Portuguese, Romanian,
            // Russian, Slovak, Spanish, Thai, Turkish, Ukrainian, Vietnamese
            'default_language'  => 'English',

            // This is the assets folder where all the JavaScript, CSS, images and font files are located
            'assets_folder' => base_url() . '/vendor/grocery-crud/',

            // The default per page when a user firstly see a list page
            'default_per_page'  => 10,

            // Having some options at the list paging. This is the default one that all the websites are using.
            // Make sure that the number of grocery_crud_default_per_page variable is included to this array.
            'paging_options' => ['10', '25', '50', '100'],

            // The environment is important, so we can have specific configurations for specific environments
            'environment' => 'development',

            // Currently you can choose between 'bootstrap-v3', 'bootstrap-v4' and 'bootstrap-v5'
            'theme' => 'bootstrap-v5',

            // Automatically cleans all the inputs by trimming strings and by completely removing any HTML tag
            // to prevent XSS attacks. This is a global configuration for all the inputs so be aware in case you
            // switch this to true
            'xss_clean' => false,

            // The character limiter at the datagrid columns, zero(0) value if you don't want any character
            // limitation to the column
            'column_character_limiter' => 50,

            // The allowed file types on upload. If the file extension doesn't exist in the array
            // it will throw an error and the upload will not be completed
            'upload_allowed_file_types' =>  [
                'gif', 'jpeg', 'jpg', 'png', 'svg', 'tiff', 'doc', 'docx',  'rtf', 'txt', 'odt', 'xls', 'xlsx', 'pdf',
                'ppt', 'pptx', 'pps', 'ppsx', 'mp3', 'm4a', 'ogg', 'wav', 'mp4', 'm4v', 'mov', 'wmv', 'flv', 'avi',
                'mpg', 'ogv', '3gp', '3g2'
            ],

            // Set this variable to true if you want to remove the file from the server
            // when a row is deleted. The file will also be removed when the user is
            // removing the file from the upload field.
            // By default, the file is not deleted from the server in these cases.
            'remove_file_on_delete' => false,

            // Show image preview - As we currently don't have thumbnails to show please keep in mind that the full
            // image will be loaded in the browser.
            'show_image_preview' => false,

            // If open_in_modal is true then all the form operations (e.g. add, edit, clone... e.t.c.) will
            // open within a modal and we will have the datagrid on the background.
            // In case you would like however to have a standalone page for all the form operations change this to false.
            'open_in_modal' => true,

            // Have url history for the CRUD forms, so it will be easier for the user
            // to navigate back to the previous form page. For example /add, /edit/11, /clone/22, ... e.t.c.
            'url_history' => true,

            // The button style that we have for the action buttons at the datagrid (list) page
            // Choose between 'icon', 'text', 'icon-text'
            'action_button_type' => 'icon-text',

            // The maximum number of buttons that we would like to have for the actions buttons.
            // If the number of buttons exceeds this number then the last button on the right
            // is going to change into a "More" dropdown button.
            // If the maximum number is 1 then as we only have one button as a dropdown list the translation
            // is "Actions" rather than "More"
            'max_action_buttons' => [
                'mobile' => 1,
                'desktop' => 2
            ],

            // Choose between 'left' or 'right'
            'actions_column_side' => 'left',

            // We have noticed that especially after using setRelation within a table that had more than 10K rows
            // that the datagrid was getting slower. For that reason we have optimized SQL wherever possible, and we
            // also have disabled the ordering for setRelation fields.  Keep in mind that the optimization of the queries
            // can be up to 20x faster!! Especially in big tables (e.g. with 1 million rows).
            // In case you would like though to use the ordering for the setRelation field, and you don't have big tables
            // you can set this to `false` and you will probably not notice any difference
            'optimize_sql_queries' => false,

            // Publish external events to the frontend (e.g. when the user clicks at the edit button)
            // For security reasons the configuration is set to false by default.
            'publish_events' => false,

            // Remember the sorting, the search and the paging upon refresh. The information is stored in the browser local storage
            'remember_state_upon_refresh' => true,

            // Remember the filters upon refresh. The information is stored in the browser local storage
            // Please note that if you have remember_state_upon_refresh set to false then this configuration
            // will also be set to false.
            'remember_filters_upon_refresh' => true,

            // Include JavaScript files in the main output and don't return them at 'js_files' variable
            // This is useful for quicker installations/demos, but it is recommended to set this to false
            // and have all of your JavaScript files at the bottom of your page before the body tag ends.
            // Please consider that when JavaScript files are included directly in the output, you lose the ability
            // to control when and where these files are loaded.
            'display_js_files_in_output' => false,
        ];
    }
}
In order to confirm that so far you did copy the correct files, your folder structure will look something like this:
.
β”œβ”€β”€ LICENSE
β”œβ”€β”€ README.md
β”œβ”€β”€ app
β”‚   β”œβ”€β”€ Common.php
β”‚   β”œβ”€β”€ Config
β”‚   β”‚   β”œβ”€β”€ App.php
β”‚   β”‚   β”œβ”€β”€ Autoload.php
β”‚   β”‚   β”œβ”€β”€ ...
β”‚   β”‚   β”œβ”€β”€ Format.php
β”‚   β”‚   β”œβ”€β”€ GroceryCrudEnterprise.php
β”‚   β”‚   β”œβ”€β”€ Honeypot.php
β”‚   β”‚   β”œβ”€β”€ ...
β”‚   β”‚   └── View.php
β”‚   β”œβ”€β”€ Filters
β”‚   β”œβ”€β”€ Helpers
β”‚   β”œβ”€β”€ Language
β”‚   β”œβ”€β”€ Models
β”‚   β”œβ”€β”€ ThirdParty
β”‚   β”œβ”€β”€ Views
β”‚   └── index.html
β”œβ”€β”€ composer.json
β”œβ”€β”€ contributing.md
β”œβ”€β”€ env
β”œβ”€β”€ license.txt
β”œβ”€β”€ phpunit.xml.dist
β”œβ”€β”€ public
β”‚   └── vendor
β”‚       └── grocery-crud
β”‚           β”œβ”€β”€ css
β”‚           β”œβ”€β”€ icons
β”‚           β”œβ”€β”€ js
β”‚           └── static
β”‚   β”œβ”€β”€ favicon.ico
β”‚   β”œβ”€β”€ index.php
β”‚   └── robots.txt
β”œβ”€β”€ spark
β”œβ”€β”€ system
β”œβ”€β”€ vendor
β”œβ”€β”€ tests
└── writable

Now you are ready basically to use grocery CRUD Enterprise. You only need some small modifications. The easiest way to create two private methods to your controller that it will look like this:

<?php namespace App\Controllers;

// Add those two lines at the beginning of your controller
include(APPPATH . 'Libraries/GroceryCrudEnterprise/autoload.php');
use GroceryCrud\Core\GroceryCrud;

...

private function _getDbData() {
    $db = (new \Config\Database())->default;
          return [
              'adapter' => [
              'driver' => 'Pdo_Mysql',
              'host'Β  Β  Β => $db['hostname'],
              'database' => $db['database'],
              'username' => $db['username'],
              'password' => $db['password'],
              'charset' => 'utf8'
          ]
    ];
}
private function _getGroceryCrudEnterprise($bootstrap = true, $jquery = true) {
        $db = $this->_getDbData();
        $config = (new \Config\GroceryCrudEnterprise())->getDefaultConfig();

        $groceryCrud = new GroceryCrud($config, $db);

        $groceryCrud->setCsrfTokenName(csrf_token());
        $groceryCrud->setCsrfTokenValue(csrf_hash());

        return $groceryCrud;
}

And now when you want to use groceryCRUD enterprise you will simply do this:

// Your function at your controller
public function customers()
{
    $crud = $this->_getGroceryCrudEnterprise();
    $crud->setTable('customers');
    $crud->setSubject('Customer', 'Customers');

    $output = $crud->render();

    return $this->_example_output($output);
}

private function _example_output($output = null) {
    if (isset($output->isJSONResponse) && $output->isJSONResponse) {
                header('Content-Type: application/json; charset=utf-8');
                echo $output->output;
                exit;
    }

    return view('example.php', (array)$output);
}

A full working example of a controller with name Example located at app/Controllers/Example.php can be found here:

<?php
namespace App\Controllers;

include(APPPATH . 'Libraries/GroceryCrudEnterprise/autoload.php');
use GroceryCrud\Core\GroceryCrud;

class Example extends BaseController
{
    public function index() 
    {
        $output = (object)[
            'js_files' => [],
            'output' => ''
        ];

        return $this->_example_output($output);
    }
    public function customers()
    {
        $crud = $this->_getGroceryCrudEnterprise();

        $crud->setTable('customers');
        $crud->setSubject('Customer', 'Customers');

        $output = $crud->render();

        return $this->_example_output($output);
    }

    private function _example_output($output = null) {
        if (isset($output->isJSONResponse) && $output->isJSONResponse) {
                    header('Content-Type: application/json; charset=utf-8');
                    echo $output->output;
                    exit;
        }

        return view('example.php', (array)$output);
    }

    private function _getDbData() {
        $db = (new \Config\Database())->default;
        return [
            'adapter' => [
                'driver' => 'Pdo_Mysql',
                'host'     => $db['hostname'],
                'database' => $db['database'],
                'username' => $db['username'],
                'password' => $db['password'],
                'charset' => 'utf8'
            ]
        ];
    }
    private function _getGroceryCrudEnterprise($bootstrap = true, $jquery = true) {
        $db = $this->_getDbData();
        $config = (new \Config\GroceryCrudEnterprise())->getDefaultConfig();

        $groceryCrud = new GroceryCrud($config, $db);

        $groceryCrud->setCsrfTokenName(csrf_token());
        $groceryCrud->setCsrfTokenValue(csrf_hash());

        return $groceryCrud;
    }
}

Go to app/Views and create a file with name example.php and it is the exact same view that we were using as an example at Community edition. More specifically the view example.php will contain the below code:

<!DOCTYPE html>
<html lang="en">
<head>
 <meta charset="utf-8" />

<?php foreach($js_files as $file): ?>

 <script src="<?php echo $file; ?>"></script>
<?php endforeach; ?>

<style type='text/css'>
body
{
 font-family: Arial;
 font-size: 14px;
}
</style>
</head>
<body>
<!-- Beginning header -->
 <div>
     <a href='<?php echo site_url('example/customers')?>'>Customers</a>
 </div>
<!-- End of header-->

 <!-- Beginning of main content -->
 <div style='height:20px;'></div> 
 <div style='padding: 10px;'>
     <?php echo $output; ?>

 </div>
 <!-- End of main content -->

<!-- Beginning footer -->

<!-- End of Footer -->
</body>
</html>

Since Codeigniter 4.2.0 or later the Routing is not defaulting to auto-routing. This means that you will need to add the routes manually. Go to app/Config/Routes.php and add the below code for every function that is using grocery CRUD:

// Make sure that you always add both lines for each CRUD function
$routes->add('/example/customers', 'Example::customers');
$routes->add('/example/customers/(:segment)(/(:segment))?', 'Example::customers/$1/$2');

1. Getting the message "Ooooops, something went wrong!" The most common mistake of the installation of grocery CRUD Enteprise is when the assets_folder has a wrong path.Β If you did follow all the steps and you see that your webpage looks like that:

wrong-codeigniter-installation

then make sure that you have configured your app/Config/App.php file atΒ the line public $baseURL = 'http://localhost:8080';. For example if your project URL looks like this: http://localhost/my-test-project/public/index.php then your baseURL should look like this: public $baseURL = 'http://localhost/my-test-project/public/';

It is really important to also don't forget the trailing slash at the end of the URL.

The most common approach, best for security and suggested way of Codeigniter 4 installation is to configure your URL to point directly to your public folder. For example for apache virtual hosts you will probably have an apache configuration that is looking like this:

<VirtualHost *:80>
    DocumentRoot "/var/www/my-test-project/public"
    ServerName my-test-project.local
    ServerAlias www.my-test-project.local
</VirtualHost>

At the above example your $baseURL should look like this:

public $baseURL = 'http://my-test-project.local/';

Too lazy to read the documentation? We have also created a video tutorial for that: Troubleshooting Grocery CRUD Enteprise part 1.

2. Getting an empty box with a border If you are getting an empty box with a border that is looking like this:

wrong-codeigniter-installation

This is because by default Codeigniter 4 has as CI_ENVIRONMENT=production in simple words Codeigniter is trying to hide all of the errors by default and you will not get any errors. You can bypass that by renaming the env that you have at the root to .env and uncomment the below line:

# CI_ENVIRONMENT = production

And replace it with:

CI_ENVIRONMENT = development

If you are using Google Chrome press right click "Inspect Element" and then go to the Network tab and check where the response is red (or else it returns header 500). Once you click on the URL you can see the error as per below screenshot:

inspect-error

You can also press right click "Open in new Tab" to see the error at full screen rather than the "Preview" tab.

For example in our case we've forgotten to change the default database credentials to our ones. So by going to .env file and uncommenting this lines:

# database.default.hostname = localhost
# database.default.database = ci4
# database.default.username = root
# database.default.password = root
# database.default.DBDriver = MySQLi

to your specific database credentials everything is just working smoothly.