Tag Archive Template

PowerBuilder: Target ( Template Application )

วิธีสร้าง target application จาก template

  1. เปิด workspace ที่ต้องการขึ้นมาเช่น งานชิ้นใหม่ก็เปิดจาก development.pbw
  2. คลิก file
  3. คลิก Open..
  4. Browse ไปไฟล์ *.pbw ที่ต้องการ
  5. คลิก OK
  6. คลิก file
  7. คลิก New…
  8. ที่เท็บ Target เลือก Template Application
  9. คลิก OK
  10. หน้า About the Template Application Wizard
  11. คลิก Next >
  12. หน้า What you will do
  13. คลิก Next >
  14. หน้า Specify New Application and Library
    • Application Name: ใส่ชื่อ เช่น prototype_pb8
    • Library: ใส่ชื่อ Library ตัวหลักเช่น C:\UsersDatas\ProjectsGit\PrototypesPowerBuilder8\Source code\main.pb
    • Target: เช่น C:\UsersDatas\ProjectsGit\PrototypesPowerBuilder8\Source code\prototype_pb8.pb
  15. หน้า Specify Template Type เลือกชนิดของ application ที่ต้องการ
    • MDI Application with Microhelp
    • SDI Application
    • PFC-base application
  16. เลือก MDI
  17. คลิก Next >
  18. หน้า Adjust Application Library Search Path
  19. คลิก Next >
  20. หน้า Name MDI Frame and Menu
    • MDI Frame: ใส่ชื่อ เช่น w_main
    • MDI Frame Menu: เช่น m_main
  21. คลิก Next >
  22. หน้า Name MDI Base Sheet, Menu and Service
    • Base Sheet Window: เช่น w_basesheet
    • Sheet Menu: เช่น m_sheet
    • Sheet Manager Service: เช่น n_sheetmanager
  23. คลิก Next >
  24. หน้า Name individual Sheets
    • Sheet 1: เช่น w_sheet1
    • Sheet 2: เช่น w_sheet2
    • Sheet 3: เช่น w_sheet3
  25. คลิก Next >
  26. หน้า Assign Display Name to Sheets
    • W_sheet1 Title (1) : เช่น Untitled for Sheet 1
    • W_sheet2 Title (2) : เช่น Untitled for Sheet 2
    • W_sheet3 Title (3) : เช่น Untitled for Sheet 3
  27. คลิก Next >
  28. หน้า Name About Box and Toolbar Window
    • About Window: เช่น w_about
    • Toolbar Window: เช่น w_toolbars
  29. คลิก Next >
  30. หน้า Specify Connectivity
    • Requires SQL Database connection
    • Requires EAServer connection
    • None
  31. เลือก Requires SQL Database connection
  32. คลิก Next >
  33. หน้า Choose Database Profile
    • เลือก database ที่ต้องการ
  34. หน้า Specify Connectivity Source Info
    • Application INI file คือเก็บไว้ในไฟล์ .ini
    • Registry Settings ฝากไว้ในความจำของ windows
    • Script
    • Connection Service Object: เก็บไว้ในชื่อ เช่น n_connectservice
  35. คลิก Next >
  36. หน้า Name Application INI File
    • Application INI File: เช่น C:\UsersDatas\ProjectsGit\PrototypesPowerBuilder8\Source code\main.ini
  37. คลิก Next >
  38. หน้า Create Project?
    • No. create project later
    • Yes, Create project now
  39. เลือก Yes ซิจะได้ไปต่อ
  40. คลิก Next >
  41. หน้า Specify Project Object
    • Project: เช่น p_prototype_pb8_exe
  42. คลิก Next >
  43. Specify Executable and Resource Files
    • Executable File Name เช่น C:\UsersDatas\ProjectsGit\PrototypesPowerBuilder8\Source code\prototype_pb8.exe
    • Option Resource File (.pbr) เว้นไว้ก่อน
  44. คลิก Next >
  45. Specify Build Options จากจุดนนี้ไปทำเหมือนตอน build เอา

PHPWord: กรอกข้อมูลใส่ template

เพราะว่า word นั้นมีความสามารถปรับแต่งรูปแบบได้ซับซ้อนมากกว่า excel อยู่มาก อย่างน้อยแค่ตำแหน่งของส่วนต่างๆ ในแบบฟอร์มก็มีมากกว่า excel ที่เลือกตำแหน่งได้แค่ว่าจะใส่ column / row ไหน

การใช้ PHP สร้างไฟล์ word ขึ้นมาการสร้างไฟล์แม่แบบขึ้นก่อน โดยการสร้างตัว word template ขึ้นมาก่อนโดยใช้โปรแกรม Microsoft Word สร้างเอกสารไปตามปกติ จึงง่ายกว่า จากนั้นก็แก้เพียงแต่ในส่วนที่่ต้องการจะแทนค่าให้ใส่ ${key name} ลงไป (ระวังเรื่องช่องว่างด้วยนะครับ) หรือส่วนที่ต้องการ repeat ก็เพิ่ม ${key name} … ${/key name} เข้าไปเท่านั้นจะง่ายกว่า ไฟล์ในตัวอย่างนี้สามารถโหลดได้จาก template.docx

จากนั้นก็เขียน code

<?php
ini_set('max_execution_time', 0);
ini_set('memory_limit', '-1');

include '../vendor/autoload.php';

use PhpOffice\PhpWord;

$title = 'Template Render ' . date('Y-m-d H:i:s');

/* load template */
$templateProcessor = new \PhpOffice\PhpWord\TemplateProcessor('template.docx');

/* fill data */
$templateProcessor->setValue('header', $title);

/* random data */
$scores = [];
for ($a = 0; $a < 10; $a++) {
    $scores[$a + 1] = rand(0, 100);
}

/* clone table row and fill */
$templateProcessor->cloneRow('student_id', count($scores));
foreach ($scores as $key => $value) {
    $templateProcessor->setValue('score#' . $key, htmlspecialchars($value, ENT_COMPAT, 'UTF-8'));
    $templateProcessor->setValue('student_id#' . $key, htmlspecialchars($key, ENT_COMPAT, 'UTF-8'));
}

/* clone all block */
$templateProcessor->cloneBlock('repeater', 5);

header("Content-Description: File Transfer");
header('Content-Disposition: attachment; filename="' . $title . '.docx"');
header('Content-Type: application/vnd.openxmlformats-officedocument.wordprocessingml.document');
header('Content-Transfer-Encoding: binary');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Expires: 0');
$templateProcessor->saveAs('php://output');

อธิบาย code

  • การทำงานโดยจะโหลด ตัว PHPWord มาใช้ก่อน จะสังเกตุว่าจะมีการใช้ namespaces แทนที่จะใช้ include เข้ามาเหมือน PHPExcel
  • กำหนดจุดที่จะกรอกข้อมูลโดยใส่ ${key name} ใน word เช่น ${header} จากนั้นใน PHP ก็ส่งค่าตัวแปรไปแทนที่โดยใช้
    $templateProcessor->setValue('header', $title);
  • สามารถ repeat ตารางได้โดยการใส่ ${key name} ใน column ที่ต้องการคัดลอกแถวทั้งแถว เช่น ${student_id} และสั่งให้คัดลอกแถวโดยใช้
    $templateProcessor->cloneRow('student_id', จำนวนครั้ง);

    แถวในตารางที่ใส่ ${student_id} จะเพิ่มขึ้นมาทั้งแถวรวมทั้งคอลัมน์อื่นด้วย

  • สามารถเติิมช้อมูลให้คอลัมน์ที่เพิ่มมาใหม่นี้โดยใช้
    foreach ($scores as $key => $value) {
        $templateProcessor->setValue('score#' . $key, htmlspecialchars($value, ENT_COMPAT, 'UTF-8'));
        $templateProcessor->setValue('student_id#' . $key, htmlspecialchars($key, ENT_COMPAT, 'UTF-8'));
    }

    สังเกตุว่าจะมี

    #' . $key

    เพิ่มขึ้นมาเพิื่อจะแทนที่ลำดับที่เพิ่มขึ้นมานั่นเอง

  • ในรูปแบบตารางที่ซับซ้อนเช่น ตาราง “ใบขออนุญาตสอบซ่อม” ที่ต้องทำซ้ำหลายแถวและหลายคอลัมน์พร้อมๆกัน ทั้งตารางจะไม่สามารถใช้
    $templateProcessor->cloneRow('student_id', จำนวนครั้ง);

    ได้ ต้องเปลี่ยนไปใช้

    $templateProcessor->cloneBlock('repeater', จำนวนครั้ง);

    แทน แต่จะไม่สามารถใส่ตัวแปรลงไปแทนที่ได้ใน version นี้ (PHPWord version 0.13.0)

CKEditor template builder

การใส่ content เดี่ยวนี้จะมีรูปแบบที่บังคับเหมือนๆกัน ทั้งที่เป็นเพราะว่า ต้องการให้เนื่อหาออกมาใน format รูปแบบเดียวกันและ พวก framework อย่าง bootstrap ก็ จะมีโครงสร้าง อย่าง tabs ก็จะมีโครงสร้าง

<ul class="nav nav-tabs">
  <li class="active"><a data-toggle="tab" href="#home">Home</a></li>
  <li><a data-toggle="tab" href="#menu1">Menu 1</a></li>
  <li><a data-toggle="tab" href="#menu2">Menu 2</a></li>
</ul>

<div class="tab-content">
  <div id="home" class="tab-pane fade in active">
    <h3>HOME</h3>
    <p>Some content.</p>
  </div>
  <div id="menu1" class="tab-pane fade">
    <h3>Menu 1</h3>
    <p>Some content in menu 1.</p>
  </div>
  <div id="menu2" class="tab-pane fade">
    <h3>Menu 2</h3>
    <p>Some content in menu 2.</p>
  </div>
</div>

ถ้าจะต้อง copy จาก template snipted ก็ไม่สดวก ไหนๆ ก็ใช้ WYSIWYG ตอนที่กรอกข้อมูลอยู่แล้วก็ทำให้มันใส่ เทมเพลต template ในเนื้อหาให้แล้วมาแก้ทีหลัง จะดีกว่า

เริ่มกันเลย

  1. โหลด CKEditor
  2. โหลด plugin Content Templates แตกไฟล์โพลเดอร์ ออกมา ในโฟลเดอร์ ckeditor\plugins\templates เป็น \ckeditor\plugins\templates
  3. เขียน code ประมาณ
    <!doctype html>
    <html lang="th-TH">
    <head>
    <meta charset="utf-8">
    <title>CKEditor: Content Templates</title>
    </head>
    
    <body>
    <textarea name="editor" id="editor1" rows="10" cols="80">
    This is my textarea to be replaced with CKEditor.
    </textarea>
    <script src="ckeditor.js"></script>
    <script>
    CKEDITOR.replace( 'editor', {
    	"extraPlugins": "templates",
    });
    </script>
    </body>
    </html>
    
  4. สร้างเทมเพลตเพิ่มโดยเปิดไฟล์ \ckeditor\plugins\templates\templates\default.js
    	templates: [
    ...
    {
    		title: 'Bootstrap Tabs',
    		image: 'bootstrapTabs.gif',
    		description: 'add bootstrap tabs to content.',
    		html: '<ul class="nav nav-tabs">' +
    '<li class="active"><a data-toggle="tab" href="#home">Home</a></li>' +
    '<li><a data-toggle="tab" href="#menu1">Menu 1</a></li>' +
    '<li><a data-toggle="tab" href="#menu2">Menu 2</a></li>' +
    '</ul>' +
    '<div class="tab-content">' +
    '<div id="home" class="tab-pane fade in active">' +
    '<h3>HOME</h3>' +
    '<p>Some content.</p>' +
    '</div>'+
    '<div id="menu1" class="tab-pane fade">' +
    '<h3>Menu 1</h3>' +
    '<p>Some content in menu 1.</p>' +
    '</div>' +
    '<div id="menu2" class="tab-pane fade">' +
    '<h3>Menu 2</h3>' +
    '<p>Some content in menu 2.</p>' +
    '</div>' +
    '</div>'
    	},
    ...
     ]
    } );
    

    ใส่ภาพตัวอย่างที่ \ckeditor\plugins\templates\templates\images

  5. ทดลองใช้งานดู ตัว icons จะอยู่ที่ เมนูชุดแรกหลังปุ่มพิมย์ ถ้าไม่เห็นเทมเพลตที่สร้างลอง clear cache ดูก่อน

เสียเวลาเขียนระบบเพิ่ม แต่อำนวยความสดวกให้ทำ content ง่ายขึ้นเยอะเลย

แก้ validation error ใน YII 2

ฟอร์มของ yii จะมีการแจ้งเตือนถ้าหากพบว่าข้อมูล input ที่เรากรอกใน form ไม่ถูกต้อง โดยจะทำกรอบอินพุต ป้าย label เป็นสีแดงและมีข้อความแสดงใน help-block เพิ่มขึ้นมา บางครั้งก็ทำให้ฟอร์มที่จัดไว้แน่นๆ ไม่ใช่แบบบรรทัดละกล่องข้อความตามแบบเว็บสมัยใหม่ เวลาเจอความผิดพลาด มันก็จะถีบตัวอื่นออกไป หรือดูอัดแน่นเกินไปจนดูไม่สวย

ก็สามารถเอาออกได้โดยใช้ form template เหมือนเดิม โดยยังสามารถทำ validation ได้ตามปกติ

วิธีการคือ

  1. เปิดไฟล์ _form.php ใน view เป้าหมาย
  2. เปลี่ยน
    <?php $form = ActiveForm::begin(['id' => 'login-form']); ?>
    

    เป็น

    <?php $form = ActiveForm::begin([
        'fieldConfig' => [
            'template' => "{label}\n{input}\n{hint}"
        ],
        'id' => 'login-form'
    ]); ?>
    

อย่าลืมเปลี่ยน id นะครับ

ถ้าใช้

use yii\bootstrap\ActiveForm;

ให้เปลี่ยน template เป็น

'template' => "{label}\n{beginWrapper}\n{input}\n{hint}\n{endWrapper}"

YII 2 : Horizontal / inline form

ตามปกติ form ของ yii ที่ใช้ GII generate ออกมาจะเป็นรูปแบบ label บรรทัดหนึ่ง input อีกบรรทัดหนึ่ง อ่านง่าย สวยงามพอสมควร แต่อาจจะไม่ถูกใจบรรดาหัวหน้าอนุรักษ์นิยมทั้งหลาย

yii มีอีกทางเลือกให้ใช้ทำฟอร์ม คือ มี Horizontal form ให้เลือกใช้ yii bootstrap activeform (Horizontal form) อีกตัว

วิธีการคือ

  1. เปิดไฟล์ _form.php ใน view เป้าหมาย
  2. เปลี่ยน use yii\widgets\ActiveForm; เป็น use yii\bootstrap\ActiveForm; ถ้าไม่เปลี่ยนจะเจอ error Setting unknown property: yii\widgets\ActiveForm::layout
  3. เปลี่ยน
    $form = ActiveForm::begin();

    เป็น

    $form = ActiveForm::begin([
        'fieldConfig' => [
            'horizontalCssClasses' => [
                'label' => 'col-sm-2',
                'offset' => 'col-sm-offset-2',
                'wrapper' => 'col-sm-10'
            ]
        ],
        'layout' => 'horizontal'
    ]);
  4. สำเร็จแล้ว ฟอร์มจะเปลี่ยนเป็นรูปแบบเหมือนกับ Bootstrap Horizontal form โดย

    • layout คือ จะวางฟอร์มเป็นแบบไหน มีให้เลือก คือ default, horizontal และ inline
    • label คือ ค่า grid ของ label
    • wrapper คือ ความกว้างของช่อง input
    • offset คือ การเว้นระยะของพวก checkbox ตั้งไว้เท่ากับ label จะได้ตรงกันพอดี

    เสร็จแล้ว หรือจะใช้การจัด code แบบของผมก็ได้ครับ ไม่อยากสลับ php เข้าออก ไปๆ มาๆ

    <?php
    
    use yii\helpers\Html;
    use yii\bootstrap\ActiveForm;
    
    ?>
    
    <div class="user-form">
    <?php
    $form = ActiveForm::begin([
        'fieldConfig' => [
            'horizontalCssClasses' => [
                'label' => 'col-sm-2',
                'offset' => 'col-sm-offset-2',
                'wrapper' => 'col-sm-10'
            ]
        ],
        'layout' => 'horizontal'
    ]);
    
    echo $form->field($model, 'username')->textInput(),
    $form->field($model, 'email')->textInput(),
    $form->field($model, 'status')->checkbox(array('label'=>'enable')),
    '<div class="form-group">',Html::submitButton($model->isNewRecord ? Yii::t('app', 'Create') : Yii::t('app', 'Update'), ['class' => $model->isNewRecord ? 'btn btn-success' : 'btn btn-primary']);
    ActiveForm::end();
    echo'</div>';

PHP เทมเพลต

วิธีติดต่อ user ดีที่สุดคือการส่งจดหมายข่าวบอกไปว่าเว็บเราอัพเดต มีอะไรน่าสนใจบ้าง แต่จะให้ส่งข้อความไปเหมือนๆ กันทุกๆ คน คงจะดูไม่น่าสนใจเท่าไหร ถ้ามีบางส่วนที่พิเศษไปสำหรับแต่ละคน เช่น แสดงชื่อของลูกค้า จะดูน่าสนใจขึ้นใช้ไหมครับ
ก่อนอื่นก็สร้างไฟล์ที่เป็นต้นแบบของจดหมายมาก่อนชื่อ templates.tmp.html

<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>#title#</title>
</head>
<body bgcolor="#c00000">
#contents#
</body>
</html>

จากนั้นจะทดลองเปลี่ยนเนื้อหาจากต้นฉบับดู สร้างไฟล์ templates.php ตามตัวอย่าง

<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>PHP template By Pitt Phunsanit</title>
</head>
<body>
<?php
$output = file_get_contents('templates.tmp.html');
$patternSearch = array('#title#', '#contents#');
$patternReplace = array('ทดลองเทมเพลต', 'แสดงเนื้อหาแล้วนะ');
$output = str_replace($patternSearch, $patternReplace, $output);
echo'<textarea cols="200" rows="40">',$output,'</textarea>';
?>
</body>
</html>

หลักการง่ายๆ คือแทนที่คำๆหนึ่ง ด้วยค่าจากตัวแปรอื่น ๆ ลองดัดแปลงใช้กับฟังก์ชั่นเมล์ดูนะครับ อาจจะเพิ่มให้มีไฟล์ต้นแบบหลายๆ แบบ