🦖
[] Бүрэн танилцуулга
codesaur/raptor GitHub дээр үзэх

Raptor Framework - Бүрэн танилцуулга

PHP Version License

codesaur/raptor - PSR стандартууд дээр суурилсан, олон давхаргат архитектуртай, олон байгууллагын (multi-tenant) PHP CMS фреймворк.


Агуулга

  1. Танилцуулга
  2. Суулгах
  3. Тохиргоо (.env)
  4. Архитектур
  5. Middleware pipeline
  6. Модулиуд - модуль бүр өөрийн дэд бүлэгтэй
  7. Template систем
  8. Routing
  9. Controller
  10. Model
  11. Тест
  12. Хэрэглээний жишээ

1. Танилцуулга

codesaur/raptor нь PSR-7/PSR-15 middleware суурьтай PHP фреймворк юм. Анхдагч байдлаараа Web (нийтийн вебсайт) болон Dashboard (админ панель) гэсэн хоёр апп-тай ирэх бөгөөд developer хэрэгцээндээ тааруулан хэдэн ч апп давхарга нэмж болно.

Гол боломжууд

  • PSR-7/PSR-15 middleware суурьтай архитектур
  • JWT + Session нэвтрэлт баталгаажуулалт
  • Олон байгууллагын (multi-tenant) RBAC эрхийн удирдлага
  • Олон хэл дэмжлэг (Localization)
  • CMS модулиуд: Мэдээ, Хуудас, Файл, Лавлах, Тохиргоо
  • Дэлгүүр модуль (Бүтээгдэхүүн, Захиалга, Үнэлгээ)
  • MySQL, PostgreSQL алийг нь ч дэмжинэ
  • SQL файл суурьтай өгөгдлийн сангийн migration систем
  • codesaur/template өөрийн template engine (Twig-маягийн синтакс)
  • OpenAI интеграци (moedit editor)
  • Зураг optimize хийх (GD)
  • PSR-3 лог систем
  • И-мэйл илгээх (Brevo API, SMTP, PHP mail)
  • PSR-14 Event Dispatcher систем (Discord, и-мэйл, лог - listener-ээр)
  • Discord webhook мэдэгдэл (event listener-ээр)
  • SEO: Хайлт, Sitemap, XML Sitemap, RSS feed
  • Спам хамгаалалт (honeypot, HMAC token, rate limiting, Cloudflare Turnstile)
  • CSRF хамгаалалт (CsrfMiddleware, csrfFetch)
  • Shared hosting / WAF тохиромж (cPanel/LiteSpeed/mod_security): HTTP method override, body encoding
  • File-based DB cache (PSR-16 SimpleCache) - автомат invalidation-тэй
  • Холбоо барих форм, мессеж удирдлага
  • Мэдээний сэтгэгдэл, 1 түвшний хариулт
  • Бүтээгдэхүүний үнэлгээ, одтой үнэлгээ (1-5)
  • Админ имэйл мэдэгдэл: мессеж, захиалга, сэтгэгдэл, үнэлгээ (суваг тус бүрд тохируулах боломжтой)
  • Хогийн сав модуль - устгасан контент бичлэгүүдийг сэргээх боломжтой

codesaur экосистем

Raptor нь дараах codesaur packages-тэй хамтран ажиллана:

PackageЗориулалт
codesaur/http-applicationPSR-15 Application, Router, Middleware суурь
codesaur/dataobjectPDO суурьтай ORM (Model, LocalizedModel)
codesaur/templateTemplate engine wrapper
codesaur/http-clientHTTP client (OpenAI API дуудлага)
codesaur/containerPSR-11 Dependency Injection Container

2. Суулгах

Шаардлага

  • PHP 8.2.1+
  • Composer
  • MySQL or PostgreSQL
  • PHP extensions: ext-gd, ext-intl

Composer ашиглан суулгах

composer create-project codesaur/raptor my-project

Composer-ийн setup-env скрипт (create-project, composer install, composer update бүрт ажиллана):

  1. .env.example файлыг .env руу автоматаар хуулна (.env байхгүй бол)
  2. RAPTOR_JWT_SECRET нууц түлхүүрийг автоматаар үүсгэнэ (зөвхөн байхгүй, хоосон, эсвэл placeholder хэвээр байвал - бодит secret-ийг хэзээ ч дарж солихгүй)

Хэрэв .env файл үүсээгүй бол cp docs/conf.example/.env.example .env командаар гараар хуулж, RAPTOR_JWT_SECRET утгыг өөрөө тохируулна.

Гараар суулгах

git clone https://github.com/codesaur-php/Raptor.git my-project
cd my-project
composer install

composer install дээрх setup-env скриптийг ажиллуулж .env-ийг автоматаар үүсгэнэ.


3. Тохиргоо

.env файлын бүх тохиргоонуудын тайлбар:

Орчин ба Апп

# Орчны горим: development эсвэл production
CODESAUR_APP_ENV=development

# Аппликейшний нэр
CODESAUR_APP_NAME=raptor

# Цагийн бүс (заавал биш)
#CODESAUR_APP_TIME_ZONE=Asia/Ulaanbaatar
  • development горимд алдааг дэлгэцэн дээр харуулахын зэрэгцээ logs/code.log файлд бичнэ
  • production горимд зөвхөн logs/code.log файлд бичнэ

Өгөгдлийн сан

RAPTOR_DB_HOST=localhost
RAPTOR_DB_NAME=raptor
RAPTOR_DB_USERNAME=root
RAPTOR_DB_PASSWORD=
RAPTOR_DB_CHARSET=utf8mb4
RAPTOR_DB_COLLATION=utf8mb4_unicode_ci
RAPTOR_DB_PERSISTENT=false
  • Шинэ орчинд хоосон өгөгдлийн санг developer өөрөө заавал урьдчилж үүсгэнэ - Raptor зөвхөн бэлэн сан руу холбогддог, санг өөрөө үүсгэдэггүй (жишээ нь MySQL дээр: CREATE DATABASE raptor CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;)
  • Харин сан доторх бүх хүснэгт болон анхны seed өгөгдлийг (permission, role, орчуулга, цэс, жишээ контент) Raptor анх ажиллах үедээ Model классуудаараа автоматаар үүсгэнэ
  • Хүснэгтүүдийг гараар үүсгэж болохгүй - бүтэц нь зөрсөн хүснэгт дээр код ажиллахгүй

JWT (JSON Web Token)

RAPTOR_JWT_ALGORITHM=HS256
RAPTOR_JWT_LIFETIME=2592000
RAPTOR_JWT_SECRET=auto-generated
#RAPTOR_JWT_LEEWAY=10
  • RAPTOR_JWT_SECRET - Composer-ийн скриптээр автоматаар 128 тэмдэгт (64 байт hex) үүсгэнэ
  • RAPTOR_JWT_LIFETIME - Токений хүчинтэй хугацаа секундээр (2592000 = 30 хоног)
  • RAPTOR_JWT_LEEWAY - Серверийн цагийн зөрөөг зөвшөөрөх хугацаа

WAF Compatibility (mod_security)

RAPTOR_WAF_BODY_ENCODING=true
  • RAPTOR_WAF_BODY_ENCODING - true (default) үед csrfFetch() form талбаруудыг base64-аар кодолж, mod_security маягийн WAF-д POST body доторх HTML/JS-төстэй rich-text харагдахгүй болгоно; BodyEncodingMiddleware server тал дээр decode хийнэ. Body-inspection хийдэг WAF-гүй хост дээр false болго. Дэлгэрэнгүйг CLAUDE.md-ийн "Shared Hosting / WAF Compatibility" хэсгээс үз.

Session cookie-ийн хугацааг Raptor SessionMiddleware дотроос 30 хоног болгож тохируулдаг (session_set_cookie_params(...)) - энэ нь зөвхөн client талын cookie бөгөөд практик дээр админ browser хаасан ч удаан нэвтэрсэн хэвээр үлддэг нь батлагдсан. Харин server талын session файлын цэвэрлэгээ (session.gc_maxlifetime) нь Raptor-аар бус host-ийн php.ini-аар удирдагдана; session file-ийг найдвартай хадгалж хугацаанд нь цэвэрлэдэг байлгахыг хүсвэл host бүрд түүнийг тохируулна - SESSION-LIFETIME.md-г үз.

"Яагаад миний PUT/DELETE хүсэлт browser дээр POST болж харагдаж байна вэ?"

Энэ нь алдаа биш, зориудаар. DevTools -> Network нээгээд method="PUT" (эсвэл PATCH/DELETE) гэсэн dashboard form илгээхэд хүсэлт POST-оор гарахыг харна. csrfFetch() эдгээр verb-ийг зориудаар POST болгож, жинхэнэ verb-ийг X-HTTP-Method-Override request header-аар дамжуулдаг - учир нь олон shared host (cPanel/LiteSpeed + mod_security) PUT/PATCH/DELETE-г PHP ажиллахаас өмнө web-server түвшинд блоклодог. Server тал дээр MethodOverrideMiddleware тэр header-ийг уншиж, routing-аас өмнө жинхэнэ method-ийг сэргээдэг тул GET_PUT('/news/{id}') нь PUT handler-руугаа хэвийн очно.

DevTools -> Network -> (хүсэлт) -> Headers дотроос юу болж буйг шалгах:

  • Request method: POST (tunnel)
  • X-HTTP-Method-Override: PUT - route хүлээж авах жинхэнэ verb
  • X-Body-Encoding: base64 - body encoding асаалттай үед байна; form body нь уншигдах HTML биш, base64-аар харагдана (энэ нь бас зориуд - доороос үз)

URL болон JSON хариу нь жинхэнэ PUT-тэй яг ижил тул дараагийн ямар ч хэсэг өөрчлөгдөхгүй.

Body encoding-г унтраах

Хост чинь body-inspection хийдэг WAF-гүй бөгөөд raw form body-г харах/шалгахыг хүсвэл:

  1. Site-wide: .envRAPTOR_WAF_BODY_ENCODING=false болго. Тэгвэл Controller::template() нь <meta name="waf-body-encoding" content="0"> гаргаж, csrfFetch() encode хийхээ болино. (Server талын decode нь header-gated тул огт ажиллахгүй - аль ч тохиолдолд аюулгүй.)
  2. Custom layout: <meta name="waf-body-encoding"> tag нь энэ флагийг browser-т дамжуулах цорын ганц суваг. Shipped dashboard.html-ийг ашиглахгүй бол түүнийг заавал оруул, эс бөгөөс =false тохиргоо client дээр чимээгүй үл хэрэгсэгдэнэ.
  3. Нэг удаагийн raw хүсэлт: csrfFetch()-д per-call opt-out байхгүй. Нэг хүсэлтийг verb болон body-той нь хувиргалгүй илгээх бол энгийн fetch()-ийг ашигла - гэхдээ CSRF-тэй route-д X-CSRF-TOKEN header-ийг өөрөө нэм (getCsrfToken()). Энэ нь голдуу dashboard-аас гадуурх / external endpoint-д зориулагдсан; dashboard route-уудад csrfFetch()-ийг илүүд үз.

Тэмдэглэл: method override (verb -> POST хувиргалт)-д унтраах switch байхгүй - үргэлж асаалттай ч override header байхгүй бол no-op тул хэзээ ч унтраах шаардлагагүй. Endpoint руу жинхэнэ PUT/DELETE verb-ээр хүрэхийн тулд хост тэр verb-ийг зөвшөөрдөг байх ёстой бөгөөд csrfFetch()-аас өөр client (жишээ: энгийн fetch()) ашиглах хэрэгтэй.

И-мэйл

RAPTOR_MAIL_FROM=noreply@codesaur.domain
#RAPTOR_MAIL_FROM_NAME="Raptor Notification"
#RAPTOR_MAIL_REPLY_TO=

# Transport: brevo (анхдагч), smtp, mail
#RAPTOR_MAIL_TRANSPORT=brevo
#RAPTOR_MAIL_BREVO_APIKEY=

# SMTP тохиргоо (transport=smtp үед)
#RAPTOR_SMTP_HOST=smtp.gmail.com
#RAPTOR_SMTP_PORT=465
#RAPTOR_SMTP_USERNAME=
#RAPTOR_SMTP_PASSWORD=
#RAPTOR_SMTP_SECURE=ssl
  • send() нь RAPTOR_MAIL_TRANSPORT-оос хамааран transport сонгоно (brevo/smtp/mail)

OpenAI

#RAPTOR_OPENAI_API_KEY=sk-your-api-key-here
  • moedit editor-ийн AI товчинд ашиглагдана

Зургийн optimize

RAPTOR_CONTENT_IMG_MAX_WIDTH=1920
RAPTOR_CONTENT_IMG_QUALITY=90
  • CMS-д зураг upload хийхэд GD extension ашиглан optimize хийнэ

Cloudflare Turnstile

#RAPTOR_TURNSTILE_SITE_KEY=
#RAPTOR_TURNSTILE_SECRET_KEY=
  • Заавал биш: тохируулаагүй бол Turnstile widget харагдахгүй, сервер талын шалгалт алгасна
  • SpamProtectionTrait ашиглан нийтийн формуудад CAPTCHA шалгалт хийнэ

Discord мэдэгдэл

#RAPTOR_DISCORD_WEBHOOK_URL=https://discord.com/api/webhooks/...
  • Заавал биш: хоосон эсвэл тохируулаагүй бол мэдэгдэл илгээхгүй
  • DiscordNotifier сервис системийн үйл явдлын мэдэгдэлд ашиглана

Серверийн тохиргоо

Анхаар: web серверийн document root нь заавал public_html/ байх ёстой, project root биш. Зөвхөн public_html/-ийг web-ээр үйлчлүүлэхээр зориулсан; бусад бүх зүйл (application/, protected/, database/, vendor/, .env, logs/, ...) түүний нэг шатнаас дээр байрладаг бөгөөд URL-аар хүрэшгүй байх ёстой. Docroot-ийг project root руу чиглүүлбэл эх код, .env нууц утгууд, upload хийсэн файл, session өгөгдөл бүгд ил гарна. Энэ ганц дүрэм нь server-аас үл хамаарах үндсэн хамгаалалт (Apache, Nginx адил) - .htaccess / nginx deny дүрмүүд нь зөвхөн яг энэ буруу тохиргооны үеийн нэмэлт fallback. Shared hosting дээр домэйний document root-ийг .../public_html болго; доорх жишээ тохиргоонууд аль хэдийн ингэж тохируулсан.

Apache болон Nginx серверийн жишээ тохиргоонууд docs/conf.example/ хавтаст байна:

ФайлТайлбар
.env.exampleОрчны тохиргооны лавлагаа
.htaccess.exampleApache URL rewrite болон HTTPS redirect
.nginx.conf.exampleNginx серверийн блок (HTTP, HTTPS, PHP-FPM)

CI/CD

Framework нь 2 GitHub Actions workflow-тэй:

CI (.github/workflows/ci.yml)

Repo-д анхнаасаа орсон default workflow. Push болон pull request бүрт код чанарын шалгалт хийнэ:

  • composer validate --strict - composer.json шалгах
  • PHP syntax check - бүх .php файлын синтакс
  • Merge conflict markers - <<<<<<<, =======, >>>>>>> илрүүлэх
  • Debug statements - var_dump, dd, print_r анхааруулга
  • composer dump-autoload --strict-psr - autoload шалгах

Deploy (.github/workflows/deploy.yml)

Нэгдсэн deploy workflow, 3 job-той: FTP, SSH, болон Windows Server self-hosted runner. Job бүр зөвхөн шаардлагатай secrets/variables тохируулсан үед ажиллана. Тохируулсан бүх job-ууд зэрэг (parallel) ажиллана.

Доорх A / B / C нь энэ workflow-ийн job-ууд бөгөөд shared hosting, VPS, cloud VM, dedicated, Windows Server гээд бараг бүх орчныг хамарна. D нь workflow-оос гаднах, зөвхөн A/B/C-гийн аль нь ч сервер лүү хүрч чадахгүй онцгой орчны fallback.

Ажиллах дараалал:

Push to main -> CI workflow ажиллана -> Амжилттай бол -> Deploy workflow эхэлнэ
                                     -> Амжилтгүй бол -> Deploy хийгдэхгүй

Deploy workflow нь workflow_run trigger ашиглан CI workflow-н дүнг хүлээнэ. CI амжилттай дуусвал (conclusion == 'success') deploy эхэлнэ. CI fail болвол deploy skipped болно - алдаатай код серверт очихгүй. Deploy-ийн secrets/variables тохируулаагүй бол (жишээ: developer clone) бүх job чимээгүй алгасагдана.

A) FTP Deploy

FTP хандалттай дурын серверт (shared hosting, VPS, dedicated). Settings -> Secrets and variables -> Actions -> Secrets хэсэгт дараах secret-үүдийг нэмнэ:

SecretТайлбарЖишээ
FTP_HOSTСерверийн FTP хаягftp.example.com
FTP_USERNAMEFTP хэрэглэгчийн нэрuser@example.com
FTP_PASSWORDFTP нууц үг
FTP_SERVER_DIRСерверийн зорьсон хавтас/

B) SSH Deploy

SSH хандалттай Linux серверт (VPS, cloud VM, dedicated). Settings -> Secrets and variables -> Actions -> Secrets хэсэгт дараах secret-үүдийг нэмнэ:

SecretТайлбарЖишээ
SSH_HOSTСерверийн хаягexample.com эсвэл 1.2.3.4
SSH_USERNAMESSH хэрэглэгчийн нэрdeploy
SSH_KEYSSH private key (id_rsa агуулга бүтнээр)
SSH_DEPLOY_DIRСерверийн зорьсон хавтас/var/www/myproject
SSH_PORT(заавал биш) SSH порт, анхдагч: 2222

C) Windows Self-hosted Runner Deploy

  1. Windows Server дээр self-hosted runner суулгах:
    • Settings -> Actions -> Runners -> New self-hosted runner -> Windows
    • Runner-г Windows service болгон бүртгэж, сервер restart хийхэд автомат асдаг болгоно
  2. Settings -> Secrets and variables -> Actions -> Variables хэсэгт дараах variable нэмнэ:
VariableТайлбарЖишээ
DEPLOY_PATHСерверийн project хавтасC:\xampp\htdocs\myproject
  1. PHP болон Composer серверийн system PATH-д байх ёстой.

D) cPanel Git Deploy (fallback - зөвхөн A/B/C-гийн аль нь ч боломжгүй үед)

Дээрх гурван зам бол стандарт бөгөөд cPanel хосттой байлаа ч гэсэн FTP (A) эсвэл SSH (B) хандалт нээлттэй л бол тэдгээрийг ашиглана - cPanel дээр байршсан гэдэг нь дангаараа энэ D замыг сонгох шалтгаан биш.

Харин GitHub Actions-ийн аль ч job сервер лүү хүрч чадахгүй онцгой орчин цөөн ч гэсэн байдаг: SSH/Terminal хаалттай, гаднаас FTP холбогдох боломжгүй cPanel shared hosting. Ийм орчны нэг бодит жишээ нь Монгол Улсын Үндэсний Дата Төвийн төрийн байгууллагуудын веб порталд зориулсан shared hosting юм. Зөвхөн ийм тохиолдолд cPanel-ийн өөрийн Git + cron дээр суурилсан scaffold-ийг ашиглана:

ФайлҮүрэг
docs/conf.example/.cpanel.yml.exampleRepo root-д .cpanel.yml нэрээр хуулна - cPanel Git deploy task list
docs/conf.example/auto-deploy.sh.exampledeploy/auto-deploy.sh болгон хуулж cron-оор ажиллуулна

Бүрэн заавар: docs/mn/CPANEL.md

Анхаарах: Deploy workflow нь CI (ci.yml) байхыг шаарддаг. CI workflow-г устгасан бол deploy trigger хийгдэхгүй.

Deploy хийгдэхгүй файлууд

  • .env - Серверт гараар үүсгэж тохируулна
  • Runtime хавтаснуудын агуулга - cache/, logs/, protected/, public_html/public/, database/migrations/ хавтаснууд guard файлуудтайгаа (.htaccess г.м.) deploy хийгдэж серверт үүснэ, харин доторх runtime агуулгыг нь (кэш, лог, upload файл, migration SQL) deploy хэзээ ч upload хийхгүй, дарахгүй, устгахгүй. Deploy зам бүр үүнийг өөр өөрийн механизмаар хангадаг тул deploy.yml-ийн гурван шүүлтүүрийн жагсаалт зориудаар ялгаатай - "жигдлэхээсээ" өмнө тэндхийн comment-уудыг уншина уу.
  • docs/, tests/ - Зөвхөн хөгжүүлэлтийн зориулалттай
  • vendor/ - Workflow дотор composer install/update --no-dev ажиллуулж build хийнэ

4. Архитектур

Хоёр давхаргат бүтэц

public_html/index.php (Entry point)
|
|-- /dashboard/* -> Dashboard\Application (Админ панель)
|    |-- Middleware: ErrorHandler -> MethodOverride -> BodyEncoding -> Session -> JWT -> Container -> Localization -> Settings (CSRF нь per-route)
|    |-- Routers: Login, Users, Organization, RBAC, Localization, Contents, Messages, Comments, Logs, Template, Shop, Development, Migration
|    \-- Controllers -> Templates -> HTML Response
|
\-- /* -> Web\Application (Нийтийн вэб сайт)
     |-- Middleware: ExceptionHandler -> Container -> Session -> Localization -> Settings
     |-- Router: WebRouter (/, /page, /news, /contact, /products, /order, /search, /sitemap, /rss, /session/language, /session/contact-send, /session/order, /session/news/{id}/comment, /session/product/{id}/review, ...)
     \-- Controllers -> Templates -> HTML Response

Request-ийн дамжих урсгал

Browser -> index.php -> .env -> ServerRequest
  -> Application сонгох (URL path-аар)
    -> Middleware chain (дарааллаар)
      -> Router match
        -> Controller::action()
          -> Model (DB)
          -> FileTemplate (codesaur/template) -> render()
            -> HTML Response -> Browser

Директорийн бүтэц

Raptor нь MVC pattern-г баримталдаг ч модульчилсан (package-by-feature) зохион байгуулалттай: модуль бүр өөрийн Controller, Model, темплейтүүдийг нэг хавтаст хамт агуулдаг бөгөөд тэдгээрийг тусдаа давхаргын директорт (top-level Models/, Controllers/, Views/) салгадаггүй. Модуль нэмэх, устгах нь нэг хавтсыг хуулах, устгахтай адил энгийн.

application/ дотор хоёр апп бий: dashboard/ (удирдлагын самбарын application - web-ийн хэрэглэдэг хуваалцсан суурь модулиуд болох Controller, middleware, model-ууд ч энд байрлана), web/ (нийтийн вэбийн application). Апп түвшний директорийн бүдүүвчийг үндсэн README.md-ийн "Directory Structure" хэсгээс харна уу. Модуль бүрийн хавтасны байршил, ангиудыг 6-р бүлгийн тухайн модулийн хэсэгт баримтжуулсан.

vendor/-оос бусад бүх директор хөгжүүлэгчийн мэдэлд. composer create-project-оор татсаны дараа application/, public_html/, database/, tests/, docs/, тохиргооны файлууд бүгд таны төслийн хэсэг болж, хэрэгцээ шаардлагадаа тааруулан бүрэн өөрчлөх, устгах, шинээр бичих боломжтой. Тусдаа "framework core" гэсэн давхарга байхгүй - application/ дотор dashboard/, web/ гэсэн хоёр апп байх бөгөөд хоёулаа таны төслийн энгийн код. Үндсэн (default) codebase нь хөгжүүлэгчийн нийтлэг хэрэгцээг хангасан суурь тул өөрийн нарийвчилсан хэрэгцээ шаардлагаа кодод шууд шингээгээрэй. Зөвхөн vendor/* packages нь Composer-ээр удирдагдах dependency тул гар хүрэхгүй (composer update-ээр шинэчилнэ).


5. Middleware Pipeline

Middleware бол PSR-15 стандартын дагуу request/response-г боловсруулах давхаргууд юм. Бүртгэгдсэн дараалал чухал!

PDO холболт нь public_html/index.php entry point дотор \Dashboard\DatabaseConnection::connect()-ээр нэг л удаа үүсэн request-ийн pdo attribute хэлбэрээр Application руу дамждаг.

Dashboard Middleware

#MiddlewareЗориулалт
1ErrorHandlerАлдааг JSON/HTML хэлбэрээр хариулна
2MethodOverrideMiddlewareX-HTTP-Method-Override-аас PUT/PATCH/DELETE-г сэргээнэ (WAF verb-block-ийн шийдэл). Session/routing-аас өмнө ажиллаж жинхэнэ verb-ийг бүх давхаргад харагдуулна
3BodyEncodingMiddlewareX-Body-Encoding-той ирсэн form талбаруудыг base64-аас decode хийнэ (WAF body-inspection-ийн шийдэл)
4SessionMiddlewarePHP session эхлүүлж удирдна
5JWTAuthMiddlewareJWT шалгаж User объект үүсгэнэ
6ContainerMiddlewareDI Container-г inject хийнэ
7LocalizationMiddlewareХэл, орчуулгыг тодорхойлно
8SettingsMiddlewareСистемийн тохиргоог inject хийнэ

CsrfMiddleware нь app-wide pipeline-д биш - router дээр mutating route бүрд per-route наагдана (6.20-г үз).

Web Middleware

#MiddlewareЗориулалт
1ExceptionHandlerTemplate ашиглан алдааны хуудас рендерлэнэ
2ContainerMiddlewareDI Container
3SessionMiddlewareSession (хэл хадгалах)
4LocalizationMiddlewareОлон хэл
5SettingsMiddlewareТохиргоо (logo, title, footer)

Database driver сонголт

Driver сонголт .env доторх RAPTOR_DB_DRIVER хувьсагчаар хийгдэнэ (mysql эсвэл pgsql). \Dashboard\DatabaseConnection::connect() түүнийг уншиж тохирох PDO instance үүсгэж буцаана:

# MySQL (default)
RAPTOR_DB_DRIVER=mysql

# PostgreSQL
RAPTOR_DB_DRIVER=pgsql

6. Модулиуд

6.1 Authentication (Нэвтрэлт)

Классууд: LoginRouter, LoginController, JWTAuthMiddleware, SessionMiddleware, User

  • JWT + Session хосолсон authentication
  • Login / Logout / Forgot password / Signup
  • Нууц үг сэргээх токен нэг удаагийн хэрэглээтэй: амжилттай сольсны дараа deactivateById()-ээр идэвхгүй болдог (устгагдахгүй) - админы хүсэлтүүдийн жагсаалтад used / expired / ready гэсэн 3 төлөвт харагдана
  • Байгууллага сонгох (олон байгууллагатай хэрэглэгч)
  • JWT нь $_SESSION['RAPTOR_JWT'] дотор хадгалагдана
  • User объект нь profile, organization, RBAC permissions агуулна

6.2 User (Хэрэглэгч)

Классууд: UsersRouter, UsersController, UsersModel

  • Хэрэглэгчийн CRUD (Create, Read, Update, Deactivate/soft delete)
  • Нууц үг bcrypt hash ашиглан хадгална
  • Profile мэдээлэл: username, email, phone, first_name, last_name
  • Avatar зураг upload

6.3 Organization (Байгууллага)

Классууд: OrganizationRouter, OrganizationController, OrganizationModel, OrganizationUserModel

  • Байгууллагын CRUD
  • Хэрэглэгч-байгууллагын холбоос удирдлага
  • Нэг хэрэглэгч олон байгууллагад харьяалагдах боломжтой
  • Topbar байгууллага солих dropdown: олон байгууллагатай хэрэглэгч topbar-ийн brand хэсгээс шууд солино (10-аас олон бол хайлтын шүүлтүүр гарна)
  • system_coder аль ч идэвхтэй байгууллага руу шилжинэ - хандах эрх рольоос гарна, гишүүнчлэлийн мөр үүсгэхгүй

6.4 RBAC (Эрхийн удирдлага)

Классууд: RBACRouter, RBACController, RBAC, Roles, Permissions, RolePermissions, UserRole

  • Role (дүр) үүсгэх, удирдах
  • Permission (эрх) үүсгэх, удирдах
  • Role-Permission хамаарал
  • User-Role оноох
  • Controller дотроос эрх шалгах:
// Хэрэглэгч system байгууллага дээр "admin" дүртэй эсэх
$this->isUser('system_admin');

// Хэрэглэгч "news_edit" эрхтэй эсэх
$this->isUserCan('news_edit');

6.5 Files (Файл)

Классууд: FileRouter, FileController, FilesController, FilesModel, ProtectedFilesController

  • Файл upload (native JS, FormData)
  • Зураг optimize хийх (GD)
  • Файлыг модуль/хүснэгтээр ангилах
  • MIME type тодорхойлох
  • Protected файл (зөвхөн нэвтэрсэн хэрэглэгчдэд, authorizeRead() hook)

6.6 Content - News (Мэдээ)

Классууд: NewsController, NewsModel

  • Мэдээний CRUD (бүрмөсөн устгах, Хогийн савд нөөцлөх)
  • Нүүр зураг upload
  • Хавсралт файлууд
  • Нийтлэх огноо удирдах
  • Үзэлтийн тоо (read_count)
  • moedit editor ашиглан контент засварлах
  • Жишиг дата цэвэрлэх: seed дата устгаж ID=1-ээс эхлүүлэх (reset() метод)

6.7 Content - Pages (Хуудас)

Классууд: PagesController, PagesModel

  • Хуудасны CRUD (бүрмөсөн устгах, Хогийн савд нөөцлөх), хялбаршуулсан нэг формтой интерфэйс (type wizard хасагдсан)
  • Parent-child бүтэц (олон түвшний навигацийн меню)
  • position талбараар эрэмбэлэх
  • type талбар: content (анхдагч), nav (эцэг/навигац хуудас - "Эцэг хуудас" switch ашиглан үүсгэнэ)
  • Эцэг хуудас (хүүхэдтэй хуудас) засах үед контент талбарууд (description, content, link, featured) нуугдана
  • is_featured талбар: Footer-д онцлох холбоос (хуудас эцэг болоход автоматаар 0 болно)
  • link талбар: URL эсвэл локал зам, frontend + backend шалгалттай (isValidLink())
  • read() хамгаалалт: нийтлэгдсэн эсэх, эцэг хуудас эсэх, link redirect
  • SEO slug үүсгэх (generateSlug)
  • Файл хавсаргах
  • Жишиг дата цэвэрлэх: seed дата устгаж ID=1-ээс эхлүүлэх (reset() метод)

6.8 Content - References (Лавлагаа)

Классууд: ReferencesController, ReferencesModel

  • Лавлагааны хүснэгтүүд (key-value хэлбэрийн)
  • Олон хэлтэй (LocalizedModel)
  • Динамик хүснэгтийн нэр

6.9 Content - Settings (Тохиргоо)

Классууд: SettingsController, SettingsModel, SettingsMiddleware

  • Системийн ерөнхий тохиргоо (олон хэлтэй)
  • Сайтын гарчиг, лого, тайлбар
  • Favicon, Apple Touch Icon
  • Холбоо барих мэдээлэл (утас, имэйл, хаяг)
  • Footer мэдээлэл (copyright, социал холбоосууд)
  • SettingsMiddleware нь тохиргоог request attributes-д inject хийнэ

6.10 Localization (Олон хэл)

Классууд: LocalizationRouter, LocalizationController, LanguageModel, TextModel, LocalizationMiddleware

  • Хэл нэмэх / засах / устгах
  • Орчуулгын текст удирдах (key -> value)
  • Session дээр суурилсан хэл сонголт
  • Template дотор {{ 'key'|text }} ашиглах

6.11 Log (Лог)

Классууд: LogsRouter, LogsController, Logger

  • PSR-3 стандартын лог систем
  • Өгөгдлийн санд лог хадгалах
  • Лог түвшин: emergency, alert, critical, error, warning, notice, info, debug
  • Server request metadata автоматаар бүртгэх
  • Хэрэглэгчийн мэдээлэл автоматаар бүртгэх
  • Error log таб (system_coder хэрэглэгчид) - PHP error.log файлыг Хандалтын протокол хуудаснаас шууд харах

6.12 Mail (И-мэйл)

Классууд: Mailer

  • send() нь .env-ийн RAPTOR_MAIL_TRANSPORT-оос хамааран brevo/smtp/mail сонгоно
  • HTML форматтай мессеж, CC/BCC, хавсралт дэмжинэ

6.13 Template (Dashboard UI)

Классууд: TemplateRouter, TemplateController, DashboardTrait, MenuModel, FileController

  • Dashboard layout рендерлэлт DashboardTrait::dashboardTemplate() ашиглан
  • Sidebar цэс олон хэл, эрх, parent/child бүтэцтэй (MenuModel)
  • Цэс удирдлагын CRUD (нэмэх, засах, идэвхгүй болгох)
  • Файл upload, шалгалт, зураг optimize FileController суурь классаар
  • SweetAlert2, motable, moedit зэрэг JS компонентууд
  • Responsive Bootstrap 5 дизайн

6.14 Shop (Дэлгүүр)

Классууд: ProductsController, OrdersController, ReviewsController, ShopRouter (products + orders + reviews нэгдсэн router), ProductsModel, ProductOrdersModel, ReviewsModel

  • Бүтээгдэхүүний CRUD (бүрмөсөн устгах, Хогийн савд нөөцлөх), slug үүсгэх, хураангуй гаргах
  • Бүтээгдэхүүний талбарууд: үнэ, хямдралын үнэ, SKU, barcode, хэмжээ, өнгө, нөөц, ангилал, онцлох, үнэлгээ зөвшөөрөх
  • Захиалгын удирдлага (products_orders хүснэгт) - хэрэглэгчийн мэдээлэл, статус хянах
  • Бүтээгдэхүүний үнэлгээ, одтой үнэлгээ (1-5), бичмэл сэтгэгдэл
  • Үнэлгээ products-view дотор харагдана (web болон dashboard)
  • Web бүтээгдэхүүний хуудсанд media gallery (thumbnail strip + том preview)
  • Жишиг дата анхны ачааллаар автоматаар үүсгэгдэнэ
  • Шинэ захиалга, статус өөрчлөлт, үнэлгээний PSR-14 event суурьтай мэдэгдэл
  • Шинэ захиалгын админ имэйл мэдэгдэл (toggle + хаяг тохируулах, system_coder эрхтэй)

6.15 Reviews (Бүтээгдэхүүний үнэлгээ)

Классууд: ReviewsController, ReviewsModel (dashboard, ShopRouter-аар бүртгэгдсэн), ShopController::reviewSubmit() (web)

  • Бүтээгдэхүүний хуудсан дээрх нийтийн үнэлгээний форм (review=1 үед)
  • Одтой үнэлгээ (1-5), бичмэл сэтгэгдэл
  • Зочин хэрэглэгч нэр, имэйлээ бичнэ (имэйл заавал биш)
  • SpamProtectionTrait ашиглан спам хамгаалалт (honeypot, HMAC, rate limiting, Turnstile)
  • Дундаж үнэлгээ, тоо бүтээгдэхүүний жагсаалтын карт дээр харагдана
  • Dashboard: products-view дотор үнэлгээний жагсаалт, устгах боломжтой
  • Dashboard: products-index толгой хэсгээс үнэлгээний жагсаалт руу очих линк
  • Badge: шинэ үнэлгээ info (усан цэнхэр) badge-ээр products sidebar дээр харагдана
  • Админ имэйл мэдэгдэл (toggle + хаяг тохируулах, system_coder эрхтэй, анхдагч: идэвхгүй)
  • Web талаас /session/product/{id}/review-ээр үнэлгээ илгээнэ

6.16 Event систем & Мэдэгдэл

Классууд: EventDispatcher, ListenerProvider, ContentEvent, UserEvent, OrderEvent, DevRequestEvent, DiscordListener

  • PSR-14 Event Dispatcher систем - шууд Discord дуудлагыг орлосон
  • Event классууд: ContentEvent, UserEvent, OrderEvent, DevRequestEvent
  • ListenerProvider нь listener-үүдийг бүртгэнэ (одоогоор DiscordListener)
  • DiscordListener нь бүх төрлийн event-д Discord webhook мэдэгдэл илгээнэ
  • Controller-ууд $this->dispatch(new ContentEvent(...)) helper-ээр event дамжуулна
  • DiscordNotifier нь админы нэр, dashboard URL-г хадгална (ContainerMiddleware-д inject хийгдсэн)
  • Мэдэгдлийн төрлүүд: хэрэглэгч бүртгүүлсэн, хэрэглэгч зөвшөөрсөн, шинэ захиалга, захиалгын статус өөрчлөлт, контентийн үйлдлүүд (нэмэх, засах, устгах, нийтлэх)
  • Өнгөт Discord embed мессеж
  • RAPTOR_DISCORD_WEBHOOK_URL орчны хувьсагчаар тохируулна
  • Webhook URL тохируулаагүй эсвэл listener байхгүй бол чимээгүй алгасна

6.17 Development (Хөгжүүлэлтийн хэрэгсэл)

Классууд: DevelopmentRouter, DevRequestController, DevRequestModel, DevResponseModel

  • Хөгжүүлэлтийн хүсэлт хянах систем (хүсэлт илгээх, хариулах, түүх харах)
  • application/dashboard/development/ хавтаст байрлана (Dashboard\Development namespace)
  • Нэвтэрсэн бүх хэрэглэгч хүсэлт үүсгэж, зөвхөн өөрийн үүсгэсэн болон өөрт хуваарилагдсан хүсэлтийг харах, хариулах, устгах боломжтой
  • system_development эрхтэй хэрэглэгч бүх хүсэлтийг харах, хариулах, устгах бүрэн эрхтэй

6.18 Site Service (Web)

Классууд: SeoController

  • Хуудас, мэдээ, бүтээгдэхүүн дундаас бүтэн текст хайлт
  • Хүнд ээлтэй sitemap хуудас, шатлалтай хуудасны бүтэцтэй
  • XML sitemap (/sitemap.xml) хайлтын системүүдэд
  • RSS 2.0 feed (/rss) сүүлийн мэдээ, бүтээгдэхүүнтэй
  • robots.txt - Хайлтын системийн бот удирдлага public_html/-д агуулагдана

robots.txt

public_html/robots.txt файл нь хайлтын системийн ботуудыг удирдана:

  • Зөвшөөрөгдсөн: Googlebot, Bingbot, YandexBot, Baiduspider
  • Хаагдсан: SEO scraper-ууд (MJ12bot, SemrushBot, AhrefsBot, DotBot, Bytespider, PetalBot)
  • AI ботууд: Анхдагчаар зөвшөөрөгдсөн (GPTBot, ClaudeBot гэх мэт). Хаахыг хүсвэл тухайн мөрийг uncomment хийнэ
  • Dashboard: /dashboard/ бүх ботоос хаагдсан
  • Sitemap: Sitemap: мөрийг өөрийн домэйн хаягаар солино
Sitemap: https://example.com/sitemap.xml

6.19 Спам хамгаалалт

Классууд: SpamProtectionTrait

  • Honeypot нууц талбарын илрүүлэлт
  • HMAC токен цаг хугацааны хамт шалгах
  • Үйлдэл тус бүрийн хурд хязгаарлалт (login 2s, signup 5s, forgot 10s)
  • Формын хугацаа дуусах шалгалт (1 цагийн дотор)
  • Бөглөх хурдны доод хязгаар (1 секунд)
  • Cloudflare Turnstile CAPTCHA дэмжлэг (.env дотор RAPTOR_TURNSTILE_SECRET_KEY тохируулсан үед идэвхжинэ)
  • Линк спам шүүлтүүр (хэт олон URL агуулсан текстийг хаана)
  • Нэвтрэх, бүртгүүлэх, нууц үг сэргээх, холбоо барих, сэтгэгдэл, үнэлгээ, захиалгын формуудад ашиглагдана

6.20 CSRF хамгаалалт

Классууд: CsrfMiddleware

  • Per-route middleware (app-wide биш). Router дээр mutating route бүрд ->middleware([CsrfMiddleware::class])-аар наагдана (use Dashboard\CsrfMiddleware;)
  • Middleware нь зөвхөн шалгана: $_SESSION['CSRF_TOKEN']X-CSRF-TOKEN header-тэй тулгаж, зөрвөл 403 буцаана
  • GET/HEAD/OPTIONS хүсэлтүүд шалгалтгүйгээр дамжина (GET_POST/GET_PUT compound route-ийн GET талыг хамгаална)
  • Token нь login үед үүсэж $_SESSION['CSRF_TOKEN'] дотор хадгалагдана. Хуучин session-д fallback болгож Controller::template() (нэвтэрсэн хэрэглэгчид token байхгүй + session writable бол) үүсгэнэ
  • Token нь dashboard.html доторх <meta name="csrf-token"> tag-аар frontend-д хүрнэ (Controller::template() session-аас уншина)
  • Клиент тал (JS) нь csrfFetch() wrapper ашиглан X-CSRF-TOKEN header-аар дамжуулна
  • Шинэ модуль нэмэхэд: mutating route бүрд ->middleware([CsrfMiddleware::class]) нэмнэ (автомат биш); зөвхөн login routes exempt. Клиент талд бүх state-changing хүсэлтэд fetch() биш csrfFetch() ашиглана

6.21 Database Migration (Өгөгдлийн сангийн шилжүүлэг)

Классууд: MigrationRunner, MigrationController, MigrationRouter, MigrationSecurityScanner

  • SQL файл дээр суурилсан, зөвхөн урагшлах (forward-only) migration систем
  • Файлын систем дээр state хадгалагдана (tracking хүснэгт байхгүй)
  • database/migrations/ нь git-ignored - per-environment upload
  • Per-user folder: {userId}-{username}/ дотор pending файл, {userId}-{username}/ran/ дотор амжилттай ажилласан файл
  • Coder dashboard-аас .sql upload хийнэ (max = min(10 MB, php.ini post_max_size, upload_max_filesize)), apply дарвал ажиллаж дараагийн file-аа ran/ руу зөөнө
  • Apply үед MigrationSecurityScanner нь sensitive хүснэгт (users, rbac_*, organizations*, localization_language, raptor_menu) болон DCL (GRANT/REVOKE/CREATE-DROP-ALTER USER)-д хандсан pattern илрүүлж soft warning гаргана - coder CONFIRM бичиж баталгаажуулна
  • Advisory lock (GET_LOCK / pg_try_advisory_lock) зэрэгцээ apply-аас хамгаална
  • dashboard_log-д бүх upload/apply/delete үйлдлийг SHA-256 hash, statement тоо, warning тоотойгоор бичнэ
  • Зөвхөн system_coder role-той хэрэглэгчид хандах боломжтой
  • Эцэг database/.htaccess (deny from all) хамгаалалт SQL файлуудад шууд хандахыг хаана

6.22 Messages (Холбоо барих мессеж)

Классууд: MessagesController, MessagesModel (dashboard), ContactController (web)

  • Нийтийн холбоо барих форм (/contact), спам хамгаалалттай
  • Холбоо барих формын мессежүүдийг өгөгдлийн санд хадгална
  • Dashboard интерфэйс: мессежүүдийг харах, удирдах
  • Мессежийн дэлгэрэнгүйг modal цонхонд харуулна
  • Бүрмөсөн устгах, Хогийн савд нөөцлөх (soft delete/идэвхгүй болгохыг орлосон)
  • Шинэ мессежийн event суурьтай мэдэгдэл (PSR-14 listener-ээр Discord)
  • Админ имэйл мэдэгдэл (toggle + хаяг тохируулах, system_coder эрхтэй)
  • Web талын ContactController нь формыг харуулах болон /session/contact-send-ээр илгээхийг удирдана

6.23 Comments (Мэдээний сэтгэгдэл)

Классууд: CommentsController, CommentsModel (dashboard), NewsController::commentSubmit() (web)

  • Мэдээний хуудсан дээрх нийтийн сэтгэгдлийн форм
  • 1 түвшний хариулт (parent_id ашиглан дээд түвшний сэтгэгдэлд хариулах)
  • Зочин хэрэглэгч нэр, имэйлээ бичнэ
  • Нэвтэрсэн хэрэглэгчийн нэр/имэйл профайлаас автоматаар бөглөгдөнө
  • SpamProtectionTrait ашиглан спам хамгаалалт (honeypot, HMAC, rate limiting, Turnstile)
  • Dashboard: news-view дотор сэтгэгдлийн жагсаалт, хариулах, устгах боломжтой
  • Dashboard: news-index толгой хэсгээс сэтгэгдлийн жагсаалт руу очих линк
  • Badge: шинэ сэтгэгдэл info (усан цэнхэр) badge-ээр news sidebar дээр харагдана
  • Бүрмөсөн устгах, Хогийн савд нөөцлөх (soft delete/идэвхгүй болгохыг орлосон)
  • Админ имэйл мэдэгдэл (toggle + хаяг тохируулах, system_coder эрхтэй, анхдагч: идэвхгүй)
  • Web талаас /session/news/{id}/comment-ээр сэтгэгдэл илгээнэ

6.24 Badge систем (Sidebar Badge)

Классууд: Dashboard\Badge\BadgeController, Dashboard\Badge\BadgeRouter, Dashboard\Badge\AdminBadgeSeenModel (application/dashboard/badge/)

  • Sidebar цэсний зүйлс дээр модуль тус бүрийн уншаагүй үйлдлийн тоог өнгөт badge-ээр харуулна
  • *_log хүснэгтүүдээс уншина - тусдаа event хүснэгт шаардахгүй
  • Multi-tenant: orgScopedModules() жагсаасан модулийн badge-ийг харж буй админы байгууллагаар хязгаарлана - бичлэгийн байгууллагаар (log context-ийн record_organization_id) шүүж, байхгүй бол үйлдэгчийн байгууллага руу fallback хийнэ; system_coder болон системийн байгууллагаар нэвтэрсэн админ (isSystemWideViewer()) бүх байгууллагыг харна
  • Badge өнгө: ногоон (create), цэнхэр (update), улаан (delete)
  • Модуль бүрт 3 хүртэл badge, зүүнээс баруун тийш ногоон-цэнхэр-улаан дарааллаар
  • Админы эрхээр шүүж (PERMISSION_MAP), өөрийн үйлдлийг хасна
  • Шинэ хэрэглэгчид 30 хоногийн lookback
  • Manual, migration-д файлын тоон дээр суурилсан badge (лог бус)
  • JS: initSidebarBadges() dashboard.js дотор хуудас ачаалахад badge татаж рендерлэнэ

6.25 Dashboard Home

Классууд: HomeRouter, SearchController, WebLogStatsController, WebLogStats

  • Dashboard нүүр хуудас системийн ерөнхий мэдээлэлтэй
  • Topbar түргэн icon-ууд (хайлт | хэл | загвар): хайлтын modal (Ctrl+K) - мэдээ, хуудас, бүтээгдэхүүн, захиалга, хэрэглэгч, байгууллага, хөгжүүлэлтийн хүсэлт, мессеж, сэтгэгдэл, үнэлгээнээс (RBAC шүүлтүүртэй - эх сурвалж бүр модулийнхаа index permission эсвэл мөрийн түвшний шүүлтээр хамгаалагдана); хэл солих dropdown (session-д хадгалагдана); цайвар/бараан загварын dropdown (reload-гүй шууд)
  • Вэб зочилсон статистик: график, шилдэг хуудас/мэдээ/бүтээгдэхүүн, IP хаяг
  • Системийн *_log хүснэгтүүдийн статистик (өнөөдөр/долоо хоног/нийт)
  • web_log_cache хүснэгт гүйцэтгэлийг хурдасгахад ашиглана

6.26 Dashboard Manual (Гарын авлага)

Классууд: ManualRouter, ManualController

  • Бүх гарын авлагын HTML файлуудыг модулиар бүлэглэн жагсаана
  • Тодорхой гарын авлагыг харуулна, хэлний fallback англи руу
  • Файлууд: application/dashboard/manual/ хавтаст {name}-manual-{lang}.html форматтай

6.27 AI Helper (moedit)

Классууд: AIHelper

  • moedit WYSIWYG editor-ийн OpenAI API интеграци
  • HTML горим: контент сайжруулалт (Bootstrap 5 компонент) - модель RAPTOR_OPENAI_MODEL (.env, default gpt-5-mini)
  • Vision горим: зургаас текст таних (OCR) - модель RAPTOR_OPENAI_VISION_MODEL (.env, default gpt-5.1)
  • Endpoint: POST /dashboard/content/moedit/ai
  • .envRAPTOR_OPENAI_API_KEY шаардлагатай

6.28 Seed болон анхдагч дата

Классууд: PermissionsSeed, RolePermissionSeed, MenuSeed, TextInitial, ReferenceInitial, NewsSamples, PagesSamples, ProductsSamples

  • Шинэ суулгалтад өгөгдлийн сангийг Model __initial() методоор автоматаар дүүргэнэ
  • Эрхүүд: system_ угтвартай 18+ системийн эрх
  • Role-ууд: coder, admin, manager, editor, viewer - эрхийн оноолттой
  • Цэс: 4 хэсэгтэй dashboard sidebar (Contents, Shop, System, Coder - сүүлийнх нь зөвхөн system_coder-д), олон хэлтэй
  • Орчуулга: 100+ системийн UI keyword MN/EN хэлээр
  • Лавлагаа загварууд: 11+ и-мэйл загвар (нууц үг сэргээх, мэдэгдлүүд, захиалга) + Нөхцөл/Нууцлал
  • Жишиг дата: демо мэдээ (6), хуудас (14+), бүтээгдэхүүн (4) - dashboard-ийн "Reset" товчоор устгах боломжтой

6.29 Trash (Хогийн сав)

Классууд: TrashRouter, TrashController, TrashModel

  • Бүрмөсөн устгахаас өмнө устгасан бичлэгүүдийг JSON хэлбэрээр хадгална
  • Контент модулиудын хуучин soft delete (is_active=0) загварыг орлосон
  • 15 model-оос is_active багана хасагдсан; deactivateById() нь deleteById() болж солигдсон: News, Pages, Products, Orders, Reviews, Comments, Messages, Files, References, Settings, DevRequests, DevResponses, Menus, Texts, Languages
  • Users болон Organizations нь soft delete хэвээр хадгалагдсан (is_active багана хэвээр)
  • Dashboard интерфэйсээс устгасан бичлэгүүдийг харах, шалгах, удирдах
  • Сэргээх (Restore): бичлэгийг үндсэн хүснэгт рүү буцаах. Эхлээд анхны ID-аар оролдох (FK холбоосыг хадгалахын тулд), амжилтгүй бол auto-increment ID; UNIQUE талбар (slug, keyword, code, sku) давхцалтай бол админд ойлгомжтой алдаа буцаах; LocalizedModel-ийн _content мөрүүд хамт сэргээгдэнэ
  • Хоёр давхар аудит лог: сэргээх үйлдэл trash_log (бүрэн audit) ба trash бичлэгийн log_table баганаас уншсан channel-д аль алинд бичигдэнэ - энэ нь Logger Protocol-оор сэргээгдсэн record-ын view/update хуудсан дээр харагдана. Controller-ууд TrashModel::store()-руу log channel-ийн нэрийг шууд дамжуулна (жишээ: ReviewsController -> 'products', ReferencesController -> 'content')
  • Хогийн савыг бүрэн хоослох боломжтой
  • Зөвхөн system_coder дүртэй админ хандана

7. Template систем

Raptor нь codesaur/template package-ийн FileTemplate классыг ашиглана - Twig-ийн синтаксыг дуурайсан хөнгөн engine (бодитоор twig/twig library биш).

Суурь хувьсагчид

Controller дотроос template() дуудахад доорх хувьсагчид автоматаар нэмэгднэ:

ХувьсагчТайлбар
userНэвтэрсэн хэрэглэгчийн User объект (null байж болно)
indexScript path (subdirectory дэмжлэг)
localizationХэл, орчуулгын мэдээлэл
requestОдоогийн URL path

Custom filter-ууд (Controller-ээс бүртгэгдсэн)

FilterХэрэглээТайлбар
text{{ 'key'|text }}Орчуулгын текст авах
link{{ 'news'|link({'id': 5}) }}5-р мэдээний URL үүсгэх
basename{{ path|basename }}Файлын нэр гаргах (Web templates)

Twig-ийн дэмжигдэхгүй боломжууд

codesaur/template дотор дараах Twig pattern ажилладаггүй; жишигийн орлуулга ашиглана:

Twig (дэмжигдэхгүй)Орлуулга
{% for i in 1..5 %}{% for i in range(1, 5) %}
**, //байхгүй (*, / ашиглана)
is divisible by, is same asбайхгүй
loop.revindex, loop.parentбайхгүй
{% verbatim %}, {% include %}, {% extends %}байхгүй
|date(format='Y-m-d')|date('Y-m-d') (зөвхөн positional)

codesaur/template 4.1.0-аас хойш in / not in (membership), ends with, matches (regex), is even / is odd дэмжигдэнэ - жишээ: {% if type in ['image', 'video'] %}.

Жишээ

<!-- Орчуулга -->
<h1>{{ 'welcome'|text }}</h1>

<!-- Route link -->
<a href="{{ 'page'|link({'id': page.id}) }}">{{ page.title }}</a>

<!-- Хэрэглэгч шалгах (object method дуудлага дэмжигдэнэ) -->
{% if user is not null and user.can('system_content_index') %}
    <p>Сайн байна уу, {{ user.profile.first_name }}!</p>
{% endif %}

<!-- Хэл солих -->
{% for code, language in localization.language %}
    <a href="{{ 'language'|link({'code': code}) }}">{{ language.title }}</a>
{% endfor %}

8. Routing

Raptor нь codesaur/http-application package-ийн Router классыг ашиглана.

Route тодорхойлох

class MyRouter extends \codesaur\Router\Router
{
    public function __construct()
    {
        // GET маршрут
        $this->GET('/path', [Controller::class, 'method'])->name('route-name');

        // POST маршрут
        $this->POST('/path', [Controller::class, 'method'])->name('route-name');

        // PUT маршрут (бүтэн ресурс шинэчлэх)
        $this->PUT('/path/{uint:id}', [Controller::class, 'method'])->name('route-name');

        // PATCH маршрут (хэсэгчлэн шинэчлэх - нэг талбар, статус toggle)
        $this->PATCH('/path/{uint:id}/status', [Controller::class, 'method'])->name('route-name');

        // DELETE маршрут
        $this->DELETE('/path', [Controller::class, 'method'])->name('route-name');

        // GET + POST (форм)
        $this->GET_POST('/path', [Controller::class, 'method'])->name('route-name');

        // GET + PUT (засах форм)
        $this->GET_PUT('/path/{uint:id}', [Controller::class, 'method'])->name('route-name');
    }
}

Динамик параметрууд

PatternТайлбарЖишээ
{name}String параметр/page/{slug}
{uint:id}Unsigned integer/page/{uint:id}
{code}String (хэлний код)/language/{code}

Router бүртгэх

Application класс дотроос:

$this->use(new MyRouter());

Route нэрийн оновчлол

->name('route-name') зөвхөн route нэр бодитоор ашиглагдаж байгаа үед тавина:

  • Template дотор {{ 'route-name'|link }} хэлбэрээр
  • PHP controller дотор $this->redirectTo('route-name') хэлбэрээр

Нэрээр дуудагддаггүй route-д ->name() шаардлагагүй бөгөөд илүүдэл ачааллыг бууруулна.


9. Controller

Суурь Controller (Dashboard\Controller)

Бүх Controller-ууд Dashboard\Controller ангиас удамшина. Доорх боломжуудыг нийтлэг авна:

МетодТайлбар
$this->pdoPDO холболт
getUser()Нэвтэрсэн хэрэглэгч (User|null)
getUserId()Хэрэглэгчийн ID
isUserAuthorized()Нэвтэрсэн эсэх
isUser($role)RBAC дүр шалгах
isUserCan($permission)RBAC эрх шалгах
getLanguageCode()Идэвхтэй хэлний код
getLanguages()Бүх хэлний жагсаалт
text($key)Орчуулгын текст
template($file, $vars)Template объект
respondJSON($data, $code)JSON хариулт
redirectTo($route, $params)Redirect хийх
log($table, $level, $msg)Лог бичих
dispatch($event)PSR-14 event дамжуулах
generateRouteLink($name, $params)URL үүсгэх
getContainer()DI Container
getService($id)Service авах

Жишээ: Шинэ Controller бичих

namespace Dashboard\Products;

class ProductsController extends \Dashboard\Controller
{
    public function index()
    {
        // Эрх шалгах
        if (!$this->isUserCan('product_read')) {
            throw new \Error('Эрх хүрэлцэхгүй', 403);
        }

        // Model ашиглах
        $model = new ProductsModel($this->pdo);
        $products = $model->getRows();

        // Template рендерлэх
        $twig = $this->template(__DIR__ . '/index.html', [
            'products' => $products
        ]);
        $twig->render();
    }

    public function store()
    {
        $body = $this->getRequest()->getParsedBody();
        $model = new ProductsModel($this->pdo);
        $id = $model->insert($body);

        // Лог бичих - стандарт `record_id` түлхүүр ашиглах
        // (бичлэгийн харах/засах хуудсан дээрх Logger Protocol-д харагдана).
        $this->log('products', \Psr\Log\LogLevel::INFO, 'Бүтээгдэхүүн нэмлээ', [
            'action'    => 'create',
            'record_id' => $id
        ]);

        // JSON хариулт
        $this->respondJSON(['status' => 'success', 'id' => $id]);
    }
}

10. Model

Raptor нь codesaur/dataobject package-ийн Model классуудыг ашиглана.

Model (нэг хэлтэй)

use codesaur\DataObject\Column;
use codesaur\DataObject\Model;

class ProductsModel extends Model
{
    public function __construct(\PDO $pdo)
    {
        $this->setInstance($pdo);
        $this->setColumns([
           (new Column('id', 'bigint'))->primary(),
            new Column('name', 'varchar', 255),
            new Column('price', 'decimal', '10,2'),
           (new Column('is_active', 'tinyint'))->default(1),
            new Column('created_at', 'datetime'),
        ]);
        $this->setTable('products');
    }
}

LocalizedModel (олон хэлтэй)

use codesaur\DataObject\Column;
use codesaur\DataObject\LocalizedModel;

class CategoriesModel extends LocalizedModel
{
    public function __construct(\PDO $pdo)
    {
        $this->setInstance($pdo);

        // Үндсэн хүснэгт
        $this->setColumns([
           (new Column('id', 'bigint'))->primary(),
           (new Column('is_active', 'tinyint'))->default(1),
        ]);

        // Хэл тус бүрийн контент
        $this->setContentColumns([
            new Column('title', 'varchar', 255),
            new Column('description', 'text'),
        ]);

        $this->setTable('categories');
    }
}

Гол методууд

МетодТайлбар
insert($record)Бичлэг нэмэх
updateById($id, $record)ID-р шинэчлэх
deleteById($id)ID-р бүрмөсөн устгах (контент модулиудад)
deactivateById($id, $record)ID-р идэвхгүй болгох (Users/Organizations-ийн soft delete, мөн Forgot токеныг ашиглагдсаны дараа идэвхгүй болгоход)
getRowWhere($with_values)WHERE key=value хэлбэрийн нөхцөлөөр нэг мөр авах
getRow($condition)SELECT нөхцөлөөр нэг мөр авах
getRows($condition)SELECT нөхцөлөөр олон мөр авах
getName()Хүснэгтийн нэр авах

LocalizedModel өгөгдлийн бүтэц

LocalizedModel::getRows() буцаах бүтэц:

[
    1 => [
        'id' => 1,
        'is_active' => 1,
        'localized' => [
            'mn' => ['title' => 'Монгол гарчиг', 'description' => '...'],
            'en' => ['title' => 'English title', 'description' => '...'],
        ]
    ],
    // ...
]

11. Тест

Raptor нь PHPUnit 11 суурьтай unit болон integration тестүүдтэй.

Шаардлага

composer install   # phpunit dev dependency суулгах

Тест ажиллуулах

# Бүх тест
composer test

# Зөвхөн unit тест
composer test:unit

# Зөвхөн integration тест
composer test:integration

Тохиргоо

.env.testing файл нь тест орчны тохиргоог агуулна. Integration тест нь тусдаа test database ашиглана (жишээ: raptor12_test).

RAPTOR_DB_NAME=raptor12_test

Тестийн бүтэц

tests/
|-- bootstrap.php              # Тест орчин тохируулах
|-- Support/
|   |-- RaptorTestCase.php     # Unit тестийн суурь анги
|   \-- IntegrationTestCase.php # Integration тестийн суурь анги
|-- Unit/
|   |-- Authentication/
|   |   \-- UserTest.php       # User::is(), User::can() тест
|   |-- Controller/
|   |   \-- ControllerTextTest.php  # Controller::text() тест
|   \-- Migration/
|       \-- MigrationSecurityScannerTest.php  # Sensitive SQL pattern шалгалт
\-- Integration/
    |-- Model/
    |   |-- UsersModelTest.php          # Хэрэглэгчийн CRUD тест
    |   |-- OrganizationModelTest.php   # Байгууллагын тест
    |   \-- SignupModelTest.php         # Бүртгэлийн тест
    |-- RBAC/
    |   \-- RolesPermissionsTest.php    # RBAC seed шалгалт
    |-- Authentication/
    |   \-- JWTAuthTest.php             # JWT encode/decode тест
    \-- Migration/
        \-- MigrationRunnerIntegrationTest.php  # File-based migration runner тест

Тестийн онцлогууд

  • Transaction isolation - Integration тест бүр transaction дотор ажиллаж, дуусахад rollback хийнэ. Тест дата бодит database-д нөлөөлөхгүй
  • RaptorTestCase - Mock request, mock user үүсгэх helper-ууд (createAdmin(), createCoder(), createGuest())
  • IntegrationTestCase - Static PDO холболт (тест анги дотор дахин холбогдохгүй), auto database create

Шинэ тест бичих жишээ

namespace Tests\Unit;

use Tests\Support\RaptorTestCase;

class MyTest extends RaptorTestCase
{
    public function test_example(): void
    {
        $user = $this->createAdmin();
        $this->assertTrue($user->can('system_user_index'));
    }
}

12. Хэрэглээний жишээ

Шинэ Router нэмэх

  1. Router класс үүсгэх:
// application/dashboard/mymodule/MyModuleRouter.php
namespace Dashboard\MyModule;

class MyModuleRouter extends \codesaur\Router\Router
{
    public function __construct()
    {
        $this->GET('/dashboard/mymodule', [MyModuleController::class, 'index'])->name('mymodule');
        $this->GET_POST('/dashboard/mymodule/insert', [MyModuleController::class, 'insert'])->name('mymodule-insert');
    }
}
  1. composer.json дотор namespace бүртгэх:
{
    "autoload": {
        "psr-4": {
            "Dashboard\\MyModule\\": "application/dashboard/mymodule/"
        }
    }
}

Дараа нь autoloader-г шинэчлэх:

composer dump-autoload
  1. Dashboard\Application-ийн constructor дотор бусад $this->use(...) router бүртгэлүүдийн хажууд Router-аа бүртгэнэ:
// application/dashboard/Application.php  (__construct дотор)
$this->use(new MyModule\MyModuleRouter());  // Шинэ router

Web хуудас нэмэх

// application/web/WebRouter.php
$this->GET('/products', [HomeController::class, 'products'])->name('products');
// application/web/HomeController.php
public function products()
{
    $model = new ProductsModel($this->pdo);
    $products = $model->getRows(['WHERE' => "published=1 AND code='$code'"]);
    $this->webTemplate(__DIR__ . '/products.html', ['products' => $products])->render();
}

Database сонгох

Driver-г .env доторх RAPTOR_DB_DRIVER хувьсагчаар солино:

# MySQL (default)
RAPTOR_DB_DRIVER=mysql

# PostgreSQL руу шилжих
RAPTOR_DB_DRIVER=pgsql

\Dashboard\DatabaseConnection::connect() энэ утгыг уншиж тохирох PDO үүсгэнэ.


Дараагийн алхмууд

Энэ хуудсанд