| Current Path : /var/www/html/maiwp.bak/console/controllers/ |
| 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();
}
}