Structure of an IceHrm Extension

Before diving into development, it’s vital to understand the structure of the extension. The following image shows a list of directories and files inside the extension. Let’s go through each one of these.

kudos.php (Main extension file with the same name as the extension) #

When IceHrm is loaded, all the extensions inside the icehrm/extensions directory are also initialized. During the initialization, a file with the same name as the extension will be loaded. In this case, it is kudos.php. This file is responsible for loading the rest of the code responsible for initializing the extension.

A closer look at kudos.php shows how it is loading different classes required by the extension.

<?php
require_once __DIR__.'/src/Extension.php';
require_once __DIR__.'/src/Controller.php';
require_once __DIR__.'/src/ApiController.php';

// Migrations
require_once __DIR__.'/src/Migrations/CreateTables.php';

Each class being loaded here is important for the extension to work properly. Let’s explore the responsibility of each class.

Extension Manager #

Class Extension defined in src/extension.php is the file that controls the behaviour of the extension. It is responsible for:

  • Loading database models for the ORM used by IceHrm.
  • Defining REST API.
  • Loading the Controller.
  • Loading the dashboard menu for the extension, etc.

Controller #

IceHrm provides a very convenient way to pass data between the front end and backend of the extension. The class Controller defines a set of actions that can be called from the front end.

<?php

namespace KudosAdmin;

use Classes\IceController;
use Classes\IceResponse;

class Controller extends IceController
{
    public function testAction($req): IceResponse
    {
        return new IceResponse(IceResponse::SUCCESS, 'Echo from server: '.$req->data);
    }
}

Invoking these actions can be done via AdminExtensionController class defined in web/js/controller.js file.

handleTestAction() {
    /**
     * The `testAction` should be defined in the `Controller.php` class
     */
    this.handleRequest(
      'testAction',
      { data: 'message from client' },
    ).then((response) => {
      console.log(response);
    });
  }

As you may see above the handleTestAction method is passing some data to the testAction and prints the output to the console.

Rest API #

A Rest API for the extension can be easily defined and exposed using src/ApiController.php. The example methods added in ApiController with the generated code will further show how it can be utilized.

Database Migration #

The file src/Migrations/CreateTables.php defines a sample migration. You are free to create additional migrations and add them to the \KudosAdmin\Extension::initialize method.

e.g:

public function initialize() {
    BaseService::getInstance()->registerExtensionMigration(new CreateTables());
}

Each migration can perform tasks like creating a table or adding data to the database required by the extension. Each migration needs to have a unique name. Here is an example of a migration that creates a table for this extension.

<?php

namespace KudosAdmin\Migrations;

use Classes\Migration\AbstractMigration;
use Classes\Migration\MigrationInterface;

class CreateTables extends AbstractMigration implements MigrationInterface
{
	
	public function getName() {
		return 'kudos_create_table';
	}
	
	public function up() {
        $sql = <<<'SQL'
            create table EmployeeKudos
            (
                id bigint auto_increment primary key,
                employee bigint null,
                sender bigint not null,
                message varchar(500) charset utf8 not null,
                created datetime null,
                updated datetime null,
                CONSTRAINT `Fk_EmployeeKudos_Sender` FOREIGN KEY (`sender`) REFERENCES `Employees` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
                CONSTRAINT `Fk_EmployeeKudos_Employee` FOREIGN KEY (`employee`) REFERENCES `Employees` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
            )
            collate=utf8mb4_unicode_ci;
SQL;
        $this->executeQuery($sql);
	}
	
	public function down() {
        $sql = <<<'SQL'
            DROP TABLE IF EXISTS `EmployeeKudos`; 
SQL;
        return $this->executeQuery($sql);
	}
}

When the extension is loaded, IceHrm core checks if the migration has already been executed. If it is not executed the migration up method will be used to create the EmployeeKudos table.

Creating an ORM Model For EmployeeKudos Table #

In order to access data using php-active-record, you need to create a model class for the table defined in previous sections. These models are defined in src/Common/Model directory and loaded in \KudosAdmin\Extension::setupModuleClassDefinitions.

Models are not auto-generated. So you will need to add this class manually.

// File: src/Common/Model/EmployeeKudos.php
<?php
namespace KudosAdmin\Common\Model;

use Model\BaseModel;

class EmployeeKudos extends BaseModel
{
    public $table = 'EmployeeKudos';
}

Frontend Structure #

IceHrm extension web directory has the following structure:

📦extensions
 ┣ 📂web
   ┣ 📂js
   ┃ ┣ 📜controller.js
   ┃ ┣ 📜index.js
   ┣ ┣ 📜module.js
   ┃ ┗ 📜view.js
   ┗ 📜index.php

The index.php is the entry point for the front end. It defines a <div> element to load the root react component. Also, it calls the init function defined in web/js/index.php to start initializing Module class defined in web/js/module.js.

After IceHrm framework is initialized the showExtensionView function of the module class will be called. This function mounts the react component which you can see here:

empty Kudos Admin extension

Your entry point to build the frontend for the extension is web/js/view.js file which contains a React component which will be used as the main container component.

Tech Stack Used for Extensions #

  • IceHrm extensions use React and Ant Design to build the front end.
  • The backend is developed using PHP.
  • We use the php-active-record for the DB layer.
  • When building frontend components please use Ant Design components to match the UI of the rest of the application. The currently supported ant design version is 4.x.

Powered by BetterDocs