Your IP : 216.73.216.79


Current Path : /var/www/html/maiwp.bak/console/controllers/
Upload File :
Current File : /var/www/html/maiwp.bak/console/controllers/UserHrmsController.php

<?php

namespace console\controllers;

use Yii;
use yii\console\Controller;
use GuzzleHttp\Client;
use console\models\UserIntegration;
use yii\db\Expression;

/**
 * Sync user with hrms user
 */
class UserHrmsController extends Controller
{   
    /**
     * @property debug
     **/
    const DEBUG_LEVEL = 'ALL';

    /**
     * @property image base path for saving user image
     **/
    const IMAGE_BASE_PATH = '/home/opensoft/www.maiwp.gov.my/www';

    /**
     * @property image path for saving user image
     **/
    const IMAGE_PATH = '/uploads/hrms/';

    /**
     * @property Api base url
     **/
    public string $BASE_URL;

    /**
     * @property Username for api
     **/
    public string $USERNAME;

    /**
     * @property password for api
     **/
    public string $PASSWORD;

    /**
     * @property guzzle client
     **/
    public $client;

    /**
     * @method initialize
     **/
    public function init()
    {
        echo 'INIT--' . PHP_EOL;

        $this->BASE_URL = Yii::$app->params['hrms']['BASE_URL'];

        $this->USERNAME = Yii::$app->params['hrms']['USERNAME'];

        $this->PASSWORD = Yii::$app->params['hrms']['PASSWORD'];

        $this->client = new Client([
            'base_uri' => $this->BASE_URL,
            'timeout'  => 100,
            'request.options' => [
                'exceptions' => false
            ]
        ]);
    }

    /***
     * Main action sync user with hrms api 
     * 
     ***/
    public function actionSyncUserProfile()
    {
        $track = new UserIntegration();

        $track->start = date('Y-m-d H:i:s');

        try {

            $token = $this->logon();

            /*** update all to non active status initialy this will be updated if user is active**/
            $this->updateNStatus();

            $user = $this->grabUser($token);

            $this->syncUser($user, function ($updated, $inserted) use (&$track) {
                $track->updated = $updated;

                $track->inserted = $inserted;
            });

            $track->end = date('Y-m-d H:i:s');

            $track->status = 1;

            $track->save();
        } catch (\Throwable $t) {

            echo 'Error:--------------------------------------------'
                . PHP_EOL
                . $t->getLine() . PHP_EOL
                . $t->getFile() . PHP_EOL
                . $t->getMessage() . PHP_EOL;

            $track->status = 0;

            $track->errors = $t->getFile() . ' | ' . $t->getLine() . ' | ' . $t->getMessage();

            $track->end = date('Y-m-d H:i:s');

            $track->save();
        }
    }

    public function actionStubImageDownload()
    {
        // $this->client->request('GET', '/image', ['sink' => '/var/www/html/maiwp/www/uploads/hrms/' . time() . '.jpg']);
    }

    /***********private**************
     *  Private method section
     * ***/

    /***
     * Logon into api with given credential
     *  
     **/
    private function logon()
    {
        try {

            echo 'TRY LOGON--' . PHP_EOL;

            $res = $this->client->request('POST', "/api/loginDirectory?userId={$this->USERNAME}&password={$this->PASSWORD}",  []);

            $body = json_decode($res->getBody());

            $statuscode = $res->getStatusCode();

            if ($statuscode > 300) {
                throw new \Exception('Cannot connect to api endpoint');
            }

            if (empty($body) or empty($body->token)) {
                throw new \Exception('Cannot decode body from request endpoint');
            }
            
            echo 'SUCESSFULLY LOGON -- ' . $body->token . PHP_EOL;

            return $body->token;
        } catch (\Throwable $t) {
            throw $t;
        }
    }

    /**
     * Grab user, by supplying token
     * @param string $token
     **/
    private function grabUser(string $token)
    {
        try {
            echo 'GRABBING ..USER  --' . PHP_EOL;
            

            $res = $this->client->request('GET', "/api/getListOfStaff",  [
                'headers' => ['Authorization' => 'Bearer ' . $token],
            ]);

            $body = json_decode($res->getBody());

            $statuscode = $res->getStatusCode();

            if ($statuscode > 300) {
                throw new \Exception('Cannot connect to api endpoint');
            }

            if (empty($body) or empty($body->data)) {
                throw new \Exception('Cannot decode body from request endpoint');
            }

            return $body->data;
        } catch (\Throwable $t) {
            throw $t;
        }
    }

    /**
     * Field use for comparison, initialy email was used, but now we are using empno
     **/
    private function keyCompare()
    {
        return 'emel';
    }

    /**
     * Grab user, by supplying token
     * @param object $data user object from api
     * @param callback $track_callback callback for tracking record
     **/
    private function syncUser($data, $track_callback)
    {
        try {
            $record_update = 0;
            $record_insert = 0;
            foreach ($data as $user_row) {

                /** debug **/
                if (self::DEBUG_LEVEL == 'ALL') {
                    // echo  '[' . $user_row->no_pekerja . ']' . PHP_EOL;
                }

                /** extra dept name, this important as directory use a mapping for it department directory**/
                $user_row->nama_bahagian_name = $user_row->nama_bahagian;

                /** new class model instance **/
                $r = new \ReflectionClass($this->modelClassName());

                $instance =  $r->newInstanceWithoutConstructor();

                /** check first if user already exist **/
                $exist_user = $instance->find()->where([
                    'employee_number' => $user_row->no_pekerja,
                ])->one();

                /** if user dont have empno but record exist as email**/
                if (empty($exist_user)) {
                    $exist_email = $instance->find()->where([
                        'employee_email' => $user_row->{$this->keyCompare()}
                    ])->count();

                    /** select email prefix **/
                    preg_match('/.+(?=@)/', $user_row->{$this->keyCompare()}, $match_email);

                    if(is_array($match_email) && count($match_email) > 0)
                        list($email_prefix) = $match_email;

                    
                    // comment after first run
                    // disabled for now as this is only needed for the initial data migration, because there are data inserted without emp no.
                    // if(!empty($exist_email) && $exist_email && strlen($email_prefix) > 2) {
                    //     $exist_user = $instance->find()->where([
                    //         'employee_email' => $user_row->{$this->keyCompare()}
                    //     ])->one();
                    // }
                    
                }

                /** if exist update **/
                if (!empty($exist_user)) {
                    $record_update++;
                    $this->updateUser($exist_user, $user_row);
                } else {
                    $record_insert++;
                    $this->insertUser($user_row);
                }

                if (is_callable($track_callback)) {
                    $track_callback($record_update, $record_insert);
                }
            }
        } catch (\Throwable $t) {
            throw $t;
        }
    }

    /**
     * Update user in db
     **/
    private function updateUser($exist_user, $user_row)
    {
        try {
            $need_update = $this->prepareDataBasedOnMapping($exist_user->toArray(), $user_row);

            /** time tracked **/
            if (!empty($need_update)) {
                $need_update['batch_updated_at'] = time();
                $need_update['updated_at'] = date('Y-m-d H:i:s');
            } else {
                $need_update['batch_checked_at'] = time();
            }

            /** static required field **/
            $need_update['employee_category'] = !empty($exist_user->employee_category) ? (string) $exist_user->employee_category :  '2';

            $exist_user->attributes = $need_update;

            if (!$exist_user->save()) {
                // throw new \Exception("Cannot update user information " . $user_row->no_pekerja . ' | ' . json_encode($exist_user->errors));
            }
        } catch (\Throwable $t) {
            throw $t;
        }
    }


    /**
     * insert user to db
     **/
    private function insertUser($user_row)
    {
        try {
            if (self::DEBUG_LEVEL == 'ALL' || self::DEBUG_LEVEL == 'INSERT') {
                echo  '===================[' . $user_row->no_pekerja . ']==================' . PHP_EOL;
            }

            $create = [];
            
            /** required static property **/
            $create['employee_category'] = '2';
            $create['status_gambar'] = 'OFF';
            $create['employee_status'] = 'N';
            
            foreach ($this->columnMap() as $columnKey => $column_prop) {
                if (isset($user_row->{$columnKey})) {

                    /** sanitize input **/
                    $payload_sanitize = $this->{$column_prop['type']}($user_row->{$columnKey}, $create);

                    /** asign to input **/ 
                    // if jobtitle is not empty skip it
                    if(in_array($columnKey, ['skim_perkhidmatan']) && !empty($column_prop['field'])) {
                    } else {
                        $create[$column_prop['field']] = !empty($payload_sanitize) ? $payload_sanitize : '-';
                    }
                }
            }

            /** create a new instance of model **/
            $r = new \ReflectionClass($this->modelClassName());

            $model = $r->newInstance();

            /** time tracked **/
            $create['batch_created_at'] = time();
            $create['created_at'] = date('Y-m-d');
            $model->attributes = $create;

            if (!$model->save()) {
                throw new \Exception("Cannot create user information " . $user_row->no_pekerja . " | " . json_encode($model->errors));
            }
            if (self::DEBUG_LEVEL == 'ALL' || self::DEBUG_LEVEL == 'INSERT') {
                echo '' . PHP_EOL;
                print_r($create) . PHP_EOL;
                echo '' . PHP_EOL;
            }
        } catch (\Throwable $t) {
            throw $t;
        }
    }

    /**
     * Prepare data for update, match field mapping with every row of user data
     **/
    private function prepareDataBasedOnMapping($existing_user, $user_row)
    {
        $temp_arr = [];

        if (self::DEBUG_LEVEL == 'ALL' || self::DEBUG_LEVEL == 'UPDATE') {
            echo  '===================[' . $user_row->no_pekerja . ']==================' . PHP_EOL;
        }

        $existing_field = "";
        $payload_sanitize = "";
        foreach ($this->columnMap() as $column_key => $column_prop) {
            /** only grab existing field in column mapping **/
            if (
                in_array($column_prop['field'], array_keys($existing_user))
                &&
                !empty($user_row->{$column_key})
            ) {
                
                $existing_field     = $existing_user[$column_prop['field']];

                /** filter base on type **/
                $payload_sanitize   = $this->{$column_prop['type']}($user_row->{$column_key}, $user_row);
                
                if ($existing_field != $payload_sanitize) {

                    if (!empty($payload_sanitize))
                        $temp_arr[$column_prop['field']] = $payload_sanitize;

                    if (self::DEBUG_LEVEL == 'ALL' || self::DEBUG_LEVEL == 'UPDATE') {
                        echo '' . PHP_EOL;
                        echo $column_prop['field'] . PHP_EOL;
                        echo 'Existing :-' . $existing_field . PHP_EOL;
                        echo 'Payload  :-' . $payload_sanitize . PHP_EOL;
                        echo '' . PHP_EOL;
                    }
                }
            }
        }
       
        return $temp_arr;
    }

    /***
     * Column mapping from api, and field form db
     **/
    private function columnMap()
    {
        return [
            "no_pekerja" => [
                "field" => "employee_number",
                "type" => "string"
            ],
            "nama" => [
                "field" => "employee_name",
                "type" => "string"
            ],
            "gelaran_jawatan" => [
                "field" => "job_title",
                "type" => "string"
            ],
            "skim_perkhidmatan" => [
                "field" => "job_title",
                "type" => "jobtitle"
            ],
            "gred_jawatan" => [
                "field" => "job_grade_name",
                "type" => "string"
            ],
            "nama_bahagian" => [
                "field" => "employee_dept",
                "type" => "department"
            ],
            "nama_bahagian_name" => [
                "field" => "employee_dept_name",
                "type" => "string"
            ],
            "nama_unit" => [
                "field" => "employee_unit_name",
                "type" => "string"
            ],
            "kump_perkhidmatan" => [
                "field" => "employee_group_name",
                "type" => "string"
            ],
            "status_perkhidmatan" => [
                "field" => "employee_status",
                "type" => "service_status"
            ],
            "taraf_perkhidmatan" => [
                "field" => "employee_position",
                "type" => "string"
            ],
            "no_pejabat" => [
                "field" => "employee_phone",
                "type" => "string"
            ],
            "path_gambar" => [
                "field" => "employee_image",
                "type" => "image"
            ],
            "emel" => [
                "field" => "employee_email",
                "type" => "string"
            ],
        ];
    }

    /**
     * Class name from content directory
     **/
    private function modelClassName()
    {
        return \console\models\ContentDirectory::class;
    }

    /**
     * String filter
     **/
    private function string($val)
    {
        return filter_var($val, FILTER_SANITIZE_STRING);
    }

    /**
     * Service status filter
     **/
    private function service_status($val)
    {   
        return  $val == 'BERKHIDMAT' ? 'Y' : 'N';
    }


    /**
     * department filter
     **/
    private function department($val)
    {
        $expression = new Expression("LOWER(theme_name) LIKE '%" . trim(strtolower($val)) . "%'");
        $directory = (new \yii\db\Query())
            ->from('directory_release')
            ->orderBy(['sort' => SORT_ASC])
            ->where($expression)
            ->one();
            
            // echo 'DEPARTMENT_VALUE: '  . $val . PHP_EOL;
            // echo 'DEPARTMENT: ' .$directory['theme_id'] . PHP_EOL;

        return !empty($directory) ? strtolower($directory['theme_id']) : '0';
    }

    /**
     * safe filter
     **/
    private function safe($val)
    {
        return;
    }

    /**
     * safe filter
     **/
    private function jobtitle($val, $new)
    {
        if(empty($new->gelaran_jawatan)) {
            if(!empty($new->skim_perkhidmatan))
                return $new->skim_perkhidmatan;
        } else {
            return $new->gelaran_jawatan;
        }
    }

    /**
     * image filter, download the image and return the filename
     **/
    private function image($val)
    {
        try {

            //debug uncomment in production
            // if ($val !== 'http://father-mediawiki.gl.at.ply.gg:6625/images.jpg') {
            //     return;
            // }

            if (!empty($val)) {
                // $path = self::IMAGE_PATH . uniqid() . '.jpg';
                preg_match('/(?:.+\/)(.+)/', $val, $matches);

                list($url, $filename) = $matches;

                $path = self::IMAGE_PATH . $filename;

                /** guzzle **/
                $client = new Client([
                    'base_uri' => $this->BASE_URL,
                    'timeout'  => 1,
                    'verify' => false,
                    'request.options' => [
                        'exceptions' => false
                    ]
                ]);

                // $client->request('GET', $val, ['sink' => self::IMAGE_BASE_PATH . $path]);

                return '..' . $path;
            }
        } catch (\Throwable $t) {
            echo $t->getMessage();
            // throw $t;
        }
    }

    /**
     * Update all record change it status to N, because API Only returns who active and never who's not active
     **/
    private function updateNStatus()
    {
        echo 'UPDATING STATUS TO NON ACTIVE FOR ALL RECORD--' . PHP_EOL;
        
        \Yii::$app->getDb()->createCommand(
            "
            UPDATE content_directory 
                SET employee_status = 'N' 
                WHERE employee_number IS NOT NULL
            "
        )
        ->execute();
    }
}