Tag Archive list

Byphunsanit

joGet: Pending Process Activity and Assignees

ต้องการสร้าง List ใน joGet เพิ่อที่จะได้ดูสถานะและเข้าไปดู form ใน process ตามขั้นตอนต่างๆ ใน workflow

ทำได้โดยใช้ความรู้ 2 เรื่องคือ

การใช้ query เพิ่อดู process activity

process ที่กำลังอยู่ระหว่างสถานะต่างๆ จะถูกบันทึกลงใน database สามารถ query มาดูได้โดยใช้ตัวอย่าง เช่น

SELECT
a.*,
sact.Name AS activityName,
GROUP_CONCAT(DISTINCT sass.ResourceId
SEPARATOR ', ') AS assignee
FROM
app_fd_hr_expense_claim a
JOIN
SHKActivities sact ON a.id = sact.ProcessId
JOIN
SHKActivityStates ssta ON ssta.oid = sact.State
INNER JOIN
SHKAssignmentsTable sass ON sact.Id = sass.ActivityId
WHERE
ssta.KeyValue = 'open.not_running.not_started'
GROUP BY a.id

ตามตัวอย่างใน List Pending Activity and Assignees อย่าลืมเปลี่ยนตาราง a เป็นตารางที่ใช้ใน process จริงๆ

การใช้ link ไปยังฟอร์มตาม activity
ลิงค์ของ joget จะอยู่ในรูปแบบ /jw/web/userview/ {app id} / {userview id} /_/ {process_id} ?_action=assignmentView

ตัวอย่าง list ที่เสร็จแล้ว

{"id":"activity_and_assignees","name":"Activity And Assignees","pageSize":"0","order":"","orderBy":"","showPageSizeSelector":"true","pageSizeSelectorOptions":"10,20,30,40,50,100","buttonPosition":"bottomLeft","checkboxPosition":"left","useSession":"false","hidePageSize":"true","description":"","rowActions":[{"name":"Data List Hyperlink Action","className":"org.joget.apps.datalist.lib.HyperlinkDataListAction","label":"Hyperlink","type":"text","id":"rowAction_0","properties":{"href":"\/jw\/web\/userview\/vehicle\/carpark\/_\/car_park_registration?_action=assignmentView","target":"_self","hrefParam":"activityId","hrefColumn":"activityId","label":"Run Process","confirmation":"","visible":"","rules":[]}}],"actions":[],"filters":[],"binder":{"className":"org.joget.plugin.enterprise.JdbcDataListBinder","properties":{"jdbcDatasource":"default","sql":"SELECT \n    a.*,\n    sass.activityId,\n    sact.Name AS activityName,\n    GROUP_CONCAT(DISTINCT sass.ResourceId\n        SEPARATOR ', ') AS assignee\nFROM\n    app_fd_cars AS a\n        JOIN\n    SHKActivities AS sact ON a.id = sact.ProcessId\n        JOIN\n    SHKActivityStates AS ssta ON ssta.oid = sact.State\n        INNER JOIN\n    SHKAssignmentsTable AS sass ON sact.Id = sass.ActivityId\nWHERE\n    ssta.KeyValue = 'open.not_running.not_started'\nGROUP BY a.id","primaryKey":"id"}},"columns":[{"id":"column_0","label":"id","displayLabel":"id","name":"id"},{"id":"column_1","label":"c_licensePlate","displayLabel":"c_licensePlate","name":"c_licensePlate"},{"id":"column_2","label":"c_brand","displayLabel":"c_brand","name":"c_brand"},{"id":"column_3","label":"c_approve","displayLabel":"c_approve","name":"c_approve"},{"id":"column_4","label":"activityName","displayLabel":"activityName","name":"activityName"},{"id":"column_5","label":"assignee","displayLabel":"assignee","name":"assignee"}]}

นอกจากนี้ยังสามารถหาตัวอย่างได้จาก app Process Monitor Utility ได้อีกด้วย

Byphunsanit

PHP: ดูการทำงานสร้าง flowchart (backtrace)

ถ้าเรียนเขียน program มาคงจะคุ้นเคยกับ flowchart การทำงานของของโปรแกรม แต่ในชีวิตการทำงานจริงๆ โดยเฉพาะถ้าเขียน code โดยใช้ framework ต่างๆ จะไม่เป็นเหมือนที่ได้ออกแบบไว้เสมอไป เพราะว่าบางครั้งโปรแกรมจะทำงานให้เราเองโดยที่ไม่ได้สั่ง สาเหตุคือ มีการเรียกใช้ hook หรือ tricker ทำให้เกิด process ที่อาจจะไม่ทราบที่มา หรือต้องมาแก้งานของคนอื่นโดนที่ไม่มีเอกสารให้

นอกจากการใช้วิธี PHP: list included หรือ required ไฟล์ที่ใช้ ถ้าเราใช้ตัว framework ต่างๆ มักจะมีการเตรียม function ในการสร้าง backtrace ไว้ให้ แต่ถ้าไม่มีหรือเป็น code ที่เขียนด้วยตัวเอง ยังสามารถใช้ debug_backtrace ในการค้นหาที่มาที่ไปได้เช่น

<?php

function getBacktrace()
{
    $backtrace = debug_backtrace();
    echo '<pre>', print_r($backtrace, true), '</pre>';
    fwrite(fopen('logs_debug_backtrace.txt', 'a+'), "\n\n" . __FILE__ . ' :' . __LINE__ . "\n\n" . print_r($backtrace, true));
}

function getPhpInfo($what)
{
    phpinfo($what);

    /* จะดูว่า ทำไม่ getPhpInfo ถึงทำงาน */
    getBacktrace();
}

function index()
{
    getPhpInfo(INFO_ENVIRONMENT);
}

index();

เมื่อทดสอบดูจะได้ผลลัพธ์

Array
(
    [0] => Array
        (
            [file] => D:\xampp\htdocs\snippets\PHP\debug.debug_backtrace.php
            [line] => 13
            [function] => getBacktrace
            [args] => Array
                (
                )

        )

    [1] => Array
        (
            [file] => D:\xampp\htdocs\snippets\PHP\debug.debug_backtrace.php
            [line] => 18
            [function] => getPhpInfo
            [args] => Array
                (
                    [0] => 16
                )

        )

    [2] => Array
        (
            [file] => D:\xampp\htdocs\snippets\PHP\debug.debug_backtrace.php
            [line] => 21
            [function] => index
            [args] => Array
                (
                )

        )

)

เพราะว่าเราเขียน function debug_backtrace() ไว้ใน function getBacktrace() อีกชั้น เพื่อที่ความง่ายในการค้นหา flow เมื่อต้องการดูว่า function หรือ class ที่เราสนใจมันมี flow มายังไงก็แค่ไปเรียกใน function ที่สงสัย เราก็จะได้ลำดับการทำงานย้อนกลับไป เราจะได้ทราบทั้งฟังก์ชั้น คลาส บรรทัด ไฟล์ แม้แต่ตัวแปรที่ส่งเข้าไปใน function นั้นๆ

Byphunsanit

PHP: list included หรือ required ไฟล์ที่ใช้

การเขียนโปรแกรมโดยใช้ php นิยมจะแยกไฟล์ออกเป็นส่วนๆ เพื่อความสะดวกในการเขียนและ reused ไฟล์เพื่อที่จะนำมาใช้ซ้ำอีกครั้ง เช่น ในเว็บทั่วไปมันจะมีส่วนของ header และ footer เหมือนกันทุกๆหน้า แทนนี้จะเขียนส่วนหัวและส่วนท้ายทุกครั้ง สำหรับทุกหน้าเพื่อแสดงผลเหมือนๆ กันก็จะนิยมสร้างเป็นไฟล์ แยกออกไป จากนั้นก็แทรกเข้ามาโดยใช้ function included หรือ required

<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title><?php echo $title; ?></title>
</head>
<body>

และ

</body>
</html>

ถ้าหากต้องมีการเปลี่ยน design ก็สามารถแก้ได้โดยแก้ใน 2 ไฟล์นี้เท่านั้นแทนที่จะต้องไปไล่เปลี่ยนในทุกๆไฟล์ (มีแค่ 100 หน้าก็เหนื่อยแล้ว)

แต่เมื่อโครงสร้างไฟล์ใน project เริ่มมีความซับซ้อน เช่น ไม่ทราบว่าไฟล์ที่เราใช้คำสั่ง included หรือ required นั้นมีไฟล์ไหนบ้าง เพราะว่าไฟล์ที่ include เข้ามาสามารถแทรกไฟล์ส่วนอื่นๆ เข้ามาเพิ่มได้เหมือนกันเช่น header.php อาจจะมีการแทรกไฟล์ menu.php เพื่อแสดงส่วนของเมนู ภาษาพีเฮชพีจึงได้เตรียม function get_included_files เข้ามาช่วย debug ไฟล์ทั้งหมดที่แทรกเอาเข้ามา

ตัวอย่างการใช้งาน

<?php
$title = 'names of included or required files';
include 'header.php';

function getIncludedFiles()
{
    $files = get_included_files();
    echo '<pre>', print_r($files, true), '</pre>';
    fwrite(fopen('logs_get_included_files.txt', 'a+'), "\n\n" . __FILE__ . ' :' . __LINE__ . "\n\n" . print_r($files, true));

}

getIncludedFiles();

include 'footer.php';

ทดลองเรียกดู จะเห็นว่าจะแสดงเป็น array

Array
(
    [0] => D:\xampp\htdocs\snippets\PHP\get_included_files.php
    [1] => D:\xampp\htdocs\snippets\PHP\header.php
)

สังเกตดูจะเป็นว่าจะแสดง array ออกมาและเขียนไฟล์ logs_get_included_files.txt เพิ่มขึ้นมา โดยเริ่มจากไฟล์ debug.get_included_files.php เองและแสดงไฟล์ header.php ที่แทรกเข้ามา แต่กลับไม่แสดง footer.php เพราะว่าแทรกเข้ามาหลัง function get_included_files() ในการใช้งานจริงๆ จึงควรแทรกไว้ที่ลำดับการทำงานสุดท้ายเช่นไฟล์ footer.php จึงจะสามารถ list ไฟล์ที่ใช้ได้ครบ

นอกจากนี้ยังสามารถเขียนให้จบในบรรทัดเดียวได้

fwrite(fopen('get_included_files.txt', 'a+'), print_r(get_included_files(), true));

Byphunsanit

ใส่ฟิลเตอร์ให้ select box

select box (drop down/ dropdown / ดรอปดาวน์ / list / ลิสต์ หลายชื่อเหลือกเกิน) นิยมใช้เวลาต้องการให้ user เลือกจากตัวเลือกที่กำหนดให้เท่านั้น แต่ถ้ามันมีเยอะมาก อย่าง 77 จังหวัด ถ้าต้องเลือกบ่อยๆ ก็ไม่สดวกที่จะต้องไล่หา แก้ได้โดยใช้ jQuery ใส่ filter ให้

ดูตัวอย่างการทำงานได้ที่

ตัวอย่าง Demo -> =>

  1. download jQuery.chosen มาจาก harvesthq Chosen แตกไฟล์
  2. ใส่ code ง่ายๆ ตามตัวอย่าง
    <!doctype html>
    <html>
    <head>
    <meta charset="utf-8">
    <title>jQuery Chosen Demo By Pitt Phunsanit</title>
    <link href="chosen/chosen.min.css" rel="stylesheet" type="text/css">
    </head>
    <body>
    <select id="province" style="width:200px;">
    	<option value="64">กระบี่</option>
    	<option value="1">กรุงเทพมหานคร</option>
    	<option value="56">กาญจนบุรี</option>
    	<option value="34">กาฬสินธุ์</option>
    	<option value="49">กำแพงเพชร</option>
    	<option value="28">ขอนแก่น</option>
    	<option value="13">จันทบุรี</option>
    	<option value="15">ฉะเชิงเทรา</option>
    	<option value="11">ชลบุรี</option>
    	<option value="9">ชัยนาท</option>
    	<option value="25">ชัยภูมิ</option>
    	<option value="69">ชุมพร</option>
    	<option value="45">เชียงราย</option>
    	<option value="38">เชียงใหม่</option>
    	<option value="72">ตรัง</option>
    	<option value="14">ตราด</option>
    	<option value="50">ตาก</option>
    	<option value="17">นครนายก</option>
    	<option value="58">นครปฐม</option>
    	<option value="36">นครพนม</option>
    	<option value="19">นครราชสีมา</option>
    	<option value="63">นครศรีธรรมราช</option>
    	<option value="47">นครสวรรค์</option>
    	<option value="3">นนทบุรี</option>
    	<option value="76">นราธิวาส</option>
    	<option value="43">น่าน</option>
    	<option value="77">บึงกาฬ</option>
    	<option value="20">บุรีรัมย์</option>
    	<option value="4">ปทุมธานี</option>
    	<option value="62">ประจวบคีรีขันธ์</option>
    	<option value="16">ปราจีนบุรี</option>
    	<option value="74">ปัตตานี</option>
    	<option value="5">พระนครศรีอยุธยา</option>
    	<option value="44">พะเยา</option>
    	<option value="65">พังงา</option>
    	<option value="73">พัทลุง</option>
    	<option value="53">พิจิตร</option>
    	<option value="52">พิษณุโลก</option>
    	<option value="61">เพชรบุรี</option>
    	<option value="54">เพชรบูรณ์</option>
    	<option value="42">แพร่</option>
    	<option value="66">ภูเก็ต</option>
    	<option value="32">มหาสารคาม</option>
    	<option value="37">มุกดาหาร</option>
    	<option value="46">แม่ฮ่องสอน</option>
    	<option value="24">ยโสธร</option>
    	<option value="75">ยะลา</option>
    	<option value="33">ร้อยเอ็ด</option>
    	<option value="68">ระนอง</option>
    	<option value="12">ระยอง</option>
    	<option value="55">ราชบุรี</option>
    	<option value="7">ลพบุรี</option>
    	<option value="40">ลำปาง</option>
    	<option value="39">ลำพูน</option>
    	<option value="30">เลย</option>
    	<option value="22">ศรีสะเกษ</option>
    	<option value="35">สกลนคร</option>
    	<option value="70">สงขลา</option>
    	<option value="71">สตูล</option>
    	<option value="2">สมุทรปราการ</option>
    	<option value="60">สมุทรสงคราม</option>
    	<option value="59">สมุทรสาคร</option>
    	<option value="18">สระแก้ว</option>
    	<option value="10">สระบุรี</option>
    	<option value="8">สิงห์บุรี</option>
    	<option value="51">สุโขทัย</option>
    	<option value="57">สุพรรณบุรี</option>
    	<option value="67">สุราษฎร์ธานี</option>
    	<option value="21">สุรินทร์</option>
    	<option value="31">หนองคาย</option>
    	<option value="27">หนองบัวลำภู</option>
    	<option value="6">อ่างทอง</option>
    	<option value="26">อำนาจเจริญ</option>
    	<option value="29">อุดรธานี</option>
    	<option value="41">อุตรดิตถ์</option>
    	<option value="48">อุทัยธานี</option>
    	<option value="23">อุบลราชธานี</option>
    </select>
    <script src="../jQuery/jquery-2.1.3.min.js"></script><!-- เรียกใช้ jQuery -->
    <script src="chosen/chosen.jquery.min.js"></script><!-- เรียกใช้ jQuery plugin -->
    <script>
    $(function(){
    
    	$('#province').chosen(); <!-- เรียกใช้ jQuery plugin chosen กับ id province-->
    
    })
    </script>
    </body>
    </html>
    
  3. ใช้ได้แล้ว