======================================================================
 PSGI::Handy Tutorial (tut/)
 Гарын авлага                                             [MN] Монгол
======================================================================

 tut/ нь PSGI::Handy-ийн албан ёсны сургалтын заавар юм: зургаан бүлэг, хорин дөрвөн алхамтай сургалт бөгөөд хар хайрцаггүйгээр, хамгийн энгийн HTTP хариунаас эхлээд бүрэн CRUD програм хүртэл вэб програмыг эхнээс нь бүтээдэг. Алхам бүр нь бие даасан, ажиллах боломжтой нэг Perl програм юм. Бүх стек нь цэвэр Perl бөгөөд хамааралгүй: PSGI::Handy (фреймворк), HTTP::Handy (сервер), HP::Handy (загвар) ба DB::Handy (өгөгдлийн сан).

[ Хэрхэн ажиллуулах ]

  tut/ хавтасны дотроос нэг удаад нэг алхмыг ажиллуулна, жишээ нь perl 01_step01_text.pl  . Програм бүр сервер эхлүүлж URL-ээ хэвлэдэг; хөтөч дээр http://127.0.0.1:8080/ -ийг нээж, зогсоохын тулд Ctrl-C дарна. templates/ хавтас болон data.csv нь одоогийн хавтаснаас хүртээмжтэй байх ёстой тул програмуудыг үргэлж tut/ дотроос эхлүүлээрэй.

[ Нийтлэг толгой ]

  Бүх .pl файл ижил толгойгоор эхэлдэг: use 5.00503; use strict; 5.6-аас хуучин Perl дээр үйлдэлгүй warnings stub нийлүүлдэг жижиг BEGIN блок; дараа нь use warnings; local $^W = 1;  . Програмууд нь Perl 5.005_03 хүртэл хүчинтэй байх үүднээс bareword filehandle болон хоёр аргументтай open ашигладаг. Энэ толгой нь алхам бүрт ижил бөгөөд доор давтагдахгүй.

----------------------------------------------------------------------
 Үндсэн файлууд
----------------------------------------------------------------------

  00_README.txt
      Сургалтын тойм: бүлэг, алхам бүр сурах зорилгынхоо хамт. Аль нэг програмыг нээхээс өмнө бүх замналыг харахын тулд эхлээд үүнийг уншина уу.

  data.csv
      4-р бүлэгт зориулсан жишээ өгөгдөл (CSV алхамууд): таслалаар тусгаарласан id,name,age гэсэн гурван мөр. 12, 14, 15-р алхам энэ файлыг дахин бичдэг тул дахин тохируулахыг хүсвэл нөөц хувийг хадгална уу. 1,Alice,20 / 2,Bob,22 / 3,Charlie,25

----------------------------------------------------------------------
 Бүлэг 1 — HTTP хариуны үндэс (статикаас динамик руу)
----------------------------------------------------------------------

  HTTP хариуны хэлбэрийг ойлгохын тулд хөтөч ба серверийн хооронд, загвар хөдөлгүүргүй, хамгийн энгийн солилцоо.

  01_step01_text.pl
      GET / -д зориулж $c->text() -ээр энгийн текст '.' буцаадаг. Хамгийн жижиг програм: хөтөч түүхий тэмдэгт хүлээн авдаг (text/plain).

  01_step02_html.pl
      $c->html() -ээр '<a>.' -ийг text/html болгон буцаадаг. 1-р алхамтай ижил байт боловч Content-Type нь хөтөчид тэдгээрийг markup гэж үзэхийг хэлдэг. Текст ба HTML-ийн ялгааг харуулдаг.

  01_step03_dyn_text.pl
      Одоогийн цагийг энгийн текст болгон буцаадаг бөгөөд хүсэлт бүрт scalar localtime() -ээр шинээр уншдаг. Динамик гаралтын анхны амт: хариу нь тухай бүрт өөрчлөгддөг.

  01_step04_dyn_html.pl
      Динамик цагийг <h1>/<p> markup-д ороож HTML болгон буцаадаг. Хувьсагчдаас тэмдэгт мөр угсарч дэлгэц бүтээх.

----------------------------------------------------------------------
 Бүлэг 2 — Хэрэглэгчийн оролт ба төлөв (форм ба салаалалт)
----------------------------------------------------------------------

  Хөтөчөөс сервер рүү өгөгдөл илгээх, ирсэн зүйл дээр үндэслэн салаалах.

  02_step05_form.pl
      GET / нь /echo руу POST хийдэг HTML форм (текст хайрцаг болон илгээх товч) харуулдаг. Илгээлтийн боловсруулагч одоогоор байхгүй; энэ алхам зөвхөн формын markup-ийн тухай.

  02_step06_echo.pl
      POST /echo боловсруулагчийг нэмдэг. Энэ нь 'message' талбарыг $c->param('message') -ээр уншиж, HTML хариуны дотор буцааж цуурайтуулдаг: хүсэлтээс хариу хүртэлх үндсэн эргэлт.

  02_step07_auth.pl
      Хамгийн бага нэвтрэлт. POST /login нь 'username' болон 'password' -ыг уншиж салаалахын тулд if ашигладаг: admin/secret амжилтын хуудас руу, бусад нь бүтэлгүйтлийн хуудас руу очдог. Баталгаажуулалт ба нөхцөлт урсгалын үр.

----------------------------------------------------------------------
 Бүлэг 3 — View-г салгах (HP::Handy-г танилцуулах)
----------------------------------------------------------------------

  Програмын дотор HTML бичихээ боль; үүнийг загвар файлууд руу зөөнө үү. HP::Handy нь render_file()/render_string() -ийг ил гаргадаг тул загварын нэрийг render_file() -д буулгадаг жижиг CODE renderer-ээр дамжуулан PSGI::Handy -д холбогддог. Тэр renderer блок нь загвартай алхам бүрт ижил.

  03_step08_template.pl
      Хувьсагчгүйгээр статик templates/step08.html -ийг render хийдэг. HTML одоо логикоос тусдаа өөрийн файлд оршдог.

  03_step09_template_var.pl
      templates/step09.html руу { current_time => ... } дамжуулдаг бөгөөд энэ нь {{ current_time }} орлуулагчаар хэвлэдэг. Өгөгдөл програмаас загвар руу урсдаг.

  03_step10_template_form.pl
      6-р алхмын цуурайг хоёр загвараар дахин бичдэг: оролтод step10_form.html, үр дүнд step10_result.html. Боловсруулагчийн логик маш жижиг болдог.

----------------------------------------------------------------------
 Бүлэг 4 — Файлын I/O ба CSV хадгалалт (CRUD үндэс)
----------------------------------------------------------------------

  Өгөгдлийн сангүйгээр энгийн CSV файл дээр Create/Read/Update/Delete -ийг хэрэгжүүлнэ. Гар аргаар өгөгдөл боловсруулах өртгийг мэдрэх нь 5-р бүлэгт өгөгдлийн сан руу шилжихийг өдөөдөг.

  04_step11_csv_readall.pl
      Read All. data.csv -ийг нээж, мөр бүрийг таслалаар { id, name, age } hash болгон хувааж, жагсаалтыг HTML хүснэгт болгон render хийдэг (step11_list.html).

  04_step12_csv_create.pl
      Create. POST /add нь data.csv -д нэмэх горимд (>>) нэг 'id,name,age' мөр нэмж, дараа нь дуусгах хуудас харуулдаг.

  04_step13_csv_readone.pl
      Read One. /user/:id маршрут id -г барьдаг; програм тохирох мөрийг хайхаар data.csv -ийг сканнердаж, дэлгэрэнгүйг харуулдаг (step13_detail.html), эсвэл олдохгүй бол 404 буцаадаг.

  04_step14_csv_update.pl
      Update. Нэг мөрийг өөрчлөхийн тулд мөр бүрийг уншиж, тохирохыг солиж, бүх файлыг дахин бичдэг: өгөгдлийн сан арилгах 'бүгдийг унш, соль, бүгдийг бич' ажил.

  04_step15_csv_delete.pl
      Delete. Адил бүх файлыг дахин бичих боловч тохирох мөрийг солихын оронд алгасдаг.

----------------------------------------------------------------------
 Бүлэг 5 — Model-г танилцуулах (DB::Handy руу шилжих)
----------------------------------------------------------------------

  CSV -г DB::Handy -ээр солино. Бариулыг DB::Handy->connect('data','app',{...}) -ээр үүсгэж db => $dbh -ээр оруулж, дараа нь боловсруулагч дотор $c->db байдлаар хүрдэг. _bootstrap() горим 'users' хүснэгтийг нэг удаа үүсгэж тариалдаг тул жишээ бүр бие даан ажилладаг.

  05_step16_db_readall.pl
      Read All. selectall_arrayref(..., { Slice => {} }) нь жагсаалтын загварт (step16_list.html) users мөр бүрийг hash болгон авдаг. Гараар файл задлах шаардлагагүй болсон.

  05_step17_db_create.pl
      Create. POST /add нь орлуулагч INSERT -ээр нэг мөр оруулж, дараа нь / руу (жагсаалт руу) чиглүүлдэг: стандарт post-then-redirect загвар.

  05_step18_db_readone.pl
      Read One. /user/:id нь selectrow_hashref() -ээр үндсэн түлхүүрээр нэг мөр авдаг, эсвэл 404 буцаадаг. Мөр бүрийг сканнердахын оронд шууд түлхүүрийн хайлт.

  05_step19_db_update.pl
      Update. GET /user/:id/edit нь засах формыг харуулдаг; POST нь UPDATE ... WHERE id=? ажиллуулж, дэлгэрэнгүй хуудас руу чиглүүлдэг. Санах ойд бүх файлыг дахин бичихгүй.

  05_step20_db_delete.pl
      Delete. DELETE ... WHERE id=? ажиллуулж, дараа нь / руу чиглүүлдэг. Төлөв өөрчилдөг маршрут нь зөвхөн POST бөгөөд GET-ээс санамсаргүй устгахаас сэргийлдэг.

----------------------------------------------------------------------
 Бүлэг 6 — Хамаарлын өгөгдөл ба жинхэнэ програм
----------------------------------------------------------------------

  Хоёр дахь 'app2' өгөгдлийн санд хоёр холбоотой хүснэгт (users ба depts). JOIN -ийг хар хайрцаг болохгүйн тулд Perl дээр гараар хийж, дараа нь бүгдийг нэг бүрэн програмд угсардаг.

  06_step21_db_join_list.pl
      JOIN List. Хоёр хүснэгтийг уншиж, 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> унждаг жагсаалт болгон render хийдэг (step23_form_select.html) тул хэрэглэгч id бичихийн оронд хэлтэс сонгодог.

  06_step24_fullstack_app.pl
      Нэг файлд бүрэн програм: users+depts өгөгдөл дээр list, detail, add, edit ба delete; хавсаргасан хэлтсийн нэрс, select унждаг жагсаалт, хаа сайгүй post-then-redirect, болон _next_id() туслагч (DB::Handy автомат нэмэгдэлгүй). app_list.html болон app_form.html ашигладаг.

----------------------------------------------------------------------
 Загварууд (templates/)
----------------------------------------------------------------------

  HP::Handy загварууд Jinja2-тэй төстэй синтакс ашигладаг: {{ var }} утга хэвлэдэг ({{ user.name }} гэх мэт цэгтэй замууд hash дотор хүрдэг), {% for x in list %} ... {% endfor %} давталт хийдэг, {% if ... %} салаалдаг. Renderer-ийг auto_escape => 1 -ээр үүсгэдэг тул хэвлэгдсэн утгууд HTML-escape хийгддэг.

  templates/step08.html
      8-р алхамд ашигладаг бүрэн статик хуудас; орлуулагчгүй.

  templates/step09.html
      Серверийн цагийг {{ current_time }} -ээр хэвлэдэг (9-р алхам).

  templates/step10_form.html
      10-р алхмын цуурайн оролтын форм; 'message' -ийг /echo руу POST хийдэг.

  templates/step10_result.html
      10-р алхамд цуурайтсан {{ message }} -ийг харуулдаг.

  templates/step11_list.html
      CSV хүснэгт зурахын тулд {{ users }} дээр давтдаг (11-р алхам).

  templates/step12_form.html
      12-р алхамд зориулсан нэмэх форм (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-р алхамд хэрэглэгч нэмэх форм.

  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-р алхамд засах форм (name, age); /user/:id/edit руу POST хийдэг.

  templates/step20_list.html
      Мөр бүрт баталгаажуулдаг POST Delete товчтой 20-р алхмын жагсаалт.

  templates/step21_join_list.html
      Нэгтгэсэн {{ user.dept_name }} баганатай ажилтны жагсаалт (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> -тэй нэмэх форм (23-р алхам).

  templates/app_list.html
      Бүрэн програмын ажилтны жагсаалт (24-р алхам): ID, холбосон нэр, хэлтэс, мөн мөр бүрт Edit болон баталгаажуулалтаар хамгаалагдсан POST Delete, болон Add холбоос.

  templates/app_form.html
      Бүрэн програмын хуваалцсан нэмэх/засах форм (24-р алхам): {{ action }} зорилт нь үүсгэх ба шинэчлэхийн хооронд сэлгэдэг, хэлтсийн <select> нь {% if %} -ээр {{ user.dept_id }} -ийг урьдчилан сонгодог.

----------------------------------------------------------------------
 Эх сурвалж
----------------------------------------------------------------------

  MetaCPAN дээрх PSGI::Handy ба Handy стекийн бусад хэсэг, мөн 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

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