======================================================================
 PSGI::Handy Tutorial (tut/)
 သင်ခန်းစာ လက်စွဲ                                        [MY] ဗမာဘာသာ
======================================================================

 tut/ သည် PSGI::Handy ၏ တရားဝင် သင်ကြားရေး သင်ခန်းစာ ဖြစ်သည်—အခန်းခြောက်ခန်း နှင့် အဆင့်နှစ်ဆယ့်လေးဆင့်ပါ သင်ရိုးတစ်ခုဖြစ်ပြီးblack box မရှိဘဲ၊ အရိုးဆုံး HTTP တုံ့ပြန်မှုမှ စတင်ကာ ပြည့်စုံသောCRUD application အထိ web application တစ်ခုကို အစမှ တည်ဆောက်သည်။အဆင့်တိုင်းသည် သီးခြားရပ်တည်နိုင်ပြီး အလုပ်လုပ်နိုင်သော Perlပရိုဂရမ်တစ်ခုဖြစ်သည်။ stack တစ်ခုလုံးမှာ Perl သန့်စင်ပြီးမှီခိုမှုကင်းသည်— PSGI::Handy (framework), HTTP::Handy (server),HP::Handy (တမ်းပလိတ်) နှင့် DB::Handy (database)။

[ မည်သို့ အလုပ်လုပ်စေမည် ]

  tut/ directory အတွင်းမှ တစ်ကြိမ်လျှင် တစ်ဆင့်စီ အလုပ်လုပ်စေပါ၊ ဥပမာperl 01_step01_text.pl  ။ ပရိုဂရမ်တိုင်းသည် server တစ်ခုကို စတင်ပြီး၎င်း၏ URL ကို ပုံနှိပ်သည်; browser တွင် http://127.0.0.1:8080/ ကိုဖွင့်ပြီး ရပ်တန့်ရန် Ctrl-C ကို နှိပ်ပါ။ templates/ directory နှင့်data.csv သည် လက်ရှိ directory မှ ဝင်ရောက်နိုင်ရမည် ဖြစ်သောကြောင့်ပရိုဂရမ်များကို tut/ အတွင်းမှ အမြဲစတင်ပါ။

[ ဘုံ ခေါင်းစီး ]

  ဖိုင်တိုင်း .pl သည် တူညီသော ခေါင်းစီးဖြင့် ဖွင့်သည်— use 5.00503;use strict; 5.6 ထက် ဟောင်းသော Perl တွင် အလုပ်မလုပ်သော warnings stubကို ပေးသော သေးငယ်သည့် BEGIN block; ထို့နောက် use warnings; local $^W= 1;  ။ ပရိုဂရမ်များသည် Perl 5.005_03 အထိ မှန်ကန်နေစေရန် barewordfilehandle နှင့် argument နှစ်ခုပါ open ကို သုံးသည်။ ဤခေါင်းစီးသည်အဆင့်တိုင်းတွင် တူညီပြီး အောက်တွင် ထပ်မဖော်ပြတော့ပါ။

----------------------------------------------------------------------
 root ဖိုင်များ
----------------------------------------------------------------------

  00_README.txt
      သင်ရိုး ခြုံငုံသုံးသပ်ချက်— အခန်းနှင့် အဆင့်တိုင်းကို ၎င်းတို့၏သင်ယူရေး ရည်မှန်းချက်နှင့်အတူ။ မည်သည့်ပရိုဂရမ်ကိုမဆို မဖွင့်မီလမ်းကြောင်းတစ်ခုလုံးကို မြင်ရန် ဤအရာကို ဦးစွာဖတ်ပါ။

  data.csv
      အခန်း 4 အတွက် နမူနာ ဒေတာ (CSV အဆင့်များ)— id,name,age ၏ကော်မာဖြင့်ခွဲထားသော သုံးတန်း။ အဆင့် 12, 14 နှင့် 15 သည်ဤဖိုင်ကို ပြန်ရေးသောကြောင့် ၎င်းကို ပြန်လည်သတ်မှတ်လိုပါက backupတစ်ခု သိမ်းထားပါ။1,Alice,20 / 2,Bob,22 / 3,Charlie,25

----------------------------------------------------------------------
 အခန်း 1 — HTTP တုံ့ပြန်မှု အခြေခံများ (static မှ dynamic သို့)
----------------------------------------------------------------------

  HTTP တုံ့ပြန်မှု၏ ပုံသဏ္ဍာန်ကို နားလည်ရန် browser နှင့် serverအကြား၊ template engine မပါဘဲ၊ ဖြစ်နိုင်သမျှ အရိုးရှင်းဆုံး ဖလှယ်မှု။

  01_step01_text.pl
      GET / အတွက် $c->text() မှတစ်ဆင့် စာသားရိုး '.' ကို ပြန်ပေးသည်။ဖြစ်နိုင်သမျှ အသေးဆုံး app— browser သည် raw အက္ခရာများလက်ခံရရှိသည် (text/plain)။

  01_step02_html.pl
      $c->html() မှတစ်ဆင့် '<a>.' ကို text/html အဖြစ် ပြန်ပေးသည်။အဆင့် 1 နှင့် byte တူညီသော်လည်း Content-Type သည် browser ကို၎င်းတို့ကို markup အဖြစ် ဆက်ဆံရန် ပြောသည်။ စာသား နှင့် HTMLကွာခြားချက်ကို ပြသသည်။

  01_step03_dyn_text.pl
      လက်ရှိ အချိန်ကို စာသားရိုးအဖြစ် ပြန်ပေးသည်၊တောင်းဆိုမှုတိုင်းတွင် scalar localtime() ဖြင့် အသစ်ဖတ်သည်။dynamic output ၏ ပထမအရသာ— တုံ့ပြန်မှုသည် အကြိမ်တိုင်းပြောင်းလဲသည်။

  01_step04_dyn_html.pl
      dynamic အချိန်ကို <h1>/<p> markup တွင် ထုပ်ပိုးပြီး HTML အဖြစ်ပြန်ပေးသည်။ variable များမှ string တစ်ခု စုစည်းခြင်းဖြင့် screenတစ်ခု တည်ဆောက်ခြင်း။

----------------------------------------------------------------------
 အခန်း 2 — အသုံးပြုသူ input နှင့် အခြေအနေ (form များနှင့် ခွဲထွက်ခြင်း)
----------------------------------------------------------------------

  browser မှ server သို့ ဒေတာ ပို့ခြင်း၊ နှင့် ရောက်လာသည့်အရာအပေါ်ခွဲထွက်ခြင်း။

  02_step05_form.pl
      GET / သည် /echo သို့ POST လုပ်သော HTML form (စာသားအကွက်နှင့်submit ခလုတ်) ကို ပြသသည်။ တင်ပြမှုအတွက် handler မရှိသေးပါ;ဤအဆင့်သည် form markup အကြောင်းသာ ဖြစ်သည်။

  02_step06_echo.pl
      POST /echo handler ထည့်သည်။ ၎င်းသည် $c->param('message') ဖြင့်'message' field ကို ဖတ်ပြီး HTML တုံ့ပြန်မှုအတွင်း ၎င်းကိုပြန်ထပ်ပေးသည်— တောင်းဆိုမှုမှ တုံ့ပြန်မှုသို့ အခြေခံ အသွားအပြန်။

  02_step07_auth.pl
      အနည်းဆုံး login တစ်ခု။ POST /login သည် 'username' နှင့်'password' ကို ဖတ်ပြီး ခွဲထွက်ရန် if ကို သုံးသည်— admin/secretသည် အောင်မြင်မှုစာမျက်နှာသို့ ရောက်ပြီး ကျန်အရာအားလုံးမအောင်မြင်မှုစာမျက်နှာသို့။ authentication နှင့် conditionalflow ၏ မျိုးစေ့။

----------------------------------------------------------------------
 အခန်း 3 — View ကို ခွဲထုတ်ခြင်း (HP::Handy မိတ်ဆက်)
----------------------------------------------------------------------

  ပရိုဂရမ်အတွင်း HTML ရေးခြင်းကို ရပ်ပါ; ၎င်းကို templateဖိုင်များသို့ ရွှေ့ပါ။ HP::Handy သည် render_file()/render_string()ကို ဖော်ပြသောကြောင့် template အမည်ကို render_file() သို့ map လုပ်သောသေးငယ်သည့် CODE renderer မှတစ်ဆင့် PSGI::Handy သို့ ချိတ်ဆက်ထားသည်။ထို renderer block သည် template ပါသော အဆင့်တိုင်းတွင် တူညီသည်။

  03_step08_template.pl
      variable မပါဘဲ static templates/step08.html ကို render လုပ်သည်။HTML သည် ယခု logic မှ သီးခြား၊ ၎င်း၏ ကိုယ်ပိုင်ဖိုင်တွင်နေထိုင်သည်။

  03_step09_template_var.pl
      templates/step09.html သို့ { current_time => ... } ကိုပေးပို့ပြီး၊ ၎င်းသည် {{ current_time }} placeholder ဖြင့်၎င်းကို ပုံနှိပ်သည်။ ဒေတာသည် ပရိုဂရမ်မှ template သို့စီးဆင်းသည်။

  03_step10_template_form.pl
      template နှစ်ခု သုံး၍ အဆင့် 6 ၏ echo ကို ပြန်ရေးသည်— input အတွက်step10_form.html နှင့် ရလဒ်အတွက် step10_result.html။ handlerlogic သည် အလွန်သေးငယ်လာသည်။

----------------------------------------------------------------------
 အခန်း 4 — File I/O နှင့် CSV တည်မြဲမှု (CRUD အခြေခံများ)
----------------------------------------------------------------------

  database မပါဘဲ၊ ရိုးရှင်းသော CSV ဖိုင်တစ်ခုအပေါ်Create/Read/Update/Delete ကို အကောင်အထည်ဖော်ပါ။ ကိုယ်တိုင်ဒေတာကိုင်တွယ်ခြင်း၏ ကုန်ကျစရိတ်ကို ခံစားရခြင်းသည် အခန်း 5 တွင်database သို့ ပြောင်းရွှေ့ရန် လှုံ့ဆော်ပေးသည်။

  04_step11_csv_readall.pl
      Read All. data.csv ကို ဖွင့်ပြီး၊ လိုင်းတိုင်းကို ကော်မာများတွင်{ id, name, age } hash များအဖြစ် ခွဲ၍၊ စာရင်းကို HTML tableအဖြစ် render လုပ်သည် (step11_list.html)။

  04_step12_csv_create.pl
      Create. POST /add သည် append mode (>>) တွင် data.csv သို့'id,name,age' လိုင်းတစ်ခု ထည့်ပြီး၊ ပြီးစီးမှု စာမျက်နှာကိုပြသသည်။

  04_step13_csv_readone.pl
      Read One. route /user/:id သည် id တစ်ခုကို ဖမ်းသည်; ပရိုဂရမ်သည်ကိုက်ညီသော row အတွက် data.csv ကို scan လုပ်ပြီး ၎င်း၏အသေးစိတ်ကို ပြသသည် (step13_detail.html) သို့မဟုတ် မတွေ့ပါက 404ပြန်ပေးသည်။

  04_step14_csv_update.pl
      Update. row တစ်ခု ပြောင်းရန် ၎င်းသည် လိုင်းတိုင်းကို ဖတ်ပြီး၊ကိုက်ညီသောအရာကို အစားထိုးကာ ဖိုင်တစ်ခုလုံးကို ပြန်ရေးသည်—database က ဖယ်ရှားမည့် 'အားလုံးဖတ်၊ လဲလှယ်၊ အားလုံးရေး'အလုပ်ကြမ်း။

  04_step15_csv_delete.pl
      Delete. တူညီသော ဖိုင်တစ်ခုလုံး ပြန်ရေးခြင်း၊ သို့သော် ကိုက်ညီသောrow ကို အစားထိုးမည့်အစား ကျော်သွားသည်။

----------------------------------------------------------------------
 အခန်း 5 — Model မိတ်ဆက် (DB::Handy သို့ ပြောင်းရွှေ့)
----------------------------------------------------------------------

  CSV ကို DB::Handy ဖြင့် အစားထိုးပါ။ handle ကိုDB::Handy->connect('data','app',{...}) ဖြင့် ဖန်တီးပြီး db => $dbhမှတစ်ဆင့် inject လုပ်ကာ၊ handler များတွင် $c->db အဖြစ် ရောက်ရှိသည်။_bootstrap() routine သည် 'users' table ကို တစ်ကြိမ် ဖန်တီး၍မျိုးစေ့ချသောကြောင့် ဥပမာတိုင်းသည် သီးခြားရပ်တည် အလုပ်လုပ်သည်။

  05_step16_db_readall.pl
      Read All. selectall_arrayref(..., { Slice => {} }) သည် listtemplate (step16_list.html) အတွက် users row တိုင်းကို hash အဖြစ်ဆွဲယူသည်။ ကိုယ်တိုင် ဖိုင် parse လုပ်ခြင်း မရှိတော့ပါ။

  05_step17_db_create.pl
      Create. POST /add သည် placeholder INSERT ဖြင့် row တစ်ခုထည့်ပြီး၊ / (စာရင်း) သို့ redirect လုပ်သည်— စံ post-then-redirect pattern။

  05_step18_db_readone.pl
      Read One. /user/:id သည် selectrow_hashref() ဖြင့် primary keyအလိုက် row တစ်ခုကို ဆွဲယူသည် သို့မဟုတ် 404 ပြန်ပေးသည်။ rowတိုင်းကို scan လုပ်မည့်အစား တိုက်ရိုက် key ရှာဖွေခြင်း။

  05_step19_db_update.pl
      Update. GET /user/:id/edit သည် edit form ကို ပြသသည်; POST သည်UPDATE ... WHERE id=? ကို run ပြီး အသေးစိတ် စာမျက်နှာသို့redirect လုပ်သည်။ memory တွင် ဖိုင်တစ်ခုလုံး ပြန်ရေးခြင်းမရှိပါ။

  05_step20_db_delete.pl
      Delete. DELETE ... WHERE id=? ကို run ပြီး၊ / သို့ redirectလုပ်သည်။ အခြေအနေ ပြောင်းလဲသော route သည် POST သာဖြစ်ပြီး GET မှမတော်တဆ ဖျက်ခြင်းကို ရှောင်ရှားရန်။

----------------------------------------------------------------------
 အခန်း 6 — ဆက်နွှယ်သော ဒေတာနှင့် တကယ့် application တစ်ခု
----------------------------------------------------------------------

  ဒုတိယ database 'app2' တွင် ဆက်စပ်သော table နှစ်ခု (users နှင့်depts)။ JOIN ကို black box မဖြစ်စေရန် Perl တွင် ကိုယ်တိုင်ပြုလုပ်ပြီး၊ ထို့နောက် အရာအားလုံးကို ပြည့်စုံသော applicationတစ်ခုအဖြစ် စုစည်းသည်။

  06_step21_db_join_list.pl
      JOIN List. table နှစ်ခုလုံးကို ဖတ်ပြီး၊ dept_id => nameရှာဖွေမှုတစ်ခု တည်ဆောက်ကာ၊ အသုံးပြုသူတိုင်းတွင် dept_name ကိုတွဲချိတ်သည် (ကိုယ်တိုင်ရေးသော JOIN) ပြီး ၎င်းတို့ကိုစာရင်းပြုသည် (step21_join_list.html)။

  06_step22_db_join_detail.pl
      JOIN Read One. အသုံးပြုသူတစ်ဦးကို ဆွဲယူပြီး၊ ထိုအသုံးပြုသူ၏တစ်ခုတည်းသော ဌာနကို ရှာဖွေကာ အသေးစိတ် စာမျက်နှာအတွက်၎င်း၏အမည်ကို တွဲချိတ်သည် (step22_join_detail.html)။

  06_step23_db_form_select.pl
      Select form. ဌာန master ကို load လုပ်ပြီး ၎င်းကို <select>dropdown အဖြစ် render လုပ်သည် (step23_form_select.html) သို့မှသာအသုံးပြုသူသည် id ရိုက်မည့်အစား ဌာနတစ်ခု ရွေးချယ်သည်။

  06_step24_fullstack_app.pl
      ဖိုင်တစ်ခုတည်းတွင် ပြည့်စုံသော application— users+deptsဒေတာအပေါ် list, detail, add, edit နှင့် delete; တွဲချိတ်ထားသောဌာနအမည်များ၊ select dropdown၊ နေရာတိုင်းတွင် post-then-redirect၊နှင့် _next_id() helper (DB::Handy တွင် auto-increment မရှိ)။app_list.html နှင့် app_form.html ကို သုံးသည်။

----------------------------------------------------------------------
 တမ်းပလိတ်များ (templates/)
----------------------------------------------------------------------

  HP::Handy template များသည် Jinja2 နှင့်ဆင်သော syntax ကို သုံးသည်— {{var }} သည် တန်ဖိုးတစ်ခုကို ပုံနှိပ်သည် ({{ user.name }} ကဲ့သို့dotted path များသည် hash များအတွင်း ရောက်ရှိသည်), {% for x in list%} ... {% endfor %} သည် loop လုပ်ပြီး {% if ... %} သည် ခွဲထွက်သည်။renderer ကို auto_escape => 1 ဖြင့် ဖန်တီးသောကြောင့် ပုံနှိပ်သောတန်ဖိုးများသည် HTML-escape ဖြစ်သည်။

  templates/step08.html
      အဆင့် 8 မှ သုံးသော လုံးဝ static စာမျက်နှာ; placeholder မရှိ။

  templates/step09.html
      {{ current_time }} မှတစ်ဆင့် server အချိန်ကို ပုံနှိပ်သည် (အဆင့်9)။

  templates/step10_form.html
      အဆင့် 10 ၏ echo အတွက် input form; 'message' ကို /echo သို့ POSTလုပ်သည်။

  templates/step10_result.html
      အဆင့် 10 အတွက် ပြန်ထပ်သော {{ message }} ကို ပြသသည်။

  templates/step11_list.html
      CSV table ဆွဲရန် {{ users }} အပေါ် loop လုပ်သည် (အဆင့် 11)။

  templates/step12_form.html
      အဆင့် 12 အတွက် ထည့်သွင်းရန် form (id, name, age)။

  templates/step12_result.html
      အဆင့် 12 ၏ "Added" အတည်ပြုစာမျက်နှာ — {{ name }} နှင့် ပြန်သွားရန် လင့်ခ်ကို ပြသသည်။

  templates/step13_list.html
      အဆင့် 13 ၏ အညွှန်း — အသုံးပြုသူတစ်ဦးစီသည် မိမိ၏ /user/:id အသေးစိတ်စာမျက်နှာသို့ ချိတ်ဆက်သည်။

  templates/step13_detail.html
      အဆင့် 13 အတွက် အသုံးပြုသူတစ်ဦး၏ id/name/age ကို ပြသသည်။

  templates/step14_list.html
      အဆင့် 14 ၏ စာမျက်နှာ — လက်ရှိအတန်းများနှင့် /update သို့ POST လုပ်သော ပြင်ဆင်မှုဖောင်။

  templates/step15_list.html
      အဆင့် 15 ၏ စာမျက်နှာ — လက်ရှိအတန်းများနှင့် /delete သို့ POST လုပ်သော ဖျက်ခြင်းဖောင်။

  templates/step16_list.html
      အဆင့် 16 အတွက် ရိုးရှင်းသော DB အသုံးပြုသူစာရင်း (လင့်ခ်မရှိသေး)။

  templates/step17_form.html
      အဆင့် 17 အတွက် အသုံးပြုသူ ထည့်သွင်းရန် form။

  templates/step17_list.html
      /add သို့ "Add New User" လင့်ခ်ပါသော အဆင့် 17 စာရင်း။

  templates/step18_list.html
      အဆင့် 18 စာရင်း — အမည်တစ်ခုစီသည် မိမိ၏ /user/:id အသေးစိတ်သို့ ချိတ်ဆက်သည်။

  templates/step18_detail.html
      အဆင့် 18 အတွက် ရိုးရှင်းသော အသုံးပြုသူ အသေးစိတ်၊ ပြန်သွားရန် လင့်ခ်ပါသည်။

  templates/step19_list.html
      အဆင့် 19 စာရင်း — အမည်တစ်ခုစီသည် မိမိ၏ အသေးစိတ်စာမျက်နှာသို့ ချိတ်ဆက်သည်။

  templates/step19_detail.html
      အဆင့် 19 အသုံးပြုသူ အသေးစိတ်၊ Edit လင့်ခ်နှင့် ပြန်သွားရန် လင့်ခ်ပါသည်။

  templates/step19_edit.html
      အဆင့် 19 အတွက် edit form (name, age); /user/:id/edit သို့ POSTလုပ်သည်။

  templates/step20_list.html
      အတန်းတိုင်းတွင် အတည်ပြုရန်လိုသော POST Delete ခလုတ်ပါသော အဆင့် 20 စာရင်း။

  templates/step21_join_list.html
      join လုပ်ထားသော {{ user.dept_name }} column ဖြင့် ဝန်ထမ်း စာရင်း(အဆင့် 21)။

  templates/step22_join_list.html
      အဆင့် 22 ဝန်ထမ်းအညွှန်း — အမည်တစ်ခုစီသည် မိမိ၏ အသေးစိတ်စာမျက်နှာသို့ ချိတ်ဆက်သည်။

  templates/step22_join_detail.html
      ဌာနအမည်ကို ပြသသော ဝန်ထမ်း အသေးစိတ် (အဆင့် 22)။

  templates/step23_list.html
      /add သို့ "Add New Employee" လင့်ခ်ပါသော အဆင့် 23 ဝန်ထမ်းစာရင်း။

  templates/step23_form_select.html
      {{ depts }} မှ တည်ဆောက်သော ဌာန <select> ဖြင့် ထည့်သွင်းရန် form(အဆင့် 23)။

  templates/app_list.html
      ပြည့်စုံသော app ၏ ဝန်ထမ်း စာရင်း (အဆင့် 24)— ID, linkချိတ်ထားသော အမည်၊ ဌာန၊ အပြင် row တိုင်းအတွက် Edit နှင့်အတည်ပြုချက်ဖြင့် ကာကွယ်ထားသော POST Delete၊ နှင့် Add link။

  templates/app_form.html
      ပြည့်စုံသော app ၏ မျှဝေထားသော ထည့်သွင်း/edit form (အဆင့် 24)— {{action }} ပစ်မှတ်သည် ဖန်တီးခြင်းနှင့် update ကြား ပြောင်းလဲပြီး၊ဌာန <select> သည် {% if %} မှတစ်ဆင့် {{ user.dept_id }} ကိုကြိုတင်ရွေးချယ်သည်။

----------------------------------------------------------------------
 ကိုးကားချက်များ
----------------------------------------------------------------------

  MetaCPAN ပေါ်ရှိ PSGI::Handy နှင့် Handy stack ၏ ကျန်အပိုင်းများ၊နှင့် PSGI သတ်မှတ်ချက်—

    https://metacpan.org/dist/PSGI-Handy
    https://metacpan.org/dist/HTTP-Handy
    https://metacpan.org/dist/HP-Handy
    https://metacpan.org/dist/DB-Handy
    https://github.com/plack/psgi-specs/blob/master/PSGI.pod

======================================================================
