======================================================================
 PSGI::Handy Tutorial (tut/)
 টিউটোরিয়াল ম্যানুয়াল                                    [BN] বাংলা
======================================================================

 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; একটি ছোট BEGIN ব্লক যা 5.6-এর চেয়ে পুরানো Perl-এ একটি নিষ্ক্রিয় warnings stub সরবরাহ করে; তারপর 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 ব্রাউজারকে সেগুলিকে মার্কআপ হিসেবে বিবেচনা করতে বলে। টেক্সট বনাম HTML পার্থক্য দেখায়।

  01_step03_dyn_text.pl
      বর্তমান সময়কে সাধারণ টেক্সট হিসেবে ফেরত দেয়, প্রতিটি অনুরোধে scalar localtime() দিয়ে নতুন করে পড়া হয়। গতিশীল আউটপুটের প্রথম স্বাদ: প্রতিক্রিয়া প্রতিবার পরিবর্তিত হয়।

  01_step04_dyn_html.pl
      গতিশীল সময়কে <h1>/<p> মার্কআপে মোড়ায় এবং HTML হিসেবে ফেরত দেয়। চলক থেকে একটি স্ট্রিং একত্রিত করে একটি স্ক্রিন তৈরি করা।

----------------------------------------------------------------------
 অধ্যায় 2 — ব্যবহারকারী ইনপুট ও অবস্থা (ফর্ম ও শাখাবিভাজন)
----------------------------------------------------------------------

  ব্রাউজার থেকে সার্ভারে ডেটা পাঠানো, এবং যা আসে তার উপর শাখাবিভাজন করা।

  02_step05_form.pl
      GET / একটি HTML ফর্ম (একটি টেক্সট বক্স ও একটি submit বোতাম) দেখায় যা /echo-এ POST করে। জমা দেওয়ার জন্য এখনও কোনো হ্যান্ডলার নেই; এই ধাপটি শুধুমাত্র ফর্ম মার্কআপ সম্পর্কে।

  02_step06_echo.pl
      POST /echo হ্যান্ডলার যোগ করে। এটি $c->param('message') দিয়ে 'message' ফিল্ড পড়ে এবং HTML প্রতিক্রিয়ার ভিতরে এটি প্রতিধ্বনিত করে: অনুরোধ-থেকে-প্রতিক্রিয়া মৌলিক চক্র।

  02_step07_auth.pl
      একটি ন্যূনতম লগইন। POST /login 'username' ও 'password' পড়ে এবং শাখাবিভাজনের জন্য একটি if ব্যবহার করে: admin/secret সফলতার পৃষ্ঠায় পৌঁছায়, বাকি সবকিছু ব্যর্থতার পৃষ্ঠায়। প্রমাণীকরণ ও শর্তসাপেক্ষ প্রবাহের বীজ।

----------------------------------------------------------------------
 অধ্যায় 3 — View পৃথক করা (HP::Handy পরিচিতি)
----------------------------------------------------------------------

  প্রোগ্রামের ভিতরে HTML লেখা বন্ধ করুন; এটি টেমপ্লেট ফাইলে সরান। HP::Handy render_file()/render_string() প্রকাশ করে, তাই এটি একটি ছোট CODE renderer-এর মাধ্যমে PSGI::Handy-এর সাথে সংযুক্ত যা একটি টেমপ্লেট নামকে render_file()-এ ম্যাপ করে। সেই renderer ব্লকটি প্রতিটি টেমপ্লেটযুক্ত ধাপে একই।

  03_step08_template.pl
      চলক ছাড়া স্ট্যাটিক templates/step08.html রেন্ডার করে। 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 টেবিল হিসেবে রেন্ডার করে (step11_list.html)।

  04_step12_csv_create.pl
      Create. POST /add append মোডে (>>) 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 ফর্ম. বিভাগ মাস্টার লোড করে এবং এটিকে একটি <select> ড্রপডাউন হিসেবে রেন্ডার করে (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
      ধাপ ১২-এর "Added" নিশ্চিতকরণ পৃষ্ঠা: {{ name }} এবং একটি ফিরে যাওয়ার লিঙ্ক দেখায়।

  templates/step13_list.html
      ধাপ ১৩-এর সূচি: প্রতিটি ব্যবহারকারী তার নিজের /user/:id বিশদ পৃষ্ঠার সাথে লিঙ্ক করে।

  templates/step13_detail.html
      ধাপ 13-এর জন্য একটি ব্যবহারকারীর id/name/age দেখায়।

  templates/step14_list.html
      ধাপ ১৪-এর পৃষ্ঠা: বর্তমান সারিগুলি এবং /update-এ POST করা একটি আপডেট ফর্ম।

  templates/step15_list.html
      ধাপ ১৫-এর পৃষ্ঠা: বর্তমান সারিগুলি এবং /delete-এ POST করা একটি মুছে ফেলার ফর্ম।

  templates/step16_list.html
      ধাপ ১৬-এর সাধারণ DB ব্যবহারকারী তালিকা (এখনও কোনো লিঙ্ক নেই)।

  templates/step17_form.html
      ধাপ 17-এর জন্য ব্যবহারকারী যোগ করার ফর্ম।

  templates/step17_list.html
      /add-এ "Add New User" লিঙ্ক সহ ধাপ ১৭-এর তালিকা।

  templates/step18_list.html
      ধাপ ১৮-এর তালিকা: প্রতিটি নাম তার নিজের /user/:id বিশদের সাথে লিঙ্ক করে।

  templates/step18_detail.html
      ধাপ ১৮-এর সাধারণ ব্যবহারকারী বিশদ, একটি ফিরে যাওয়ার লিঙ্ক সহ।

  templates/step19_list.html
      ধাপ ১৯-এর তালিকা: প্রতিটি নাম তার নিজের বিশদ পৃষ্ঠার সাথে লিঙ্ক করে।

  templates/step19_detail.html
      ধাপ ১৯-এর ব্যবহারকারী বিশদ, একটি Edit লিঙ্ক ও ফিরে যাওয়ার লিঙ্ক সহ।

  templates/step19_edit.html
      ধাপ 19-এর জন্য সম্পাদনা ফর্ম (name, age); /user/:id/edit-এ POST করে।

  templates/step20_list.html
      প্রতিটি সারিতে নিশ্চিতকরণসহ POST Delete বোতাম সহ ধাপ ২০-এর তালিকা।

  templates/step21_join_list.html
      যুক্ত {{ user.dept_name }} কলাম সহ কর্মচারী তালিকা (ধাপ 21)।

  templates/step22_join_list.html
      ধাপ ২২-এর কর্মচারী সূচি: প্রতিটি নাম তার নিজের বিশদ পৃষ্ঠার সাথে লিঙ্ক করে।

  templates/step22_join_detail.html
      বিভাগের নাম দেখানো কর্মচারী বিবরণ (ধাপ 22)।

  templates/step23_list.html
      /add-এ "Add New Employee" লিঙ্ক সহ ধাপ ২৩-এর কর্মচারী তালিকা।

  templates/step23_form_select.html
      {{ depts }} থেকে তৈরি বিভাগ <select> সহ যোগ করার ফর্ম (ধাপ 23)।

  templates/app_list.html
      সম্পূর্ণ অ্যাপের কর্মচারী তালিকা (ধাপ 24): ID, লিঙ্কযুক্ত নাম, বিভাগ, পাশাপাশি প্রতিটি সারির জন্য Edit ও একটি নিশ্চিতকরণ-সুরক্ষিত POST Delete, এবং একটি Add লিঙ্ক।

  templates/app_form.html
      সম্পূর্ণ অ্যাপের ভাগ করা যোগ/সম্পাদনা ফর্ম (ধাপ 24): {{ action }} লক্ষ্য create ও update-এর মধ্যে পরিবর্তন করে, এবং বিভাগ <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

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