<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: n0nag0n</title>
    <description>The latest articles on DEV Community by n0nag0n (@n0nag0n).</description>
    <link>https://dev.to/n0nag0n</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F998537%2F598111d3-c98e-4f9c-a6d8-3a11313dc426.jpeg</url>
      <title>DEV Community: n0nag0n</title>
      <link>https://dev.to/n0nag0n</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/n0nag0n"/>
    <language>en</language>
    <item>
      <title>Back Up Multiple Drives to Backblaze with Deduplication – Introducing b2-dedup</title>
      <dc:creator>n0nag0n</dc:creator>
      <pubDate>Sun, 18 Jan 2026 16:06:58 +0000</pubDate>
      <link>https://dev.to/n0nag0n/back-up-multiple-drives-to-backblaze-with-deduplication-introducing-b2-dedup-1c2f</link>
      <guid>https://dev.to/n0nag0n/back-up-multiple-drives-to-backblaze-with-deduplication-introducing-b2-dedup-1c2f</guid>
      <description>&lt;p&gt;Backing up terabytes of data across multiple drives, NAS boxes, or even different computers? You want everything in &lt;strong&gt;one safe, offsite place&lt;/strong&gt; without paying a fortune for redundant uploads or duplicate storage.&lt;/p&gt;

&lt;p&gt;That's exactly why I built &lt;a href="https://github.com/n0nag0n/b2-dedup" rel="noopener noreferrer"&gt;&lt;strong&gt;b2-dedup&lt;/strong&gt;&lt;/a&gt; — a parallel, streaming deduplicating uploader tailored for &lt;strong&gt;Backblaze B2&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;In this tutorial you'll learn:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Why Backblaze B2 is (in my opinion) the smartest choice for personal/large-scale backups vs. AWS S3, Azure Blob, etc.&lt;/li&gt;
&lt;li&gt;How deduplication across drives saves you time, bandwidth, and money&lt;/li&gt;
&lt;li&gt;Step-by-step setup and usage of b2-dedup&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why Backblaze B2 Beats S3, Azure Blob, and Most Alternatives (for Backup Use Cases)
&lt;/h2&gt;

&lt;p&gt;Backblaze B2 is purpose-built for simplicity and low cost — especially for "set it and forget it" backup scenarios.&lt;/p&gt;

&lt;p&gt;Here's a quick 2025–2026 comparison (based on published rates and common backup patterns):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Storage cost&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
B2 → ~$6/TB/month (recently adjusted from $5/TB; still extremely competitive)&lt;br&gt;&lt;br&gt;
AWS S3 Standard → ~$23/TB/month (first 50 TB tier)&lt;br&gt;&lt;br&gt;
Azure Blob Hot → similar ballpark to S3 (~$18–$23/TB)&lt;br&gt;&lt;br&gt;
→ B2 is roughly &lt;strong&gt;1/4 to 1/5 the price&lt;/strong&gt; for always-hot, instantly accessible storage.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Egress (downloads)&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
B2 → Free egress up to &lt;strong&gt;3× your monthly stored average&lt;/strong&gt; (and unlimited free to many CDNs/partners like Cloudflare, Fastly, etc.)&lt;br&gt;&lt;br&gt;
S3/Azure → $0.08–$0.09/GB after free tier — restore 1 TB and you're looking at ~$80+ just to get your data back.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Other gotchas&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No upload fees, delete penalties, minimum file sizes, or hidden API call charges that sting on large backups (B2 keeps Class A calls free; generous free tier on others).
&lt;/li&gt;
&lt;li&gt;S3-compatible API → works with rclone, restic, Veeam, etc.
&lt;/li&gt;
&lt;li&gt;No complex storage tiers/classes to accidentally get stuck in (unless you want Glacier/Archive for cold data).&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;For personal users, homelab hoarders, photographers/videographers, or small businesses doing offsite backups, &lt;strong&gt;B2 wins on predictable low cost + sane egress&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Shameless plug time&lt;/strong&gt; (you knew it was coming 😄):&lt;br&gt;&lt;br&gt;
I've personally used Backblaze since ~2017 (after CrashPlan killed their unlimited home service). I've backed up tens of terabytes reliably with zero drama. If you're new to B2, feel free to use my referral link — we both get a little credit:&lt;br&gt;&lt;br&gt;
👉 &lt;a href="https://secure.backblaze.com/r/01ub6m" rel="noopener noreferrer"&gt;&lt;strong&gt;Sign up for Backblaze here&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  What b2-dedup Does (and Why You Need It for Multi-Drive Backups)
&lt;/h2&gt;

&lt;p&gt;When you back up multiple drives (e.g., main PC SSD, external HDDs, media NAS), you often have &lt;strong&gt;tons of duplicate files&lt;/strong&gt; — same photos, same movies, same installers, same OS images across machines.&lt;/p&gt;

&lt;p&gt;Standard tools (rclone, Duplicati, etc.) usually deduplicate &lt;em&gt;within one backup job&lt;/em&gt;, but not &lt;em&gt;across entirely separate sources&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;b2-dedup&lt;/strong&gt; fixes that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Uses a local SQLite DB (&lt;code&gt;~/b2_dedup.db&lt;/code&gt;) to remember SHA-256 hashes of every file it has ever seen.&lt;/li&gt;
&lt;li&gt;When you point it at Drive #2, it skips anything already uploaded from Drive #1.&lt;/li&gt;
&lt;li&gt;Parallel uploads (default 10 workers, tunable) + streaming chunked uploads → low memory, high speed.&lt;/li&gt;
&lt;li&gt;Resumable — interrupted jobs pick up where they left off.&lt;/li&gt;
&lt;li&gt;Scan-only / dry-run modes for safety.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Result: One B2 bucket, many "drive-name" prefixes (e.g., &lt;code&gt;PC2025/&lt;/code&gt;, &lt;code&gt;MediaNAS/&lt;/code&gt;, &lt;code&gt;Laptop/&lt;/code&gt;) — but &lt;strong&gt;real storage usage is minimized&lt;/strong&gt; because duplicates aren't re-uploaded.&lt;/p&gt;
&lt;h2&gt;
  
  
  Step-by-Step Tutorial: Install &amp;amp; Use b2-dedup
&lt;/h2&gt;
&lt;h3&gt;
  
  
  1. Prerequisites
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Python 3.8+&lt;/li&gt;
&lt;li&gt;A Backblaze B2 account + bucket created&lt;/li&gt;
&lt;li&gt;B2 Application Key (KeyID + Application Key) — generate one with &lt;strong&gt;Read + Write&lt;/strong&gt; access to your bucket&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  2. Install
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/n0nag0n/b2-dedup.git
&lt;span class="nb"&gt;cd &lt;/span&gt;b2-dedup
pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; requirements.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  3. Authenticate
&lt;/h3&gt;

&lt;p&gt;Easiest way: Install the official &lt;code&gt;b2&lt;/code&gt; CLI and authorize it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;b2
b2 account authorize   &lt;span class="c"&gt;# follow prompts with your KeyID + App Key&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;b2-dedup will automatically use those credentials.&lt;/p&gt;

&lt;p&gt;(Alternatively, export env vars: &lt;code&gt;B2_KEY_ID&lt;/code&gt; and &lt;code&gt;B2_APPLICATION_KEY&lt;/code&gt;)&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Recommended Workflow for Multiple Drives
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;First drive (baseline)&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Optional: just scan &amp;amp; hash everything first (no upload)&lt;/span&gt;
python b2_dedup.py /mnt/primary-drive &lt;span class="nt"&gt;--drive-name&lt;/span&gt; PrimaryPC &lt;span class="nt"&gt;--bucket&lt;/span&gt; my-backup-bucket-123 &lt;span class="nt"&gt;--scan-only&lt;/span&gt;

&lt;span class="c"&gt;# Then do the real upload&lt;/span&gt;
python b2_dedup.py /mnt/primary-drive &lt;span class="nt"&gt;--drive-name&lt;/span&gt; PrimaryPC &lt;span class="nt"&gt;--bucket&lt;/span&gt; my-backup-bucket-123
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Second (or Nth) drive&lt;/strong&gt; — duplicates are skipped!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python b2_dedup.py /mnt/media-drive &lt;span class="nt"&gt;--drive-name&lt;/span&gt; MediaNAS &lt;span class="nt"&gt;--bucket&lt;/span&gt; my-backup-bucket-123 &lt;span class="nt"&gt;--workers&lt;/span&gt; 20
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pro tip: Use &lt;code&gt;--dry-run&lt;/code&gt; first to preview:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python b2_dedup.py /mnt/media-drive &lt;span class="nt"&gt;--drive-name&lt;/span&gt; MediaNAS &lt;span class="nt"&gt;--bucket&lt;/span&gt; my-backup-bucket-123 &lt;span class="nt"&gt;--dry-run&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  5. Useful Flags
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;--workers 25&lt;/code&gt; — more parallelism if your internet/upload can handle it&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--refresh-count&lt;/code&gt; — force re-count files (useful if source changed a lot)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--scan-only&lt;/code&gt; — build/populate the hash DB without touching B2&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  6. Where Files End Up in B2
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Everything under one bucket&lt;/li&gt;
&lt;li&gt;Prefix = &lt;code&gt;--drive-name&lt;/code&gt; (e.g., &lt;code&gt;PrimaryPC/Documents/report.docx&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Deduplication happens on content hash — identical files get stored only once, regardless of path/name.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Tips &amp;amp; Gotchas
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;The DB lives at &lt;code&gt;~/b2_dedup.db&lt;/code&gt; — back it up! (it's tiny, but losing it means re-hashing everything)&lt;/li&gt;
&lt;li&gt;If you rename drives or reorganize, just use a new &lt;code&gt;--drive-name&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;For very large initial scans, start with &lt;code&gt;--scan-only&lt;/code&gt; overnight&lt;/li&gt;
&lt;li&gt;Combine with rclone/Borg/restic for versioning if you need it — b2-dedup is purely for initial / incremental deduped uploads&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Wrap-Up
&lt;/h2&gt;

&lt;p&gt;With &lt;strong&gt;b2-dedup&lt;/strong&gt; + Backblaze B2 you get:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;One cheap, durable offsite location&lt;/li&gt;
&lt;li&gt;Cross-drive deduplication to slash upload time &amp;amp; storage bills&lt;/li&gt;
&lt;li&gt;Parallel, resumable, low-memory operation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I've been running similar setups for years — it's rock-solid for hoarding photos, videos, ISOs, and irreplaceable documents.&lt;/p&gt;

&lt;p&gt;Give it a spin, star the repo if you find it useful → &lt;a href="https://github.com/n0nag0n/b2-dedup" rel="noopener noreferrer"&gt;https://github.com/n0nag0n/b2-dedup&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Questions or want to contribute? Open an issue or PR!&lt;/p&gt;

&lt;p&gt;Happy (deduplicated) backing up! 🚀&lt;/p&gt;

</description>
      <category>python</category>
      <category>programming</category>
    </item>
    <item>
      <title>Supercharge Your PHP Projects with Flight's Native AI Integration in 2026</title>
      <dc:creator>n0nag0n</dc:creator>
      <pubDate>Sat, 17 Jan 2026 15:18:10 +0000</pubDate>
      <link>https://dev.to/n0nag0n/supercharge-your-php-projects-with-flights-native-ai-integration-in-2026-5eoo</link>
      <guid>https://dev.to/n0nag0n/supercharge-your-php-projects-with-flights-native-ai-integration-in-2026-5eoo</guid>
      <description>&lt;p&gt;Flight PHP keeps things delightfully simple while packing powerful tools for modern workflows. The dedicated &lt;a href="https://docs.flightphp.com/en/v3/learn/ai" rel="noopener noreferrer"&gt;AI &amp;amp; Developer Experience&lt;/a&gt; section in the official docs shows how Flight makes AI coding assistants shine—especially with built-in CLI commands via Runway that connect to LLMs and generate project-specific instructions for tools like GitHub Copilot, Cursor, Windsurf, and Antigravity (Gemini). This native support means your AI helper gets tailored context about your app's stack, conventions, and goals, leading to more accurate, relevant suggestions every time.&lt;/p&gt;

&lt;p&gt;A standout advantage: Flight's entire core codebase is tiny—easily fitting inside most AI context windows (around 51k tokens including tests, far below limits like Claude's 200k+ or Gemini's massive capacities). Your AI can ingest the whole framework without truncation, leading to fewer hallucinations and better understanding of Flight's patterns compared to heavier frameworks.&lt;/p&gt;

&lt;p&gt;For new users, this lowers the entry barrier dramatically. For long-time Flight devs, it streamlines team consistency and speeds up iteration without reinventing wheels.&lt;/p&gt;

&lt;h2&gt;
  
  
  Start Fast: Use the Official Skeleton with Runway Built-In
&lt;/h2&gt;

&lt;p&gt;The easiest way to get AI integration running is the official &lt;a href="https://github.com/flightphp/skeleton" rel="noopener noreferrer"&gt;flightphp/skeleton&lt;/a&gt;. It comes pre-configured with Runway (Flight's CLI tool), predefined AI instruction files, and a solid project structure.&lt;/p&gt;

&lt;p&gt;Step-by-step for newcomers:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Ensure PHP 7.4+ is installed.&lt;/li&gt;
&lt;li&gt;In your terminal, run:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;composer create-project flightphp/skeleton my-flight-app
&lt;span class="nb"&gt;cd &lt;/span&gt;my-flight-app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This pulls in Flight core, Runway, and sets up folders like &lt;code&gt;app/&lt;/code&gt;, &lt;code&gt;public/&lt;/code&gt;, &lt;code&gt;config/&lt;/code&gt;, plus AI-ready files in &lt;code&gt;.github/&lt;/code&gt;, &lt;code&gt;.cursor/&lt;/code&gt;, etc.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Serve it locally:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;composer start
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or use PHP's built-in server: &lt;code&gt;php -S localhost:8000 -t public/&lt;/code&gt;. You're live at &lt;a href="http://localhost:8000" rel="noopener noreferrer"&gt;http://localhost:8000&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The skeleton is AI-friendly out of the box—predefined instructions help your IDE's AI understand the namespace structure, config loading, and more right away.&lt;/p&gt;

&lt;h2&gt;
  
  
  Set Up AI Credentials with &lt;code&gt;ai:init&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Runway powers the AI commands. First, connect your LLM provider:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;php runway ai:init
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It prompts you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Choose provider: 1 for OpenAI, 2 for Grok, 3 for Claude (supports any OpenAI-compatible API).&lt;/li&gt;
&lt;li&gt;Base URL (defaults to OpenAI's).&lt;/li&gt;
&lt;li&gt;Your API key.&lt;/li&gt;
&lt;li&gt;Model (e.g., gpt-4o, claude-3-opus).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Credentials save securely to your &lt;code&gt;config.php&lt;/code&gt; file in your project. &lt;/p&gt;

&lt;p&gt;Gemini support comes via Antigravity integration—instructions generate for &lt;code&gt;.gemini/GEMINI.md&lt;/code&gt;, letting Gemini-powered tools use the same context.&lt;/p&gt;

&lt;h2&gt;
  
  
  Generate Smart Instructions with &lt;code&gt;ai:generate-instructions&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;This is where the magic happens. Run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;php runway ai:generate-instructions
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Answer prompts about your project:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Description (e.g., "RESTful API for task management").&lt;/li&gt;
&lt;li&gt;Database (SQLite, MySQL, PostgreSQL?).&lt;/li&gt;
&lt;li&gt;Templating (Latte, Twig, none?).&lt;/li&gt;
&lt;li&gt;Security focus (yes/no for auth/validation emphasis).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Flight uses your LLM to craft detailed, project-specific instructions, then writes them to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;.github/copilot-instructions.md&lt;/code&gt; → GitHub Copilot&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;.cursor/rules/project-overview.mdc&lt;/code&gt; → Cursor&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;.windsurfrules&lt;/code&gt; → Windsurf&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;.gemini/GEMINI.md&lt;/code&gt; → Antigravity (Gemini)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These files feed context directly to your IDE's AI. Instead of vague suggestions, Copilot or Cursor knows you're using Flight routes, PDO for DB, JSON responses, and security middleware—leading to code that slots in perfectly, follows your conventions, and avoids common pitfalls.&lt;/p&gt;

&lt;p&gt;Rerun anytime (new features, stack changes) to keep instructions fresh. This reduces "re-explain the project" loops and boosts productivity across teams.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why This Matters: Backwards Compatibility and Longevity
&lt;/h2&gt;

&lt;p&gt;Flight's been around since 2011, and one core goal is rock-solid backwards compatibility. The docs repeatedly note it maintains compatibility wherever possible—v3 keeps most v2 patterns intact with minimal breaking changes (mostly output buffering tweaks for MVC alignment).&lt;/p&gt;

&lt;p&gt;This stability means AI tools trained on older Flight examples still work great today—no version-specific chaos like in faster-moving frameworks. Your prompts pull from years of consistent patterns, and the tiny core ensures full context in even mid-range models.&lt;/p&gt;

&lt;p&gt;Practical win: Prompt "Add a grouped admin route with auth middleware in Flight"—the AI references your instructions and Flight's enduring style for clean, compatible code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick Example: AI-Assisted Route in Skeleton
&lt;/h2&gt;

&lt;p&gt;With instructions generated, open &lt;code&gt;public/index.php&lt;/code&gt; (or a controller). Ask your in IDE AI Assistant: "Create a GET /todos route using PDO SQLite that returns JSON array of tasks."&lt;/p&gt;

&lt;p&gt;Expect output respecting your project's DB choice, JSON formatting, and error handling—often ready to commit with little tweaking.&lt;/p&gt;

&lt;p&gt;Runway bonus: &lt;code&gt;php runway routes&lt;/code&gt; lists all endpoints; &lt;code&gt;php runway generate:controller Todos&lt;/code&gt; scaffolds if needed.&lt;/p&gt;

&lt;p&gt;Flight's AI features (added in v3.16.0) make it a joy for rapid, reliable development. Grab the skeleton, init your creds, generate instructions, and watch your AI become a true co-pilot.&lt;/p&gt;

&lt;p&gt;What LLM setup are you running with Flight? Share in the comments.&lt;/p&gt;

&lt;p&gt;Stay cool,  &lt;/p&gt;

&lt;p&gt;n0nag0n&lt;/p&gt;

</description>
      <category>php</category>
      <category>webdev</category>
      <category>programming</category>
      <category>microframework</category>
    </item>
    <item>
      <title>2026 Best PHP Micro Frameworks: Slim, Flight, Fat-Free, and More!</title>
      <dc:creator>n0nag0n</dc:creator>
      <pubDate>Sun, 04 Jan 2026 05:51:06 +0000</pubDate>
      <link>https://dev.to/n0nag0n/2026-best-php-micro-frameworks-slim-flight-fat-free-and-more-3gmf</link>
      <guid>https://dev.to/n0nag0n/2026-best-php-micro-frameworks-slim-flight-fat-free-and-more-3gmf</guid>
      <description>&lt;p&gt;Hey everyone! It's that time again to dive into the world of PHP micro frameworks. With PHP continuing to power a massive chunk of the web (think WordPress, Facebook's backend roots, and countless APIs), micro frameworks remain a go-to for developers who want speed, simplicity, and scalability without the bloat of full-stack behemoths like Laravel or Symfony's extensive modularity. These lightweight champs are perfect for RESTful APIs, microservices, or even quick prototypes that might grow into something bigger.&lt;/p&gt;

&lt;p&gt;For 2026, we're seeing steady evolution: some frameworks are getting snappier updates, others are holding strong, and a few are fading into the sunset. I'll focus on the top contenders—Slim, Flight, Fat-Free Framework (F3), and Phalcon (Micro) — with honorable mentions for emerging players.&lt;/p&gt;

&lt;p&gt;As a quick note: I maintain the Flight framework, so yeah, I'm a bit biased. But honestly, its zero-dependency design, blazing speed, and recent features make it legitimately awesome for modern PHP dev. I chat with new devs often about how they found Flight and how much they love it! I'll try to keep things fair, though—let's compare based on popularity (GitHub stars as of early 2026), features, performance (drawing from TechEmpower benchmarks where available), and ease of use.&lt;/p&gt;

&lt;h2&gt;
  
  
  Slim PHP
&lt;/h2&gt;

&lt;p&gt;Slim has been a staple in the PHP micro world for years, and in 2026, it continues to shine for its reliability and community support. It's minimalist at its core, focusing on routing and HTTP handling while letting you bolt on whatever else you need.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Key Features&lt;/strong&gt;: PSR-7 compliant, middleware support, easy integration with templating engines like Twig or ORMs like Eloquent. No built-in bloat—just the essentials.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pros&lt;/strong&gt;: Mature ecosystem, great docs, and a huge community for troubleshooting. It's battle-tested for production APIs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cons&lt;/strong&gt;: You might end up adding dependencies for advanced stuff, which can make it feel less "micro" over time.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Popularity&lt;/strong&gt;: 12.2k GitHub stars—still the leader in raw numbers, with steady growth.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Performance&lt;/strong&gt;: Solid in benchmarks; in TechEmpower's Fortunes test (DB + templating), it hits around 73k RPS. Not the absolute fastest, but consistent.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Latest Release&lt;/strong&gt;: v4.15.1 (November 2025), with PHP 8.5 support added.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Getting started is straightforward:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Psr\Http\Message\ResponseInterface&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nc"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Psr\Http\Message\ServerRequestInterface&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nc"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Slim\Factory\AppFactory&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;require&lt;/span&gt; &lt;span class="k"&gt;__DIR__&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="s1"&gt;'/vendor/autoload.php'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nv"&gt;$app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;AppFactory&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="nv"&gt;$app&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'/hello/{name}'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Request&lt;/span&gt; &lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Response&lt;/span&gt; &lt;span class="nv"&gt;$response&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;array&lt;/span&gt; &lt;span class="nv"&gt;$args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$args&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'name'&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="nv"&gt;$response&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getBody&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"Hello, &lt;/span&gt;&lt;span class="nv"&gt;$name&lt;/span&gt;&lt;span class="s2"&gt;!"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$response&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nv"&gt;$app&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you're coming from a more structured background, Slim feels like home.&lt;/p&gt;

&lt;h2&gt;
  
  
  Flight PHP
&lt;/h2&gt;

&lt;p&gt;Alright, let's talk Flight—my personal favorite and, in my opinion, the rising star that's now fully in orbit for 2026. Since taking over maintenance, we've pushed hard on features without sacrificing its core: being the fastest, simplest way to build PHP apps. Zero dependencies mean you can drop it into any project, and its extensibility lets it scale effortlessly.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Key Features&lt;/strong&gt;: Lightning-fast routing, built-in middleware, dependency injection, route groups, and aliases. Fully unit-tested, with support for everything from simple scripts to complex APIs. Recent updates include better PHP 8.5 compatibility and refined return types for cleaner code.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pros&lt;/strong&gt;: Insanely fast even without async frameworks like swoole (up to 190k RPS in plaintext benchmarks—about 50% faster than Slim on average), beginner-friendly, and no setup hassle. It's extensible without forcing you into a box, making it perfect for modern, lean development. It also has a major focus on backwards compatibility meaning your projects from years ago will work for years to come!&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cons&lt;/strong&gt;: Smaller ecosystem than giants like Slim, so you might build some integrations yourself (though the community is growing fast).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Popularity&lt;/strong&gt;: 2.8k GitHub stars—a solid jump from last year, overtaking Fat-Free and gaining traction in dev chats on Matrix and X. Active commits into 2026 show it's alive and kicking.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Performance&lt;/strong&gt;: Tops the charts among micro frameworks. TechEmpower shows it outperforming competitors in raw speed, especially in plaintext and JSON tests where its minimal overhead shines.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Latest Release&lt;/strong&gt;: v3.17.4 (December 2025), with ongoing tweaks for performance and compatibility.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here's a quick example that highlights its simplicity:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="k"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;'vendor/autoload.php'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nc"&gt;Flight&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'GET /hello/@name'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Hello, &lt;/span&gt;&lt;span class="nv"&gt;$name&lt;/span&gt;&lt;span class="s2"&gt;! Welcome to Flight—the fastest way to fly in PHP."&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nc"&gt;Flight&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;start&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If speed and control are your priorities, Flight is unbeatable. We've seen it adopted for everything from IoT backends to high-traffic APIs, and the feedback has been stellar. Give it a spin—you won't go back.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fat-Free Framework (F3)
&lt;/h2&gt;

&lt;p&gt;F3 (Fat-Free) is the veteran here, around since 2009, and it's still going strong in 2026 with its modular, all-in-one approach. It's more feature-packed than pure micros but keeps the footprint small.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Key Features&lt;/strong&gt;: Built-in ORM, templating, caching, and plugins for things like Markdown, geodata, and more. No Composer required if you don't want it—just unzip and go.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pros&lt;/strong&gt;: Balances lightness with power; great for apps needing a bit more out of the box without full-stack weight.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cons&lt;/strong&gt;: Docs assume some PHP savvy, and its growth has plateaued compared to newer players.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Popularity&lt;/strong&gt;: 2.7k GitHub stars—loyal fanbase, but not exploding like Flight.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Performance&lt;/strong&gt;: Respectable; around 40k RPS in Fortunes benchmarks. Efficient for its feature set.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Latest Release&lt;/strong&gt;: v3.9.2 (December 2025).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example to get you routing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="k"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;'vendor/autoload.php'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nv"&gt;$f3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;\Base&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="nv"&gt;$f3&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'GET /hello/@name'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$f3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'Hello, '&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nv"&gt;$args&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'name'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="s1"&gt;'! F3 keeps it light and modular.'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nv"&gt;$f3&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;F3 is ideal if you want a micro framework that feels a tad more "framework-y."&lt;/p&gt;

&lt;h2&gt;
  
  
  Phalcon Micro
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Phalcon PHP&lt;/strong&gt; (Micro mode): Phalcon stands out as a unique high-performance framework delivered as a &lt;strong&gt;C-extension&lt;/strong&gt;, offering exceptional speed and low resource usage compared to pure-PHP solutions. While it's primarily a full-stack MVC framework, its &lt;code&gt;Phalcon\Mvc\Micro&lt;/code&gt; component makes it a powerful option for lightweight RESTful APIs and microservices—perfect when you need blazing performance without the overhead of traditional frameworks.

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Key Features&lt;/strong&gt;: Extremely fast routing, built-in response handling, collections for grouped routes, dependency injection, and full access to Phalcon's powerful components (like ORM, security, etc.) when needed.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pros&lt;/strong&gt;: One of the fastest PHP options available (thanks to compiled C code), low memory/CPU footprint, great for high-load APIs, and actively maintained with PHP 8+ support.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cons&lt;/strong&gt;: Requires installing a PHP extension (not zero-dependency like pure Composer packages), steeper learning curve for extension setup, and the micro mode is less "minimalist" than dedicated micro frameworks.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Popularity&lt;/strong&gt;: ~10.8k GitHub stars—still a strong, respected player with a dedicated community.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Performance&lt;/strong&gt;: Ranks well among the top in benchmarks due to its C-extension nature; ideal for throughput-heavy applications. Before PHP7 this was a HUGE advantage, but since PHP 7 and now 8, the gap closed significantly.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Latest Release&lt;/strong&gt;: v5.10.0 (December 2025), with ongoing fixes and improvements into late 2025/early 2026.
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Here's a simple micro example that shows how clean it can be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Phalcon\Mvc\Micro&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nv"&gt;$app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Micro&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// Define a simple route&lt;/span&gt;
&lt;span class="nv"&gt;$app&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'/hello/{name}'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$app&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$app&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;setJsonContent&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
        &lt;span class="s1"&gt;'message'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"Hello, &lt;/span&gt;&lt;span class="nv"&gt;$name&lt;/span&gt;&lt;span class="s2"&gt;! Powered by Phalcon Micro – the speed demon of PHP."&lt;/span&gt;
    &lt;span class="p"&gt;]);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$app&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nv"&gt;$app&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;handle&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Phalcon Micro is an excellent choice if raw performance is your top priority and you're okay with the extension-based approach. It's especially appealing for production-grade APIs that need to handle serious traffic efficiently. Give it a try if you're chasing those benchmark wins! 🚀&lt;/p&gt;

&lt;h2&gt;
  
  
  Honorable Mentions
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Leaf PHP&lt;/strong&gt;: A modern, modular take inspired by Laravel. 1.3k stars, with the "Black Pearl" release in September 2025. Great for Laravel fans wanting lighter weight—check it out if you like expressive syntax without the overhead.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lumen&lt;/strong&gt;: Still around with 7.6k stars, but archived since 2024 and no updates. If you're deep in Laravel, it might work, but I'd recommend migrating—performance lags (around 20k RPS in benchmarks).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Deprecated ones like Silex, BulletPHP, FuelPHP and Wolff are off the list entirely.&lt;/p&gt;

&lt;h2&gt;
  
  
  Comparisons and Verdict
&lt;/h2&gt;

&lt;p&gt;Here's a quick table for newbies (weighted toward ease and speed):&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Framework&lt;/th&gt;
&lt;th&gt;Community&lt;/th&gt;
&lt;th&gt;Simplicity&lt;/th&gt;
&lt;th&gt;Performance&lt;/th&gt;
&lt;th&gt;Ease of Use&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Slim&lt;/td&gt;
&lt;td&gt;High&lt;/td&gt;
&lt;td&gt;Medium&lt;/td&gt;
&lt;td&gt;High&lt;/td&gt;
&lt;td&gt;Medium&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Flight&lt;/td&gt;
&lt;td&gt;Medium&lt;/td&gt;
&lt;td&gt;Very High&lt;/td&gt;
&lt;td&gt;Very High&lt;/td&gt;
&lt;td&gt;Very High&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Fat-Free&lt;/td&gt;
&lt;td&gt;Low&lt;/td&gt;
&lt;td&gt;High&lt;/td&gt;
&lt;td&gt;High&lt;/td&gt;
&lt;td&gt;High&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Phalcon (Micro)&lt;/td&gt;
&lt;td&gt;Medium-High&lt;/td&gt;
&lt;td&gt;Medium&lt;/td&gt;
&lt;td&gt;High&lt;/td&gt;
&lt;td&gt;Medium&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Popularity&lt;/strong&gt;: Slim dominates stars, but Flight's growth is the story of 2026—active updates and community buzz make it feel fresh.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Simplicity&lt;/strong&gt;: Flight wins hands-down with its one-file vibe and no deps.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Performance&lt;/strong&gt;: Flight edges out with benchmark wins; Slim and F3 are close but carry a bit more overhead. Phalcon performs well but with a bit of overhead of installing the extension outside of composer.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scalability&lt;/strong&gt;: All handle it, but Flight's built-ins (middleware, DI) make extending painless.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In conclusion, for 2026, &lt;strong&gt;Flight PHP&lt;/strong&gt; is my top pick—and not just because I maintain it. Its speed, simplicity, and rapid evolution make it the ideal micro framework for everything from hobby projects to production beasts. Slim remains a safe, reliable choice, and F3 is great for feature-rich needs. If you're starting fresh, try Flight v3; the &lt;a href="https://docs.flightphp.com" rel="noopener noreferrer"&gt;docs&lt;/a&gt; are polished, and the community is welcoming. Give it a go or drop in on the &lt;a href="https://matrix.to/#/#flight-php-framework:matrix.org" rel="noopener noreferrer"&gt;Matrix&lt;/a&gt; or &lt;a href="https://discord.gg/Ysr4zqHfbX" rel="noopener noreferrer"&gt;Discord&lt;/a&gt; chat!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>php</category>
      <category>microframework</category>
    </item>
    <item>
      <title>Laravel vs. Flight: A Guide to Picking Your PHP Framework</title>
      <dc:creator>n0nag0n</dc:creator>
      <pubDate>Sat, 01 Mar 2025 03:11:26 +0000</pubDate>
      <link>https://dev.to/n0nag0n/laravel-vs-flight-a-guide-to-picking-your-php-framework-41g5</link>
      <guid>https://dev.to/n0nag0n/laravel-vs-flight-a-guide-to-picking-your-php-framework-41g5</guid>
      <description>&lt;p&gt;Hey there, PHP explorer! So, you’re stepping into the world of web development and trying to pick a framework that fits your vibe. Laravel’s the big name—think of it as the fully loaded SUV of PHP frameworks, packed with features and a bold presence. But lately, some devs (&lt;a href="https://www.reddit.com/r/laravel/comments/1iyyxk4/laravel_is_going_in_the_wrong_direction_imho/?rdt=54152" rel="noopener noreferrer"&gt;like on Reddit&lt;/a&gt;) are muttering that it’s getting a bit too fancy and commercial. Then there’s Flight Framework: the sleek, no-fuss scooter that gets you rolling fast. Let’s dive in and see which one feels right for your next project!&lt;/p&gt;

&lt;h2&gt;
  
  
  What’s the Deal with Laravel?
&lt;/h2&gt;

&lt;p&gt;Laravel’s been a fan favorite for ages, but with Laravel 12 hitting the scene on February 24, 2025, some folks are raising eyebrows. A &lt;a href="https://www.reddit.com/r/laravel/comments/1iyyxk4/laravel_is_going_in_the_wrong_direction_imho/?rdt=54152" rel="noopener noreferrer"&gt;Reddit thread&lt;/a&gt; recently popped off (over 1,100 upvotes!) with grumbles about new starter kits, third-party auth like WorkOS, and quirky stuff like Volt tossing PHP, HTML, and JS into a single-file mashup. The word is Laravel’s chasing investor bucks (cue the $57 million!) and leaving some coders dazed. If you’re just getting comfy with PHP, that might sound like more than you’re ready to tackle.&lt;/p&gt;

&lt;h2&gt;
  
  
  Flight: The Easygoing Alternative
&lt;/h2&gt;

&lt;p&gt;Flight Framework is like that laid-back pal who keeps it simple. It’s a micro-framework—light, quick, and free of extras you didn’t sign up for. Great for anyone who wants to build something cool (like an API) without navigating a labyrinth of files or dodging sales pitches. Let’s check it out with a quick example!&lt;/p&gt;

&lt;h2&gt;
  
  
  Building a Simple User API: Flight vs. Laravel
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Flight: Fast and Straightforward
&lt;/h3&gt;

&lt;p&gt;Grab Flight with this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;composer create-project flightphp/skeleton myproject
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Start the dev server:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;myproject
composer start
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You’re live at &lt;code&gt;localhost:8000&lt;/code&gt;. Open &lt;code&gt;app/routes.php&lt;/code&gt; and add:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nc"&gt;Flight&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'GET /users'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$users&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'id'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'name'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'Johnny Code'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'id'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'name'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'Jane Dev'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="nc"&gt;Flight&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$users&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Hit &lt;code&gt;/users&lt;/code&gt; in your browser, and bam—JSON user list, ready to roll!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Dependencies&lt;/strong&gt;: Just 4 production packages (&lt;code&gt;flightphp/core&lt;/code&gt;, &lt;code&gt;flightphp/runway&lt;/code&gt;, &lt;code&gt;symfony/translation&lt;/code&gt;, &lt;code&gt;tracy/tracy&lt;/code&gt;). Barely a handful! If you want zero dependencies, you can just install &lt;code&gt;flightphp/core&lt;/code&gt; and configure your environment yourself.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Files/Dirs&lt;/strong&gt;: Around 10-15—like &lt;code&gt;app/&lt;/code&gt;, &lt;code&gt;public/&lt;/code&gt;, and &lt;code&gt;routes.php&lt;/code&gt;. Easy to wrap your head around. If you want to simplify that, it's easy to just start from scratch on your own.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Heads-up: The skeleton’s pretty bare, so you might tweak a few things yourself. But it’s a clean slate to play with!&lt;/p&gt;

&lt;h3&gt;
  
  
  Laravel: The Whole Toolkit
&lt;/h3&gt;

&lt;p&gt;Install Laravel with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;composer create-project &lt;span class="nt"&gt;--prefer-dist&lt;/span&gt; laravel/laravel myproject
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Launch the server:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;myproject
php artisan serve
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add your route in &lt;code&gt;routes/api.php&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nc"&gt;Route&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'/users'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;response&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'id'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'name'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'Johnny Code'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'id'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'name'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'Jane Dev'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Visit &lt;code&gt;/api/users&lt;/code&gt;, and you’re set.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Dependencies&lt;/strong&gt;: Dozens! &lt;code&gt;laravel/framework&lt;/code&gt; drags in a crew—like &lt;code&gt;illuminate/*&lt;/code&gt;, &lt;code&gt;symfony/*&lt;/code&gt;, and more. It’s a party!&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Files/Dirs&lt;/strong&gt;: About 20-30, including &lt;code&gt;app/Console/&lt;/code&gt;, &lt;code&gt;database/&lt;/code&gt;, and &lt;code&gt;resources/&lt;/code&gt;. A lot to explore!&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Laravel hands you a ton right away—auth, database goodies—but it’s like getting a Swiss Army knife when you just need a spoon.&lt;/p&gt;

&lt;h2&gt;
  
  
  Flight vs. Laravel: The Lowdown
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Thing&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Flight (Scooter)&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Laravel (SUV)&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Learning Curve&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Smooth and chill, dive right in&lt;/td&gt;
&lt;td&gt;Steeper, more to figure out&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Speed&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Quick, low overhead&lt;/td&gt;
&lt;td&gt;Slower, big engine to run&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Dependencies&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;4—light and lean&lt;/td&gt;
&lt;td&gt;Dozens—pack a suitcase&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Files/Dirs&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;10-15—nice and tidy&lt;/td&gt;
&lt;td&gt;20-30—sprawling setup&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Vibe&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Free-spirited, no sales pressure&lt;/td&gt;
&lt;td&gt;Loaded, but with a pitch&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Flight’s like a blank sketchbook—you add what you want. Laravel’s more like a furnished loft—awesome if you need it all, but a lot to take in at first.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Flight Might Click?
&lt;/h2&gt;

&lt;p&gt;If you’re itching to build something small—like a blog API or a task tracker—Flight keeps it fun and fuss-free. No third-party auth headaches, no “upgrade to Pro” nudges. It’s open-source, community-driven, and lets you explore PHP without tripping over “magic” tricks. Sure, it skips built-in auth or an ORM, but that’s your chance to craft it your way!&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Laravel Still Shines?
&lt;/h2&gt;

&lt;p&gt;Got big dreams—like a team project or an enterprise app? Laravel’s got the goods with tons of tools and a massive community. Just brace yourself for a bit more of a climb to get the hang of it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Your Call!
&lt;/h2&gt;

&lt;p&gt;So, what’s your speed? Flight’s scooter for a quick, carefree spin, or Laravel’s SUV for the long road? If Laravel’s recent twists have you side-eyeing it (thanks, Reddit!), Flight could be your chill getaway. Give that API example a whirl—it’s five minutes tops—and see what sparks joy. Happy coding, and enjoy the PHP adventure!&lt;/p&gt;

</description>
      <category>php</category>
      <category>webdev</category>
      <category>programming</category>
    </item>
    <item>
      <title>2025 Best PHP Micro Frameworks: Slim, Flight, Fat-Free, Lumen, and More!</title>
      <dc:creator>n0nag0n</dc:creator>
      <pubDate>Thu, 27 Feb 2025 15:02:24 +0000</pubDate>
      <link>https://dev.to/n0nag0n/2025-best-php-micro-frameworks-slim-flight-fat-free-lumen-and-more-2naj</link>
      <guid>https://dev.to/n0nag0n/2025-best-php-micro-frameworks-slim-flight-fat-free-lumen-and-more-2naj</guid>
      <description>&lt;p&gt;Hey PHP fans! Welcome to 2025—a year where &lt;a href="https://www.php.net/" rel="noopener noreferrer"&gt;PHP&lt;/a&gt; continues to shine as the backbone of the web (sorry, haters, it’s not going anywhere!). If you’re building a slick API, a lightweight app, or just want to ditch the bloat of full-stack frameworks, micro frameworks are your ticket to coding bliss. Today, we’re diving into the top four PHP micro frameworks: &lt;a href="https://www.slimframework.com/" rel="noopener noreferrer"&gt;Slim PHP&lt;/a&gt;, &lt;a href="https://docs.flightphp.com/" rel="noopener noreferrer"&gt;Flight PHP&lt;/a&gt;, &lt;a href="https://fatfreeframework.com/" rel="noopener noreferrer"&gt;Fat-Free Framework (F3)&lt;/a&gt;, and &lt;a href="https://lumen.laravel.com/" rel="noopener noreferrer"&gt;Lumen&lt;/a&gt;—plus a few honorable mentions to keep things spicy. &lt;/p&gt;

&lt;p&gt;I’ll break down their popularity (with a special zoom-in on the past year), ease of getting started, and how they scale from "Hello World" to "Holy Complexity, Batman!" I’ll also toss in some fresh code snippets from their latest versions—no outdated stuff here! Oh, and watch for a certain framework that’s been quietly stealing the show lately (hint: it rhymes with "light"). Let’s dive in!&lt;/p&gt;

&lt;h2&gt;
  
  
  The Top Four: Slim, Flight, Fat-Free, and Lumen
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Slim PHP: The Lean, Mean Routing Machine
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://www.slimframework.com/" rel="noopener noreferrer"&gt;Slim PHP&lt;/a&gt; is like that reliable friend who always shows up on time—minimalist, focused, and ready to handle your HTTP requests with finesse. It’s a micro framework kingpin, loved for its simplicity and flexibility, especially when crafting RESTful APIs. &lt;a href="https://github.com/slimphp/Slim/releases" rel="noopener noreferrer"&gt;Slim 4&lt;/a&gt; (the latest as of 2025) keeps things lean with no third-party dependencies out of the box, but it’s extensible enough to grow with your project.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Popularity&lt;/strong&gt;: Slim’s been a staple for years, boasting a solid &lt;a href="https://github.com/slimphp/Slim" rel="noopener noreferrer"&gt;GitHub presence&lt;/a&gt; with 12.1k stars. In 2024, it held steady traction—not the explosive growth of newer players, but its community is active and reliable for devs who want control without chaos.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Simplicity&lt;/strong&gt;: Getting started is a breeze—install via &lt;a href="https://getcomposer.org/" rel="noopener noreferrer"&gt;Composer&lt;/a&gt;, define some routes, and you’re off. Scaling up? Add middleware or libs like &lt;a href="https://twig.symfony.com/" rel="noopener noreferrer"&gt;Twig&lt;/a&gt; or &lt;a href="https://laravel.com/docs/eloquent" rel="noopener noreferrer"&gt;Eloquent&lt;/a&gt; as needed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Example (Slim 4)&lt;/strong&gt;:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Psr\Http\Message\ResponseInterface&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nc"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Psr\Http\Message\ServerRequestInterface&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nc"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Slim\Factory\AppFactory&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;require&lt;/span&gt; &lt;span class="k"&gt;__DIR__&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="s1"&gt;'/vendor/autoload.php'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nv"&gt;$app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;AppFactory&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="nv"&gt;$app&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'/hello/{name}'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Request&lt;/span&gt; &lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Response&lt;/span&gt; &lt;span class="nv"&gt;$response&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;array&lt;/span&gt; &lt;span class="nv"&gt;$args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$args&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'name'&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="nv"&gt;$response&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getBody&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"Hello, &lt;/span&gt;&lt;span class="nv"&gt;$name&lt;/span&gt;&lt;span class="s2"&gt;!"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$response&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nv"&gt;$app&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run that, hit &lt;code&gt;/hello/PHP&lt;/code&gt;, and boom—Slim delivers. It’s simple, but for complex apps, you’ll need to bolt on extras yourself and the dependencies only grow from there.&lt;/p&gt;

&lt;h3&gt;
  
  
  Flight PHP: The Rising Star Ready to Soar
&lt;/h3&gt;

&lt;p&gt;Let’s talk about &lt;a href="https://docs.flightphp.com/" rel="noopener noreferrer"&gt;Flight PHP&lt;/a&gt;—the micro framework that’s been flapping its wings and stealing the spotlight in 2025! &lt;a href="https://github.com/flightphp/core/releases" rel="noopener noreferrer"&gt;Flight 3&lt;/a&gt; (the latest version) is fast, extensible, and so beginner-friendly it practically hands you a welcome mat. With zero dependencies and a focus on simplicity &lt;em&gt;and&lt;/em&gt; power, it’s the framework you didn’t know you needed until now. It can handle tiny one-off projects or complex projects with many requirements. New features like route groups, middleware, dependency injection handlers, and aliases added in 2024 have sent it rocketing past competitors in popularity. It also helps that the framework is 100% unit tested unlike some other competitors!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Popularity&lt;/strong&gt;: Flight’s &lt;a href="https://github.com/flightphp/core" rel="noopener noreferrer"&gt;GitHub stars&lt;/a&gt; just eclipsed Fat-Free’s in February 2025 (woo-hoo!), and its 2024 updates fueled a buzz that’s still growing. Devs on &lt;a href="https://x.com/search?q=flightphp" rel="noopener noreferrer"&gt;X&lt;/a&gt; are raving about its speed and fresh features—Flight’s the one to watch this year!&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Simplicity&lt;/strong&gt;: Install via composer with &lt;code&gt;composer require flightphp/core&lt;/code&gt;, or download and unzip the repo from, drop a few lines in an &lt;code&gt;index.php&lt;/code&gt; file, and you’re coding! It’s perfect for quick prototypes yet scales effortlessly with dependency injection and middleware for bigger builds.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Example (Flight 3)&lt;/strong&gt;:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="k"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;'vendor/autoload.php'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nc"&gt;Flight&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'GET /hello/@name'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Hello, &lt;/span&gt;&lt;span class="nv"&gt;$name&lt;/span&gt;&lt;span class="s2"&gt;! Welcome to Flight 3!"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nc"&gt;Flight&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;start&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Look at that—no fluff, just results! Flight’s lightweight core (faster than Slim by ~50% in &lt;a href="https://www.techempower.com/benchmarks/" rel="noopener noreferrer"&gt;TechEmpower benchmarks&lt;/a&gt;) and built-in goodies make it a dream for newbies and pros alike. Ready to take off with your next project? Flight’s calling your name!&lt;/p&gt;

&lt;h3&gt;
  
  
  Fat-Free Framework (F3): The Minimalist Veteran
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://fatfreeframework.com/" rel="noopener noreferrer"&gt;Fat-Free Framework&lt;/a&gt;, or F3, is the wise old sage of micro frameworks—around since 2009, it’s still kicking with a tiny 90KB footprint (though I fact checked it, and it's actually 412kb of PHP files!!!). It’s all about balance: lightweight yet packed with features like ORM, templating, and caching. F3’s modular design lets you pick and choose what you need, keeping your app lean.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Popularity&lt;/strong&gt;: With 2.6k &lt;a href="https://github.com/bcosca/fatfree" rel="noopener noreferrer"&gt;GitHub stars&lt;/a&gt;, F3 has a loyal following, though its 2024 growth was steady rather than meteoric. It’s a mature choice with a tight-knit community that’s always tinkering.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Simplicity&lt;/strong&gt;: Composer or no Composer required—just unzip and go from &lt;a href="https://fatfreeframework.com/" rel="noopener noreferrer"&gt;fatfreeframework.com&lt;/a&gt;. It’s beginner-friendly, but its flexibility shines when you dig into its plugins for complex projects.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Example (F3 3.9)&lt;/strong&gt;:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="k"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;'vendor/autoload.php'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nv"&gt;$f3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;\Base&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="nv"&gt;$f3&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'GET /hello/@name'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$f3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'Hello, '&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nv"&gt;$args&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'name'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="s1"&gt;'! F3 keeps it light!'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nv"&gt;$f3&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;F3’s fast, clean, and extendable, but its docs assume some PHP know-how. It’s a solid pick for devs who love minimalism with a side of power.&lt;/p&gt;

&lt;h3&gt;
  
  
  Lumen: The Laravel Lightweight (But Let’s Be Real…)
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://lumen.laravel.com/" rel="noopener noreferrer"&gt;Lumen&lt;/a&gt; sneaks into our top four as &lt;a href="https://laravel.com/" rel="noopener noreferrer"&gt;Laravel’s&lt;/a&gt; little sibling, designed for microservices and APIs. It’s got a minimalist vibe, but here’s the tea: it’s basically Laravel Lite, carrying some of the same heft under the hood. While it’s fast for a Laravel offshoot, its performance lags behind true micro frameworks like Flight or Slim—check the &lt;a href="https://www.techempower.com/benchmarks/" rel="noopener noreferrer"&gt;TechEmpower benchmarks&lt;/a&gt; for proof.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Popularity&lt;/strong&gt;: Lumen’s got 7.6k &lt;a href="https://github.com/laravel/lumen" rel="noopener noreferrer"&gt;GitHub stars&lt;/a&gt; and a decent following, but its 2024 buzz was quieter than Flight’s meteoric rise. It leans hard on Laravel’s ecosystem, which is great if you’re already in that world, less so if you want something standalone.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Simplicity&lt;/strong&gt;: If you know Laravel, it’s a cinch—Composer install, tweak a few configs, and go. For newbies, though, it’s a bit more involved than Flight or F3.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Example (Lumen 8)&lt;/strong&gt;:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="k"&gt;require&lt;/span&gt; &lt;span class="k"&gt;__DIR__&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="s1"&gt;'/../vendor/autoload.php'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nv"&gt;$app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Laravel\Lumen\Application&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;__DIR__&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="s1"&gt;'/../'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nv"&gt;$app&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'/hello/{name}'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;"Hello, &lt;/span&gt;&lt;span class="nv"&gt;$name&lt;/span&gt;&lt;span class="s2"&gt;! Lumen says hi."&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nv"&gt;$app&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It’s fine for quick APIs, but Lumen’s heft makes it less exciting compared to leaner options. Laravel fans might dig it; others might yawn.&lt;/p&gt;

&lt;h2&gt;
  
  
  Honorable Mentions: Hidden Gems of 2025
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://leafphp.dev/" rel="noopener noreferrer"&gt;Leaf PHP&lt;/a&gt;&lt;/strong&gt;: A newer kid on the block, Leaf’s simplicity and modern vibe are gaining traction. It is an old fork of Laravel so it has a certain level of familiarity to some. It’s not as battle-tested as the top four, but worth a peek!&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://bulletphp.com/" rel="noopener noreferrer"&gt;Bullet PHP&lt;/a&gt;&lt;/strong&gt;: Ultra-light and REST-focused, Bullet’s a niche choice for API wizards. It’s less popular but shines in specific use cases.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://silex.symfony.com/" rel="noopener noreferrer"&gt;Silex&lt;/a&gt;&lt;/strong&gt;: A &lt;a href="https://symfony.com/" rel="noopener noreferrer"&gt;Symfony&lt;/a&gt;-backed micro framework that's sadly deprecated and no longer support. You gave it your all Silex!&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Verdict: Which One Wins in 2025?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Popularity (Past Year)&lt;/strong&gt;: &lt;a href="https://docs.flightphp.com/" rel="noopener noreferrer"&gt;Flight PHP&lt;/a&gt; takes the crown—its 2024 updates and community hype have it soaring past Fat-Free and nipping at Slim’s heels. Slim’s still a heavyweight, Lumen’s coasting on Laravel’s fame, but Flight’s the fresh face everyone’s talking about.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Simplicity&lt;/strong&gt;: Flight edges out with its one-file setup and no-dependencies vibe—perfect for newcomers. Slim and F3 are close behind, while Lumen’s Laravel ties make it a bit clunkier.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scalability&lt;/strong&gt;: All four scale well, but Flight’s built-in features (middleware, DI) give it a subtle boost for growing projects without extra legwork or libraries. Slim needs add-ons, F3’s modularity takes planning, and Lumen’s just… Laravel Lite.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you’re new to PHP or want a fun, fast ride, &lt;a href="https://docs.flightphp.com/" rel="noopener noreferrer"&gt;Flight PHP&lt;/a&gt; is your 2025 must-try. It’s simple enough to start in minutes, powerful enough to build something epic, and—let’s be real—its recent glow-up makes it the coolest kid in class. &lt;a href="https://www.slimframework.com/" rel="noopener noreferrer"&gt;Slim&lt;/a&gt; and &lt;a href="https://fatfreeframework.com/" rel="noopener noreferrer"&gt;F3&lt;/a&gt; are fantastic too, while &lt;a href="https://lumen.laravel.com/" rel="noopener noreferrer"&gt;Lumen&lt;/a&gt; is… well, fine if you’re already married to Laravel. So, grab Flight 3, code something awesome, and let’s soar into 2025 together!&lt;/p&gt;

&lt;p&gt;What’s your favorite micro framework? Drop a comment—I’d love to geek out with you!&lt;/p&gt;

</description>
      <category>php</category>
      <category>microframework</category>
      <category>framework</category>
      <category>bestof</category>
    </item>
    <item>
      <title>Building a Pokémon API in PHP: A Beginner's Guide</title>
      <dc:creator>n0nag0n</dc:creator>
      <pubDate>Thu, 12 Sep 2024 17:17:54 +0000</pubDate>
      <link>https://dev.to/n0nag0n/building-a-pokemon-api-in-php-a-beginners-guide-3an8</link>
      <guid>https://dev.to/n0nag0n/building-a-pokemon-api-in-php-a-beginners-guide-3an8</guid>
      <description>&lt;p&gt;In this guide, we will go through the steps to create a basic PHP project that uses the &lt;a href="https://pokeapi.co/" rel="noopener noreferrer"&gt;Pokémon API&lt;/a&gt; with the Flight framework and additional packages like Zebra_cURL and Latte. We will explore setting up the project, adding routes, and rendering views.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;tl;dr&lt;/strong&gt;: It's not hard to make a simple API based project in Flight. Check out the &lt;a href="https://github.com/n0nag0n/flight-pokeapi" rel="noopener noreferrer"&gt;code&lt;/a&gt; used in this guide.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: Setting up the Environment
&lt;/h2&gt;

&lt;p&gt;First, we need to set up a new project folder. Open your terminal, navigate to your desired location, and run the following commands to create a new directory and enter it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir &lt;/span&gt;flight-pokeapi
&lt;span class="nb"&gt;cd &lt;/span&gt;flight-pokeapi
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 2: Installing Composer
&lt;/h3&gt;

&lt;p&gt;Before we dive into the code, we need to make sure that &lt;a href="https://getcomposer.org" rel="noopener noreferrer"&gt;Composer&lt;/a&gt; is installed. Composer is the dependency manager for PHP, and it will help us include the necessary libraries.&lt;/p&gt;

&lt;p&gt;If you don’t have Composer installed, you can install it using:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;php &lt;span class="nt"&gt;-r&lt;/span&gt; &lt;span class="s2"&gt;"copy('https://getcomposer.org/installer', 'composer-setup.php');"&lt;/span&gt;
php composer-setup.php
php &lt;span class="nt"&gt;-r&lt;/span&gt; &lt;span class="s2"&gt;"unlink('composer-setup.php');"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now that Composer is installed in a current file called &lt;code&gt;./composer.phar&lt;/code&gt;, let’s manage our dependencies.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3: Installing Dependencies
&lt;/h3&gt;

&lt;p&gt;To manage the required packages, we just need to add them with composer.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./composer.phar require flightphp/core stefangabos/zebra_curl latte/latte
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will install:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Flight PHP&lt;/strong&gt;: A lightweight PHP framework.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Zebra_cURL&lt;/strong&gt;: A cURL wrapper to handle HTTP requests.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Latte&lt;/strong&gt;: A templating engine for rendering views.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Step 4: Setting Up &lt;code&gt;index.php&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Next, let’s create the entry point for our application: &lt;code&gt;public/index.php&lt;/code&gt;. This file will set up our app, configure routes, and handle the rendering of views.&lt;/p&gt;

&lt;p&gt;Create the &lt;code&gt;public&lt;/code&gt; directory and the &lt;code&gt;index.php&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir &lt;/span&gt;public
&lt;span class="nb"&gt;touch &lt;/span&gt;public/index.php
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now add the following content to &lt;code&gt;index.php&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;flight\net\Router&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Latte\Engine&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;require&lt;/span&gt; &lt;span class="k"&gt;__DIR__&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="s1"&gt;'/../vendor/autoload.php'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Autoload the installed packages&lt;/span&gt;

&lt;span class="c1"&gt;// Setup Latte for view rendering&lt;/span&gt;
&lt;span class="nv"&gt;$Latte&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Engine&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nv"&gt;$Latte&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;setTempDirectory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;__DIR__&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="s1"&gt;'/../temp'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nc"&gt;Flight&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'render'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$template_path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;array&lt;/span&gt; &lt;span class="nv"&gt;$data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[])&lt;/span&gt; &lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$Latte&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nv"&gt;$Latte&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;__DIR__&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="s1"&gt;'/../views/'&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nv"&gt;$template_path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// Setup Zebra_cURL for handling HTTP requests&lt;/span&gt;
&lt;span class="nv"&gt;$Curl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Zebra_cURL&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nv"&gt;$Curl&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;__DIR__&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="s1"&gt;'/../temp'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nc"&gt;Flight&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'curl'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$Curl&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$Curl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// Define a simple route&lt;/span&gt;
&lt;span class="nc"&gt;Flight&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'/'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'hello world!'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nc"&gt;Flight&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;start&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this file:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We load Composer’s autoloader.&lt;/li&gt;
&lt;li&gt;Set up Latte for rendering views.&lt;/li&gt;
&lt;li&gt;Map a custom &lt;code&gt;render&lt;/code&gt; method that uses Latte to render templates from the &lt;code&gt;/views&lt;/code&gt; folder.&lt;/li&gt;
&lt;li&gt;Set up Zebra_cURL to handle API requests and map it to use &lt;code&gt;Flight::curl()&lt;/code&gt; when we want to invoke it.&lt;/li&gt;
&lt;li&gt;Define a simple route for the homepage (&lt;code&gt;/&lt;/code&gt;) which just returns "hello world!"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you want to test this setup, you can start a PHP server from the &lt;code&gt;public&lt;/code&gt; directory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;php &lt;span class="nt"&gt;-S&lt;/span&gt; localhost:8000 &lt;span class="nt"&gt;-t&lt;/span&gt; public/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, visit &lt;code&gt;http://localhost:8000/&lt;/code&gt; in your browser, and you should see "hello world!". Cool eh?&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 5: Adding Routes
&lt;/h3&gt;

&lt;p&gt;Now that we have a basic route set up, let’s add a more complex route that uses the Pokémon API. Update &lt;code&gt;public/index.php&lt;/code&gt; to include the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nc"&gt;Flight&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;group&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'/pokemon'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Router&lt;/span&gt; &lt;span class="nv"&gt;$router&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Route to list all Pokémon types&lt;/span&gt;
    &lt;span class="nv"&gt;$router&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'/'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$types_response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;json_decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Flight&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;curl&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;scrap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'https://pokeapi.co/api/v2/type/'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
        &lt;span class="nv"&gt;$results&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
        &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$types_response&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;next&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nv"&gt;$results&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;array_merge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$results&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$types_response&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="nv"&gt;$types_response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;json_decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Flight&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;curl&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;scrap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$types_response&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;next&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="nv"&gt;$results&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;array_merge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$results&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$types_response&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nc"&gt;Flight&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'home.latte'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="s1"&gt;'types'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$results&lt;/span&gt; &lt;span class="p"&gt;]);&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;We created a &lt;code&gt;/pokemon&lt;/code&gt; route group. A route group "surrounds" the routes and allows us to define common functionality for all routes within the group.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;/pokemon&lt;/code&gt; route lists all available Pokémon types by fetching them from the Pokémon API using Zebra_cURL.&lt;/li&gt;
&lt;li&gt;This won't work just yet as we need to add the &lt;code&gt;home.latte&lt;/code&gt; view to display the Pokémon types.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Step 6: Rendering Views with Latte
&lt;/h3&gt;

&lt;p&gt;Now that we are fetching data, let's set up views to display it. Create the &lt;code&gt;views&lt;/code&gt; directory and add a Latte template file for displaying the Pokémon types.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir &lt;/span&gt;views
&lt;span class="nb"&gt;touch &lt;/span&gt;views/home.latte
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add the following code to &lt;code&gt;views/home.latte&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;Welcome to the Pokemon World!&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;Types of Pokemon&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;ul&amp;gt;&lt;/span&gt;
    {foreach $types as $type}
        &lt;span class="nt"&gt;&amp;lt;li&amp;gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/pokemon/type/{$type-&amp;gt;name}"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;{$type-&amp;gt;name|firstUpper}&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
    {/foreach}
&lt;span class="nt"&gt;&amp;lt;/ul&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this file:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We loop through the &lt;code&gt;$types&lt;/code&gt; array passed from our route and display the name of each Pokémon type.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now, visiting &lt;code&gt;/pokemon&lt;/code&gt; will display a list of all Pokémon types!&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 7: Grouping and Adding More Routes
&lt;/h3&gt;

&lt;p&gt;Let's extend our Pokémon routes to fetch more details for specific types and individual Pokémon. Add the following routes to your &lt;code&gt;/pokemon&lt;/code&gt; group:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Route to fetch a specific Pokémon type and list all associated Pokémon&lt;/span&gt;
&lt;span class="nv"&gt;$router&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'/type/@type'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$type&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$Curl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Flight&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;curl&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nv"&gt;$type_response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;json_decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$Curl&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;scrap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'https://pokeapi.co/api/v2/type/'&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nv"&gt;$type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="nv"&gt;$pokemon_urls&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
    &lt;span class="k"&gt;foreach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$type_response&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;pokemon&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nv"&gt;$pokemon_data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$pokemon_urls&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$pokemon_data&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;pokemon&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nv"&gt;$pokemon_data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;

    &lt;span class="c1"&gt;// The little &amp;amp; here is important to pass the variable by reference.&lt;/span&gt;
    &lt;span class="c1"&gt;// In other words it allows us to modify the variable inside the closure.&lt;/span&gt;
    &lt;span class="nv"&gt;$Curl&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$pokemon_urls&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;stdClass&lt;/span&gt; &lt;span class="nv"&gt;$result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nv"&gt;$pokemon_data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$pokemon_data&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;json_decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$result&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="nc"&gt;Flight&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'type.latte'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; 
        &lt;span class="s1"&gt;'type'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$type_response&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s1"&gt;'pokemons'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$pokemon_data&lt;/span&gt;
    &lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this route, we:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Fetch details for a specific Pokémon type, including all associated Pokémon.&lt;/li&gt;
&lt;li&gt;Send multiple API requests to fetch details for each Pokémon.&lt;/li&gt;
&lt;li&gt;Render the data using a template (&lt;code&gt;type.latte&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Next, create the &lt;code&gt;type.latte&lt;/code&gt; view:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;touch &lt;/span&gt;views/type.latte
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add the following content to &lt;code&gt;type.latte&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;{$type|firstUpper}&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;ul&amp;gt;&lt;/span&gt;
    {foreach $pokemons as $pokemon}
        &lt;span class="nt"&gt;&amp;lt;li&amp;gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/pokemon/{$pokemon-&amp;gt;id}"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;{$pokemon-&amp;gt;name|firstUpper}&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
    {/foreach}
&lt;span class="nt"&gt;&amp;lt;/ul&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This template displays the name of each Pokémon associated with a specific type.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 8: Does it work?
&lt;/h3&gt;

&lt;p&gt;At this point, you have a basic Pokémon API consumer set up using Flight PHP, Zebra_cURL for API requests, and Latte for view rendering. You can further expand this project by adding more routes and refining the templates.&lt;/p&gt;

&lt;p&gt;To view your project, start the PHP server from the &lt;code&gt;public&lt;/code&gt; directory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;php &lt;span class="nt"&gt;-S&lt;/span&gt; localhost:8000 &lt;span class="nt"&gt;-t&lt;/span&gt; public/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, visit &lt;code&gt;http://localhost:8000/pokemon&lt;/code&gt; in your browser, and you should see a list of Pokémon types.&lt;/p&gt;

&lt;h3&gt;
  
  
  Troubleshooting
&lt;/h3&gt;

&lt;p&gt;If you need help or encounter issues, you can check the &lt;a href="https://github.com/n0nag0n/flight-pokeapi" rel="noopener noreferrer"&gt;full code&lt;/a&gt; out in Github to see where you may have made a misstep.&lt;/p&gt;

&lt;p&gt;Hopefully you enjoyed this little tutorial. If you have any questions or need help, feel free to ask in the comments below. Happy coding!&lt;/p&gt;

</description>
      <category>api</category>
      <category>php</category>
      <category>flightphp</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Best PHP Micro Frameworks for 2024</title>
      <dc:creator>n0nag0n</dc:creator>
      <pubDate>Wed, 07 Aug 2024 14:34:25 +0000</pubDate>
      <link>https://dev.to/n0nag0n/best-php-micro-frameworks-for-2024-19h6</link>
      <guid>https://dev.to/n0nag0n/best-php-micro-frameworks-for-2024-19h6</guid>
      <description>&lt;p&gt;&lt;strong&gt;2024 Best Micro Frameworks for PHP&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Introduction&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Well it's August 2024 and it's time for another framework comparison! In the world of web development, PHP micro frameworks have become a popular choice for developers looking to create lightweight, efficient, and fast applications. These frameworks offer the core functionalities required to build web applications without the overhead of full-stack frameworks. Many projects developed with this frameworks are for creating RESTful APIs and they have been optimized to cater to these projects. This article will compare five popular PHP micro frameworks: Slim, Flight, Fat-Free, Silex, and Lumen. We'll examine them based on their community level, simplicity, performance, and ease of use to help you decide which one is the best fit for your project.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;&lt;a href="https://slimframework.com" rel="noopener noreferrer"&gt;Slim Framework&lt;/a&gt;&lt;/strong&gt;
&lt;/h3&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Community Level&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Slim has one of the most active communities among PHP micro frameworks. With a large number of contributors and extensive documentation, it's easy to find support, resources and example projects out there.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Simplicity&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Slim is designed to be simple and intuitive. It follows a straightforward approach, allowing developers to quickly set up routes and middleware. For a light weight framework it does have several dependencies which can turn away some developers. It also needs additional package configuration out of the box to get it to handle the requests and responses in a way that is useful for most developers.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Performance&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Slim is highly performant compared to full stack frameworks, thanks to its lightweight nature. Despite it not including unnecessary features, it is one of the heavier micro frameworks in terms of performance.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Ease of Use&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Ease of use is one of Slim's strongest points. Its clear documentation and examples make it easy to get started. The framework also supports PSR-7 and PSR-15 standards, making it compatible with various middleware and components.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;&lt;a href="https://docs.flightphp.com" rel="noopener noreferrer"&gt;Flight Framework&lt;/a&gt;&lt;/strong&gt;
&lt;/h3&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Community Level&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Flight has a smaller, but dedicated community. While not as large as Slim's, it still offers good support through &lt;a href="https://matrix.to/#/!cTfwPXhpkTXPXwVmxY:matrix.org?via=matrix.org&amp;amp;via=leitstelle511.net&amp;amp;via=integrations.ems.host" rel="noopener noreferrer"&gt;chat&lt;/a&gt; and &lt;a href="https://github.com/flightphp/core" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Simplicity&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Flight prides itself on being minimalist. Its API is clean and concise, which allows developers to build applications quickly without getting bogged down by complexity. It's documentation has recently been revamped and is now more user friendly than ever.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Performance&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Flight's performance is solid, given its minimalistic design. It avoids adding overhead, ensuring fast response times for applications. Out of all the frameworks here, according to the &lt;a href="https://www.techempower.com/benchmarks/#hw=ph&amp;amp;test=plaintext&amp;amp;section=data-r22&amp;amp;l=zik073-cn3" rel="noopener noreferrer"&gt;TechEmpower benchmarks&lt;/a&gt;, Flight is consistently the fastest beating out the next leading competitor (Slim) by an average of 50% and beating out Lumens by an average of 125%!&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Ease of Use&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Flight is user-friendly, with a gentle learning curve. It is meant for a newer developer just breaking into the framework world or for the seasoned developer that wants control over more aspects of their project. Its simplicity makes it accessible to new developers, while its power appeals to experienced ones looking for a straightforward solution. There is also a page dedicated to help &lt;a href="https://docs.flightphp.com/learn/flight-vs-another-framework" rel="noopener noreferrer"&gt;compare Flight to other frameworks&lt;/a&gt; to help you make a decision.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;&lt;a href="https://fatfreeframework.com" rel="noopener noreferrer"&gt;Fat-Free Framework (F3)&lt;/a&gt;&lt;/strong&gt;
&lt;/h3&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Community Level&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Fat-Free Framework has a moderately active community. There are sufficient resources available, including documentation and community support.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Simplicity&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Fat-Free Framework aims to be both simple and powerful. It includes a range of features out of the box, which can sometimes complicate its simplicity. However, it provides a good balance between functionality and ease of use.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Performance&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;F3 is known for its high performance. Its efficient design and minimalistic core ensure that applications run smoothly and quickly.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Ease of Use&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Fat-Free Framework is relatively easy to use, though the abundance of built-in features can be overwhelming for beginners. Once familiar with its capabilities, developers can take full advantage of its robust functionality.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;&lt;a href="https://symfony.com/projects/silex" rel="noopener noreferrer"&gt;Silex Framework&lt;/a&gt;&lt;/strong&gt;
&lt;/h3&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Community Level&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Silex had a robust community, largely due to its association with Symfony. Although Silex itself &lt;a href="https://symfony.com/blog/the-end-of-silex" rel="noopener noreferrer"&gt;has been discontinued&lt;/a&gt;, the community support and resources are still available through Symfony channels.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Simplicity&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Silex is simple and elegant, designed to leverage the power of Symfony components without the bloat. Its design makes it easy to create powerful applications with minimal effort.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Performance&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Performance is not one of Silex's strengths, however it does benefit from the optimization of Symfony components. It provides a lightweight yet powerful foundation for web applications.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Ease of Use&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Silex is user-friendly for those in the Symfony ecosystem. Its integration with Symfony components makes it easy to extend and enhance applications as needed.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;&lt;a href="https://lumen.laravel.com/docs/11.x" rel="noopener noreferrer"&gt;Lumen Framework&lt;/a&gt;&lt;/strong&gt;
&lt;/h3&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Community Level&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Lumen probably has the largest and most active community, supported by Laravel. This ensures abundant resources, documentation, and community support.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Simplicity&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Lumen is designed to be simple and "fast". It strips down Laravel to its essentials, providing a streamlined framework for building microservices and APIs.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Performance&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Lumen is built for performance, optimized for speed and efficiency. Despite that, it &lt;a href="https://www.techempower.com/benchmarks/#hw=ph&amp;amp;test=plaintext&amp;amp;section=data-r22&amp;amp;l=zik073-cn3" rel="noopener noreferrer"&gt;consistently is nearly dead last in most benchmarks&lt;/a&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Ease of Use&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Ease of use is a hallmark of Lumen, particularly for developers familiar with Laravel. Its clear documentation and extensive resources make it easy to get started and build robust applications. However, it now no longer recommended to use Lumen and to use Laravel instead which highlights that it's very likely to be discontinued in the future.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Comparison Table&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;This table provides a summary of the key features of each PHP micro framework, but it is important to note that this is weighted against the frameworks in this article for &lt;strong&gt;new users&lt;/strong&gt; and not against all PHP frameworks.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Framework&lt;/th&gt;
&lt;th&gt;Community Level&lt;/th&gt;
&lt;th&gt;Simplicity&lt;/th&gt;
&lt;th&gt;Performance&lt;/th&gt;
&lt;th&gt;Ease of Use&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Slim&lt;/td&gt;
&lt;td&gt;High&lt;/td&gt;
&lt;td&gt;Medium&lt;/td&gt;
&lt;td&gt;High&lt;/td&gt;
&lt;td&gt;Medium&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Flight&lt;/td&gt;
&lt;td&gt;Medium&lt;/td&gt;
&lt;td&gt;Very High&lt;/td&gt;
&lt;td&gt;Very High&lt;/td&gt;
&lt;td&gt;Very High&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Fat-Free&lt;/td&gt;
&lt;td&gt;Medium&lt;/td&gt;
&lt;td&gt;High&lt;/td&gt;
&lt;td&gt;High&lt;/td&gt;
&lt;td&gt;High&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Silex&lt;/td&gt;
&lt;td&gt;High&lt;/td&gt;
&lt;td&gt;High&lt;/td&gt;
&lt;td&gt;Medium&lt;/td&gt;
&lt;td&gt;Low*&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Lumen&lt;/td&gt;
&lt;td&gt;High&lt;/td&gt;
&lt;td&gt;Medium&lt;/td&gt;
&lt;td&gt;Low&lt;/td&gt;
&lt;td&gt;Medium&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;*Ease of use for Silex is rated low for being discontinued and not actively maintained. Users are asked to move to Symfony.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;FAQs&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;What is the best PHP micro framework for beginners?&lt;/strong&gt;&lt;br&gt;
Slim is generally considered the most popular for beginners due to its simplicity and extensive documentation. The best framework for you will depend on your specific needs and familiarity with PHP. For those starting out in PHP, Flight is also a great choice due to its minimalist design and ease of use.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Which PHP micro framework has the best performance?&lt;/strong&gt;&lt;br&gt;
Flight is known for its exceptional performance, making it a top choice for building fast and efficient applications.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Is Silex still a good choice for new projects?&lt;/strong&gt;&lt;br&gt;
While Silex is no longer actively maintained, it is still a viable option for new projects due to its simplicity and integration with Symfony components.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How does Flight compare to Slim in terms of ease of use?&lt;/strong&gt;&lt;br&gt;
Flight is slightly more feature-rich than Slim containing a few helpful tricks out of the box. Flight also has no dependencies, which can make it easier to get started with.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can I use Fat-Free Framework for complex applications?&lt;/strong&gt;&lt;br&gt;
Yes, Fat-Free Framework includes a range of features that make it suitable for complex applications, although architectural discipline to make sure the project is structured correctly might be overwhelming for beginners at first.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Which framework should I choose if I'm already familiar with Laravel?&lt;/strong&gt;&lt;br&gt;
Lumen is the best choice for developers familiar with Laravel, as it retains the core functionality of Laravel while being optimized for microservices and APIs.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Conclusion&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Choosing the right PHP micro framework depends on your project's specific needs and your familiarity with the frameworks. Slim is ideal for beginners and those looking for simplicity and ease of use. Flight offers a performant minimalist approach that appeals to developers who prefer a straightforward framework that gives them more control. Fat-Free Framework strikes a balance between simplicity and functionality, making it suitable for more complex applications. Silex, despite being discontinued, remains a robust choice due to its integration with Symfony. Lumen stands out for its performance and ease of use, especially for developers already familiar with Laravel.&lt;/p&gt;

&lt;p&gt;In summary, all five frameworks have their strengths and can be the right choice depending on your requirements. Evaluate your project's needs and choose the framework that aligns best with your goals. Happy coding!&lt;/p&gt;

</description>
      <category>php</category>
      <category>webdev</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Building a Simple Blog with Flight - Part 2</title>
      <dc:creator>n0nag0n</dc:creator>
      <pubDate>Thu, 04 Jul 2024 05:28:55 +0000</pubDate>
      <link>https://dev.to/n0nag0n/building-a-simple-blog-with-flight-part-2-5acb</link>
      <guid>https://dev.to/n0nag0n/building-a-simple-blog-with-flight-part-2-5acb</guid>
      <description>&lt;p&gt;This is a continuation of &lt;a href="https://dev.to/n0nag0n/building-a-simple-blog-with-flight-part-1-4ap8"&gt;part 1 of the blog&lt;/a&gt;. Hopefully you've already finished that part of the blog first before we go onto some sweet improvements!&lt;/p&gt;

&lt;h2&gt;
  
  
  Sweet Improvements
&lt;/h2&gt;

&lt;p&gt;Now that we have a basic system in place, we need a few other enhancements to really make this system shine.&lt;/p&gt;

&lt;h3&gt;
  
  
  Controller improvements
&lt;/h3&gt;

&lt;p&gt;See how it's a little annoying that the construct is the same for each of the controllers we created? We could actually create a simple abstract class to help clean up some of the code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;
&lt;span class="c1"&gt;// app/controllers/BaseController.php&lt;/span&gt;

&lt;span class="k"&gt;declare&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;strict_types&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;app\controllers&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;flight\Engine&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;flight\net\Request&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;flight\net\Response&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Ghostff\Session\Session&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;flight\database\PdoWrapper&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="cd"&gt;/**
 * These help with IDE autocompletion and type hinting if you 
 * use the shortcut method.
 * 
 * @method Request request()
 * @method Response response()
 * @method Session session()
 * @method PdoWrapper db()
 * @method string getUrl(string $route, array $params = [])
 * @method void render(string $template, array $data = [])
 * @method void redirect(string $url)
 */&lt;/span&gt;
&lt;span class="k"&gt;abstract&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;BaseController&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="cd"&gt;/** @var Engine */&lt;/span&gt;
    &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="kt"&gt;Engine&lt;/span&gt; &lt;span class="nv"&gt;$app&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="cd"&gt;/**
     * Constructor
     */&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;__construct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Engine&lt;/span&gt; &lt;span class="nv"&gt;$app&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$app&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="cd"&gt;/**
     * Call method to create a shortcut to the $app property
     * 
     * @param string $name The method name
     * @param array $arguments The method arguments
     * 
     * @return mixed
     */&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;__call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;array&lt;/span&gt; &lt;span class="nv"&gt;$arguments&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nv"&gt;$name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;...&lt;/span&gt;&lt;span class="nv"&gt;$arguments&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That &lt;code&gt;__call()&lt;/code&gt; method is a little helpful shortcut so you don't have to do &lt;code&gt;$this-&amp;gt;app-&amp;gt;something()&lt;/code&gt; in your controllers, you can instead do &lt;code&gt;$this-&amp;gt;something()&lt;/code&gt; and it "forwards" it to &lt;code&gt;$this-&amp;gt;app-&amp;gt;something()&lt;/code&gt;. There's also reference to a Session class in there that we'll talk about in juuuuuust a bit. Now we can clean up the controller code a little bit. Here's the &lt;code&gt;HomeController.php&lt;/code&gt; with the cleaned up code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class="k"&gt;declare&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;strict_types&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;app\controllers&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;HomeController&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;BaseController&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="cd"&gt;/**
     * Index
     * 
     * @return void
     */&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'home.latte'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="s1"&gt;'page_title'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'Home'&lt;/span&gt; &lt;span class="p"&gt;]);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Cleaner right? You can apply this same set of changes to the &lt;code&gt;PostController&lt;/code&gt; and &lt;code&gt;CommentController&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Route Cleanup
&lt;/h3&gt;

&lt;p&gt;You may have noticed we hard coded the routes in our little app. We can use route aliases to change that behavior so more flexible in the future (especially with such a new blog, anything can change at this point!)&lt;/p&gt;

&lt;p&gt;So let's add an alias to our home route:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nv"&gt;$router&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'/'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;\app\controllers\HomeController&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="s1"&gt;'-&amp;gt;index'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;setAlias&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'home'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then we have a couple options to generate the URLs from the alias. In some controller methods you'll notice there is a &lt;code&gt;$this-&amp;gt;app-&amp;gt;redirect('/blog');&lt;/code&gt; statement. To generate the URL from the alias you could do the following instead:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="c1"&gt;// after we setup the 'blog' alias&lt;/span&gt;
&lt;span class="nv"&gt;$url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getUrl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'blog'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;redirect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$url&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you need to add a method in your Latte code to generate the URL for you, we could change how &lt;code&gt;Latte&lt;/code&gt; is setup.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nv"&gt;$Latte&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;\Latte\Engine&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nv"&gt;$Latte&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;setTempDirectory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;__DIR__&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="s1"&gt;'/../cache/'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// This adds a new function in our Latte template files&lt;/span&gt;
&lt;span class="c1"&gt;// that allows us to generate a URL from an alias.&lt;/span&gt;
&lt;span class="nv"&gt;$Latte&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;addFunction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'route'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$alias&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;array&lt;/span&gt; &lt;span class="nv"&gt;$params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[])&lt;/span&gt; &lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$app&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$app&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getUrl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$alias&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$params&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="nv"&gt;$app&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'render'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$templatePath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;array&lt;/span&gt; &lt;span class="nv"&gt;$data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt; &lt;span class="kt"&gt;?string&lt;/span&gt; &lt;span class="nv"&gt;$block&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$app&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$Latte&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$templatePath&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;__DIR__&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="s1"&gt;'/../views/'&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nv"&gt;$templatePath&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nv"&gt;$Latte&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$templatePath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$block&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And now that you have the code in place, when you're in your template files, you can do something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- this was /blog/{$post-&amp;gt;id}/edit --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"pseudo button"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"{route('blog_edit', [ 'id' =&amp;gt; $post-&amp;gt;id ])}"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Update&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Why do we do this when it seems like it takes longer to create the url? &lt;/p&gt;

&lt;p&gt;Well some software platforms need to adjust their URLs (because marketing or product said so). Let's say you've hard coded everything so that the blog page is the &lt;code&gt;/blog&lt;/code&gt; URL and marketing says they want another blog page, but the current blog page URL they want as a different page for a different market segment. In this case, let's say they want it to be changed from &lt;code&gt;/blog&lt;/code&gt; to &lt;code&gt;/blog-america&lt;/code&gt;. If you used aliases, all you would have to do is change the route URL in one spot (the &lt;code&gt;routes.php&lt;/code&gt; file), and everywhere around your codebase it will update to the new URL. Pretty nifty right? If you want to have some fun, now that you've added an alias for &lt;code&gt;/blog/@id/edit&lt;/code&gt;, why don't you change the URL part to &lt;code&gt;/blog/@id/edit-me-i-dare-you&lt;/code&gt;. Now when you refresh the page, you'll see that because of the &lt;code&gt;-&amp;gt;getUrl('blog_edit')&lt;/code&gt; code you're using, your URL's just updated themselves and when you click on the new URL is just works! Sweet!&lt;/p&gt;

&lt;p&gt;Added bonus, you'll notice with the comment aliases we use that we only do this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"pseudo button"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"{route('comment_destroy', [ 'comment_id' =&amp;gt; $comment-&amp;gt;id ])}"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Delete&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We should need to also specify &lt;code&gt;@id&lt;/code&gt; right cause the route is &lt;code&gt;$router-&amp;gt;get('/@id/comment/@comment_id/delete', /* ... */);&lt;/code&gt;? Well, when &lt;code&gt;getUrl()&lt;/code&gt; is called, it will take a peek at your current URL and if it sees that your current URL has an &lt;code&gt;@id&lt;/code&gt; in it, it will automatically add that to the URL for you. So you don't have to worry about it!&lt;/p&gt;

&lt;h3&gt;
  
  
  Authentication with Middleware
&lt;/h3&gt;

&lt;p&gt;You don't want anyone in the world to be able to update your blog right? So we'll need to implement a simple login mechanism to make sure that only logged in people can add to or update the blog. If you're remembering from up above, we need to add a route, either a new controller and a method or a method in an existing controller, and a new HTML file. Let's create the routes we'll need first:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Blog&lt;/span&gt;
&lt;span class="nv"&gt;$router&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;group&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'/blog'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Router&lt;/span&gt; &lt;span class="nv"&gt;$router&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="c1"&gt;// Login&lt;/span&gt;
    &lt;span class="nv"&gt;$router&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'/login'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;\app\controllers\LoginController&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="s1"&gt;'-&amp;gt;index'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;setAlias&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'login'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nv"&gt;$router&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'/login'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;\app\controllers\LoginController&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="s1"&gt;'-&amp;gt;authenticate'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;setAlias&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'login_authenticate'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nv"&gt;$router&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'/logout'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;\app\controllers\LogoutController&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="s1"&gt;'-&amp;gt;index'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;setAlias&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'logout'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Posts&lt;/span&gt;
    &lt;span class="c1"&gt;// your post routes&lt;/span&gt;

&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now let's create new controllers with &lt;code&gt;runway&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;php runway make:controller Login
php runway make:controller Logout
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And you can copy the code below into your &lt;code&gt;LoginController.php&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class="k"&gt;declare&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;strict_types&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;app\controllers&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;LoginController&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;BaseController&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="cd"&gt;/**
     * Index
     * 
     * @return void
     */&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'login/index.latte'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="s1"&gt;'page_title'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'Login'&lt;/span&gt; &lt;span class="p"&gt;]);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="cd"&gt;/**
     * Authenticate
     * 
     * @return void
     */&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;authenticate&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$postData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;request&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$postData&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="s1"&gt;'admin'&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nv"&gt;$postData&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;password&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="s1"&gt;'password'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;session&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'user'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$postData&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;session&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;commit&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
            &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;redirect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getUrl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'blog'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
            &lt;span class="k"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;redirect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getUrl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'login'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And copy the below code for your &lt;code&gt;LogoutController.php&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class="k"&gt;declare&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;strict_types&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;app\controllers&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;LogoutController&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;BaseController&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="cd"&gt;/**
     * Index
     * 
     * @return void
     */&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;session&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;destroy&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;redirect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getUrl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'blog'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Well wait a minute here, the controller is now calling a &lt;code&gt;session()&lt;/code&gt; method. We'll need to register a new service in our &lt;code&gt;services.php&lt;/code&gt; file to handle sessions. Thankfully there's a &lt;a href="https://docs.flightphp.com/awesome-plugins/session" rel="noopener noreferrer"&gt;great session handler&lt;/a&gt; that we can use! First we'll need to install it with composer:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;composer require ghostff/session
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we can add the session service to our &lt;code&gt;services.php&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Session Handler&lt;/span&gt;
&lt;span class="nv"&gt;$app&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'session'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;\Ghostff\Session\Session&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Do you see that &lt;code&gt;$this-&amp;gt;session-&amp;gt;commit();&lt;/code&gt; line in the controller? This is a very intentional design decision by the library author for a very good reason. Long story short, in PHP &lt;a href="https://www.php.net/manual/en/function.session-write-close.php" rel="noopener noreferrer"&gt;there is such a thing&lt;/a&gt; as &lt;code&gt;session_write_close()&lt;/code&gt; which writes the session data and closes the session. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is important because if you have a lot of AJAX requests, you don't want to lock the session file for the entire time the request is being processed. That might sound pointless to you, but what if one of your ajax requests (or page loads) is running a very large report that might take 10-20 seconds to run? During that time you will not be able to make another request on the same site because the session in locked. Yikes!&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;commit()&lt;/code&gt; method is a way to write the session data and close the session. If you don't call &lt;code&gt;commit()&lt;/code&gt; the session will actually never be written to, which can be annoying, but what's more annoying is having long requests hang (like a report running) that causes your entire app to appear to freeze up!&lt;/p&gt;

&lt;p&gt;Now we can create the HTML file for the login page. Create a new file at &lt;code&gt;app/views/login/index.latte&lt;/code&gt; and put in the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;{extends '../layout.latte'}

{block content}
&lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;Login&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;form&lt;/span&gt; &lt;span class="na"&gt;action=&lt;/span&gt;&lt;span class="s"&gt;"{route('login_authenticate')}"&lt;/span&gt; &lt;span class="na"&gt;method=&lt;/span&gt;&lt;span class="s"&gt;"post"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;Login as whoever! And the password is always "password" (no quotes)&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;label&lt;/span&gt; &lt;span class="na"&gt;for=&lt;/span&gt;&lt;span class="s"&gt;"username"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Username:&lt;span class="nt"&gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"username"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"username"&lt;/span&gt; &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;label&lt;/span&gt; &lt;span class="na"&gt;for=&lt;/span&gt;&lt;span class="s"&gt;"password"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Password:&lt;span class="nt"&gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"password"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"password"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"password"&lt;/span&gt; &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"submit"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Login&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/form&amp;gt;&lt;/span&gt;
{/block}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Lastly, we just need a link to our new login page (and a logout one while we're at it)! Let's add a link to the &lt;code&gt;app/views/blog/index.latte&lt;/code&gt; file just after the &lt;code&gt;{/foreach}&lt;/code&gt; loop:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;p&amp;gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"{route('login')}"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Login&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt; - &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"{route('logout')}"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Logout&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Umm...wait, so we can login as anyone?! That's not very secure and you're right! We're only doing this for demonstration purposes. Of course we would want to have a system where we use &lt;code&gt;password_hash('my super cool password', PASSWORD_BCRYPT)&lt;/code&gt; to hash the password and then store that in the database. But that's a topic for another blog post!&lt;/p&gt;

&lt;p&gt;So we now have a login system in place. But what if we want to make sure that only logged in users can access the blog? We can use &lt;a href="https://docs.flightphp.com/learn/middleware" rel="noopener noreferrer"&gt;middleware&lt;/a&gt; to help us with that! A middleware is a piece of code that runs before or after a route. We can use middleware to check if a user is logged in and if they are not, we can redirect them to the login page. Let's create a new file at &lt;code&gt;app/middlewares/LoginMiddleware.php&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class="k"&gt;declare&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;strict_types&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;app\middlewares&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;flight\Engine&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;LoginMiddleware&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="cd"&gt;/** @var Engine */&lt;/span&gt;
    &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="kt"&gt;Engine&lt;/span&gt; &lt;span class="nv"&gt;$app&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;__construct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Engine&lt;/span&gt; &lt;span class="nv"&gt;$app&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$app&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;before&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;   
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;session&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;exist&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'user'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;redirect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getUrl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'login'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now that we are able to use sessions, we actually can inject them as globals into our templates. Let's go to the &lt;code&gt;services.php&lt;/code&gt; file and change our &lt;code&gt;render&lt;/code&gt; method to the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nv"&gt;$app&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'render'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$templatePath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;array&lt;/span&gt; &lt;span class="nv"&gt;$data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt; &lt;span class="kt"&gt;?string&lt;/span&gt; &lt;span class="nv"&gt;$block&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$app&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$Latte&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$templatePath&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;__DIR__&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="s1"&gt;'/../views/'&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nv"&gt;$templatePath&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="c1"&gt;// Add the username that's available in every template.&lt;/span&gt;
    &lt;span class="nv"&gt;$data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="s1"&gt;'username'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$app&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;session&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getOrDefault&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'user'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;''&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nv"&gt;$data&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nv"&gt;$Latte&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$templatePath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$block&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; One thing that's important when injecting a variable at this point is that it becomes "global". Global variables in general are bad if they are not injected properly. Don't inject the whole session, but instead inject the specific variable you need. In this case, we only need the username. Globals can be bad, you've been warned!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Now we can run checks in our templates to see if the user is logged in and if we want to show certain elements or not. For example, in the &lt;code&gt;app/views/blog/index.latte&lt;/code&gt; file, we can add the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;{if $username}
&lt;span class="nt"&gt;&amp;lt;p&amp;gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"button"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"{route('blog_create')}"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Create a new post&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
{/if}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the user isn't logged in, that button won't show! Pretty cool eh?&lt;/p&gt;

&lt;h4&gt;
  
  
  But wait, there's more!
&lt;/h4&gt;

&lt;p&gt;So, wait, remember that handy dandy debug bar called Tracy? There's an extension for it that we can take advantage of to inspect our session variables. Let's go to the &lt;code&gt;config.php&lt;/code&gt; file and change a line of code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;TracyExtensionLoader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$app&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="c1"&gt;// change it to...&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;TracyExtensionLoader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$app&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="s1"&gt;'session_data'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;\Ghostff\Session\Session&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getAll&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;]));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;While we're at it, you get a free bonus of a built in Latte extension (cause you've read all the way to down here!). Go to your &lt;code&gt;services.php&lt;/code&gt; file and add this line after the &lt;code&gt;$Latte-&amp;gt;setTempDirectory(__DIR__ . '/../cache/');&lt;/code&gt; line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="c1"&gt;// PHP 8+&lt;/span&gt;
&lt;span class="nv"&gt;$Latte&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;addExtension&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Latte\Bridges\Tracy\TracyExtension&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// PHP 7.4&lt;/span&gt;
&lt;span class="nc"&gt;Latte\Bridges\Tracy\LattePanel&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;initialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$Latte&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here's some pictures of the various Tracy Extensions:&lt;/p&gt;

&lt;p&gt;See how helpful it is to see the query that's run, and to see where the query was ran so you can trace it down???&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F96pfth0k71g5djz30el0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F96pfth0k71g5djz30el0.png" alt="Database Panel" width="680" height="216"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here's Latte to help you know the template you're using.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fri3j5umvkwmxt9u4wvr6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fri3j5umvkwmxt9u4wvr6.png" alt="Latte Panel" width="556" height="267"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And here's the session data. Obviously if we had more session data this would be more useful. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuobvt73w5o416boeunf0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuobvt73w5o416boeunf0.png" alt="Session Panel" width="335" height="156"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Permissions
&lt;/h3&gt;

&lt;p&gt;Now that we can see that we are logged in or not, maybe there are more fine grained permissions that we need to look at. For instance, can only certain people after logging in edit a blog post? Can certain people delete?&lt;/p&gt;

&lt;p&gt;Now we can create user roles for your blog such as &lt;code&gt;user&lt;/code&gt; (anyone can view the blog and make a comment), &lt;code&gt;editor&lt;/code&gt; (only you can create/edit a post) and &lt;code&gt;admin&lt;/code&gt; (you can create, update and delete a post/comment).&lt;/p&gt;

&lt;p&gt;Flight has a package for &lt;a href="https://docs.flightphp.com/awesome-plugins/permissions" rel="noopener noreferrer"&gt;permissions&lt;/a&gt; that we can use. Let's install it with composer:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;composer require flightphp/permissions
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we can add the permissions service to our &lt;code&gt;services.php&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Permissions&lt;/span&gt;
&lt;span class="nv"&gt;$currentRole&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$app&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;session&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getOrDefault&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'role'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'guest'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nv"&gt;$app&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'permission'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;\flight\Permission&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="nv"&gt;$currentRole&lt;/span&gt; &lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="nv"&gt;$permission&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$app&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;permission&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nv"&gt;$permission&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;defineRule&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'post'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$currentRole&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$currentRole&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="s1"&gt;'admin'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$permissions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'create'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'read'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'update'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'delete'&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$currentRole&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="s1"&gt;'editor'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$permissions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'create'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'read'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'update'&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$permissions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'read'&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$permissions&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="nv"&gt;$permission&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;defineRule&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'comment'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$currentRole&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$currentRole&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="s1"&gt;'admin'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$permissions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'create'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'read'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'update'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'delete'&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$currentRole&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="s1"&gt;'editor'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$permissions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'create'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'read'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'update'&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$permissions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'read'&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$permissions&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Also let's change some of the &lt;code&gt;LoginController-&amp;gt;authenticate()&lt;/code&gt; method to add the user role to the session:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$postData&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;password&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="s1"&gt;'password'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;session&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'user'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$postData&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Sets the current user role&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$postData&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="s1"&gt;'admin'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;session&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'role'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'admin'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$postData&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="s1"&gt;'editor'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;session&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'role'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'editor'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;session&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'role'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'user'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;session&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;commit&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;redirect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getUrl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'blog'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="k"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; This is a very simple example of how you can set roles. In a real world application, you would have a database table (or something) that would store the user roles and you would query the database to get the user role. For illustrative purposes, your user role in our blog application will be determined by the username you use to login.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We can also create another function in Latte to help use utilize these permissions. Let's go to the &lt;code&gt;services.php&lt;/code&gt; file and add another function after the &lt;code&gt;route&lt;/code&gt; function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nv"&gt;$Latte&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;addFunction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'permission'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$permission&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nv"&gt;$args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$app&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$app&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;permission&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;has&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$permission&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;...&lt;/span&gt;&lt;span class="nv"&gt;$args&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we can use the &lt;code&gt;permission&lt;/code&gt; function in our templates. Let's go to the &lt;code&gt;app/views/blog/index.latte&lt;/code&gt; file and add a permission to the create button to check if you really can create a blog post or not:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;{if $username &lt;span class="err"&gt;&amp;amp;&amp;amp;&lt;/span&gt; permission('post.create')}
&lt;span class="nt"&gt;&amp;lt;p&amp;gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"button"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"{route('blog_create')}"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Create a new post&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
{/if}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can now add additional permissions checks for reading, updating, and deleting posts. Go ahead to the login page and login as &lt;code&gt;admin&lt;/code&gt; and &lt;code&gt;password&lt;/code&gt;. Then try it with &lt;code&gt;user&lt;/code&gt; and &lt;code&gt;password&lt;/code&gt; and notice the differences!&lt;/p&gt;

&lt;h3&gt;
  
  
  Active Record Improvements
&lt;/h3&gt;

&lt;p&gt;The active record class is relatively simple, but it has a few tricks up its sleeve. For instance we can have certain events trigger behaviors for us automatically (like adding an &lt;code&gt;updated_at&lt;/code&gt; timestamp when we update a record). We also can connect records together by defining relationships in the active record class. Let's go to the &lt;code&gt;app/records/PostRecord.php&lt;/code&gt; file and you can paste in the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class="k"&gt;declare&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;strict_types&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;app\records&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;app\records\CommentRecord&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Flight&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="cd"&gt;/**
 * ActiveRecord class for the posts table.
 * @link https://docs.flightphp.com/awesome-plugins/active-record
 *
 * @property int $id
 * @property string $title
 * @property string $content
 * @property string $username
 * @property string $created_at
 * @property string $updated_at
 * @method CommentRecord[] comments()
 */&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PostRecord&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;\flight\ActiveRecord&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="cd"&gt;/**
     * @var array $relations Set the relationships for the model
     *   https://docs.flightphp.com/awesome-plugins/active-record#relationships
     */&lt;/span&gt;
    &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="kt"&gt;array&lt;/span&gt; &lt;span class="nv"&gt;$relations&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="s1"&gt;'comments'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;HAS_MANY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;CommentRecord&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'post_id'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;];&lt;/span&gt;

    &lt;span class="cd"&gt;/**
     * Constructor
     * @param mixed $databaseConnection The connection to the database
     */&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;__construct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$databaseConnection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$databaseConnection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$databaseConnection&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="nc"&gt;Flight&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;db&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;parent&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;__construct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$databaseConnection&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'posts'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;beforeInsert&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;created_at&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;gmdate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Y-m-d H:i:s'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;updated_at&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;beforeUpdate&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;updated_at&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;gmdate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Y-m-d H:i:s'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So let's talk about what's different.&lt;/p&gt;

&lt;h4&gt;
  
  
  Relationships
&lt;/h4&gt;

&lt;p&gt;We've added a &lt;code&gt;protected array $relations&lt;/code&gt; property to the class. This is a way to &lt;a href="https://docs.flightphp.com/awesome-plugins/active-record#relationships" rel="noopener noreferrer"&gt;define relationships between records&lt;/a&gt;. In this case, we've defined a &lt;code&gt;comments&lt;/code&gt; relationship. This is a &lt;code&gt;HAS_MANY&lt;/code&gt; relationship, meaning that a post can have many comments. The &lt;code&gt;CommentRecord::class&lt;/code&gt; is the class that represents the comments table, and the &lt;code&gt;post_id&lt;/code&gt; is the foreign key that links the comments to the posts.&lt;/p&gt;

&lt;p&gt;What this will allow us to do is in our code we can save a lot of headache but just doing &lt;code&gt;$post-&amp;gt;comments()&lt;/code&gt; and it will return all the comments for that post. For example, in the &lt;code&gt;PostController&lt;/code&gt; we can change the &lt;code&gt;show&lt;/code&gt; method to the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cd"&gt;/**
 * Show
 *
 * @param int $id The ID of the post
 * @return void
 */&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;show&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nv"&gt;$id&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$PostRecord&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;PostRecord&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;db&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
    &lt;span class="nv"&gt;$post&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$PostRecord&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="c1"&gt;// Don't need these as it now will "just work" with the relationship we've defined&lt;/span&gt;
    &lt;span class="c1"&gt;// $CommentRecord = new CommentRecord($this-&amp;gt;db());&lt;/span&gt;
    &lt;span class="c1"&gt;// $post-&amp;gt;comments = $CommentRecord-&amp;gt;eq('post_id', $post-&amp;gt;id)-&amp;gt;findAll();&lt;/span&gt;
    &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'posts/show.latte'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="s1"&gt;'page_title'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$post&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'post'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$post&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Super cool right? You'll also notice the &lt;code&gt;@method CommentRecord[] comments()&lt;/code&gt; in the docblock. This is a way to tell your IDE that the &lt;code&gt;comments()&lt;/code&gt; method will return an array of &lt;code&gt;CommentRecord&lt;/code&gt; objects giving you a ton of help with autocompletion and type hinting.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; This is a very simple example of a relationship. In a real world application, you would have more complex relationships such as &lt;code&gt;HAS_ONE&lt;/code&gt;, &lt;code&gt;BELONGS_TO&lt;/code&gt;, and &lt;code&gt;MANY_MANY&lt;/code&gt;. You can read more about relationships &lt;a href="https://docs.flightphp.com/awesome-plugins/active-record#relationships" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Performance Note:&lt;/strong&gt; Relationships are great for single records, or for small collections of records. Just remember the fact that everytime you do &lt;code&gt;-&amp;gt;comments()&lt;/code&gt; it will run a query to get the comments. If you have say a query to pull back all the posts for your blog which are say 10 posts, and then put that in a foreach loop, you will have 1 query for your posts, and then 1 query for each of your 10 posts to get the comments. This is called the N+1 problem. It's not a bad problem in a small codebase, but in a large codebase it can be a big problem!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h4&gt;
  
  
  Events
&lt;/h4&gt;

&lt;p&gt;Instead of coding in the date that needs to be assigned to every record, we can actually take care of that automatically through events! Above you'll notice there is now a &lt;code&gt;beforeInsert&lt;/code&gt; and &lt;code&gt;beforeUpdate&lt;/code&gt; method. These are example &lt;a href="https://docs.flightphp.com/awesome-plugins/active-record#events" rel="noopener noreferrer"&gt;event methods&lt;/a&gt; that are called before the record is inserted or updated. This is a great way to add some default values to your records without having to remember to do it every time. So in the &lt;code&gt;PostController&lt;/code&gt; we can remove the lines that set the &lt;code&gt;created_at&lt;/code&gt; and &lt;code&gt;updated_at&lt;/code&gt; fields like below (cause they'll now be filled in automatically):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nv"&gt;$PostRecord&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;PostRecord&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;db&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="nv"&gt;$PostRecord&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nv"&gt;$PostRecord&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$postData&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nv"&gt;$PostRecord&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$postData&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;// $PostRecord-&amp;gt;updated_at = gmdate('Y-m-d H:i:s');&lt;/span&gt;
&lt;span class="nv"&gt;$PostRecord&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;save&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One other thing that's really helpful with events is that you can automatically hash/encrypt/encode values and decrypt/decode values when you pull out records automatically. For instance in a &lt;code&gt;UserRecord-&amp;gt;beforeInsert()&lt;/code&gt; method you could has the password before it's inserted into the database:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;beforeInsert&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;password&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;password_hash&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;PASSWORD_BCRYPT&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Auto Create the Database Connection
&lt;/h4&gt;

&lt;p&gt;You'll notice that we've changed the constructor to accept no argument and that if &lt;code&gt;$databaseConnection&lt;/code&gt; is &lt;code&gt;null&lt;/code&gt; it will automatically use the global &lt;code&gt;Flight::db()&lt;/code&gt; connection. This is a nice little feature that allows you to not have to pass in the database connection every time you create a new record and reduces precious keystrokes on your fingies.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;__construct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$databaseConnection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$databaseConnection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$databaseConnection&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="nc"&gt;Flight&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;db&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;parent&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;__construct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$databaseConnection&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'posts'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So now you can just do &lt;code&gt;$PostRecord = new PostRecord();&lt;/code&gt; and it will automatically use the global database connection. But when unit testing you can inject a mock connection to test your active record class.&lt;/p&gt;

&lt;h3&gt;
  
  
  Reactify/Vueify/Angularify
&lt;/h3&gt;

&lt;p&gt;We totally could have put some JavaScript framework in this project and changed our routes to be &lt;code&gt;-&amp;gt;put()&lt;/code&gt; or &lt;code&gt;-&amp;gt;delete()&lt;/code&gt; instead. This tutorial was just to help you grasp a basic understanding of how the framework works. Go ahead and throw some fancy JS into it in your own blog post!&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;This was a longer couple of posts, but you made it! Hopefully this illustrated some of the amazing things that Flight can do for you. It's a very lightweight framework that can be extended to do a lot of things. It's not as feature rich as Laravel or Symfony, but it's not trying to be. It's trying to be a simple framework that you can use to understand why you need a framework in the first place.&lt;/p&gt;

&lt;p&gt;Do yourself a favor and smash that subscribe button and pat yourself on the back cause you're worth it! You work hard at reading long blog posts about creating blog....posts. :D Leave a comment with any questions or catch us &lt;a href="https://matrix.to/#/#flight-php-framework:matrix.org" rel="noopener noreferrer"&gt;in our chat room&lt;/a&gt;&lt;/p&gt;

</description>
      <category>php</category>
      <category>tutorial</category>
      <category>api</category>
      <category>blog</category>
    </item>
    <item>
      <title>Building a Simple Blog with Flight - Part 1</title>
      <dc:creator>n0nag0n</dc:creator>
      <pubDate>Thu, 04 Jul 2024 05:07:59 +0000</pubDate>
      <link>https://dev.to/n0nag0n/building-a-simple-blog-with-flight-part-1-4ap8</link>
      <guid>https://dev.to/n0nag0n/building-a-simple-blog-with-flight-part-1-4ap8</guid>
      <description>&lt;p&gt;Hey everyone! I figured it was time to showcase some of the new features that have been added to the Flight Framework for PHP. Earlier this year the original creator of Flight &lt;a href="https://x.com/caozilla" rel="noopener noreferrer"&gt;Mike Cao&lt;/a&gt; graciously offered to transfer ownership of &lt;a href="https://github.com/mikecao/flight" rel="noopener noreferrer"&gt;mikecao/flight&lt;/a&gt; over to a new &lt;a href="https://github.com/flightphp" rel="noopener noreferrer"&gt;Flight PHP&lt;/a&gt; organization. Since it's been moved we've added features like &lt;a href="https://docs.flightphp.com/learn/middleware" rel="noopener noreferrer"&gt;middleware&lt;/a&gt;, &lt;a href="https://docs.flightphp.com/learn/routing#route-grouping" rel="noopener noreferrer"&gt;route grouping&lt;/a&gt;, &lt;a href="https://docs.flightphp.com/learn/dependency-injection-container" rel="noopener noreferrer"&gt;DIC&lt;/a&gt;, and other features. This post will be a little longer, but it's just because I've included a lot of code examples so you can have the right context into how your blog will get built.&lt;/p&gt;

&lt;p&gt;First off, let's just get this out of the way. Flight is meant to be a simple framework with a few bells and whistles. It will not compete with Laravel or Symfony or Yii or Cake or [fill in the blank]. This framework is really built towards simple to medium size projects. It also caters to those who don't like "magic" in their code that's hard to understand or train to. It's geared more towards developers who are just starting to branch into frameworks instead of raw PHP with a lot of random &lt;code&gt;include&lt;/code&gt; statements. &lt;/p&gt;

&lt;h3&gt;
  
  
  tl;dr
&lt;/h3&gt;

&lt;p&gt;Lots of cool features, nice simple implementation, blah blah blah &lt;a href="https://github.com/n0nag0n/flightphp-blog" rel="noopener noreferrer"&gt;here's the code&lt;/a&gt;. Go to &lt;a href="https://dev.to/n0nag0n/building-a-simple-blog-with-flight-part-2-5acb"&gt;part 2&lt;/a&gt; for the cool stuff!&lt;/p&gt;

&lt;h2&gt;
  
  
  Installation
&lt;/h2&gt;

&lt;p&gt;Let's use &lt;a href="https://getcomposer.org" rel="noopener noreferrer"&gt;Composer&lt;/a&gt; to get this party started.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;composer create-project flightphp/skeleton blog/
cd blog/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Configure your New Project
&lt;/h2&gt;

&lt;p&gt;First thing to do is to go to the &lt;code&gt;app/config/config.php&lt;/code&gt; file where we can put any config like API keys, database credentials, and other important credentials for our app. For this blog, we'll uncomment the line with &lt;code&gt;file_path&lt;/code&gt; for our SQLite database path:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="s1"&gt;'database'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="c1"&gt;// 'host' =&amp;gt; 'localhost',&lt;/span&gt;
        &lt;span class="c1"&gt;// 'dbname' =&amp;gt; 'dbname',&lt;/span&gt;
        &lt;span class="c1"&gt;// 'user' =&amp;gt; 'user',&lt;/span&gt;
        &lt;span class="c1"&gt;// 'password' =&amp;gt; 'password'&lt;/span&gt;
        &lt;span class="s1"&gt;'file_path'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;__DIR__&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nv"&gt;$ds&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="s1"&gt;'..'&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nv"&gt;$ds&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="s1"&gt;'database.sqlite'&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Create the Blog Database
&lt;/h3&gt;

&lt;p&gt;Flight now comes with a command line utility called &lt;a href="https://github.com/flightphp/runway" rel="noopener noreferrer"&gt;runway&lt;/a&gt;. This allows you to create custom commands for a plugin for Flight, or even for your own project.&lt;/p&gt;

&lt;p&gt;As part of the skeleton, it comes with a &lt;code&gt;SampleDatabaseCommand&lt;/code&gt; that will give us a starting point with this blog project we are creating.&lt;/p&gt;

&lt;p&gt;Run the below command and it should populate your database for you!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;php runway init:sample-db
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next we'll open up the &lt;code&gt;app/config/services.php&lt;/code&gt; file and uncomment the line for SQLite.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="c1"&gt;// see how the $config variable references the config line we uncommented earlier?&lt;/span&gt;
&lt;span class="nv"&gt;$dsn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'sqlite:'&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nv"&gt;$config&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'database'&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="s1"&gt;'file_path'&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Just to make sure we've got everything setup correctly, run &lt;code&gt;composer start&lt;/code&gt; and then go to &lt;code&gt;http://localhost:8000/&lt;/code&gt; in your browser. You should see the following screen:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmfzhhfblyy8zi1gschpy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmfzhhfblyy8zi1gschpy.png" alt="Default Home Page" width="569" height="130"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You'll also notice in the corner you have a &lt;a href="https://tracy.nette.org/" rel="noopener noreferrer"&gt;handy debug toolbar&lt;/a&gt; with some custom Flight panels to help you understand what's going on in your application. If you hover over the various items in the toolbar, you'll see a variety of hovers that you can click on to keep sticky on the page (more on that later).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F19uqje2an4ldwapzp6sx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F19uqje2an4ldwapzp6sx.png" alt="Flight Tracy Extensions" width="713" height="327"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Building the HTML Templates
&lt;/h3&gt;

&lt;p&gt;Flight does come with a &lt;a href="https://docs.flightphp.com/learn/templates" rel="noopener noreferrer"&gt;very basic HTML templating&lt;/a&gt; solution already in the framework. This is just fine for very simple sites or just to return a simple piece of HTML. It is recommended to use another templating platform such as Latte, Twig, or Blade. In this tutorial, we're going to use Latte because it is &lt;em&gt;awesome&lt;/em&gt; and has no dependencies (you'll notice in Flight we do not like unnecessary dependencies)!&lt;/p&gt;

&lt;p&gt;Go ahead and install &lt;a href="https://docs.flightphp.com/awesome-plugins/latte" rel="noopener noreferrer"&gt;Latte&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;composer require latte/latte
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add this to your &lt;code&gt;services.php&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nv"&gt;$Latte&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;\Latte\Engine&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nv"&gt;$Latte&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;setTempDirectory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;__DIR__&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="s1"&gt;'/../cache/'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// This is fun feature of Flight. You can remap some built in functions with the framework&lt;/span&gt;
&lt;span class="c1"&gt;// to your liking. In this case, we're remapping the Flight::render() method.&lt;/span&gt;
&lt;span class="nv"&gt;$app&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'render'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$templatePath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;array&lt;/span&gt; &lt;span class="nv"&gt;$data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt; &lt;span class="kt"&gt;?string&lt;/span&gt; &lt;span class="nv"&gt;$block&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$app&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$Latte&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$templatePath&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;__DIR__&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="s1"&gt;'/../views/'&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nv"&gt;$templatePath&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nv"&gt;$Latte&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$templatePath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$block&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now that we have a templating engine in place, we can create a base HTML file. Let's create a &lt;code&gt;layout.latte&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;!doctype html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"en"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
        &lt;span class="c"&gt;&amp;lt;!-- Picnic.css is a CSS framework that works out of the box with little configuration --&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"stylesheet"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"https://cdn.jsdelivr.net/npm/picnic"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;charset=&lt;/span&gt;&lt;span class="s"&gt;"utf-8"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"viewport"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"width=device-width, initial-scale=1"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;{$page_title ? $page_title.' - '}Blog Built with Flight!&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;body&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"padding: 15px;"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        {block content}{/block}
    &lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Active Record Database Class
&lt;/h3&gt;

&lt;p&gt;Flight has a plugin for interacting with a database called &lt;a href="https://docs.flightphp.com/awesome-plugins/active-record" rel="noopener noreferrer"&gt;Flight Active Record&lt;/a&gt;. This plugin helps you not write as much raw SQL in your apps (although sometimes it is more efficient to write a raw SQL query instead of forcing an active record/ORM/mapper to run it for you). Basically the active record extension helps you interact with rows within tables in your database: one row in a database can be mapped to an object in PHP (with autocomplete for the columns) saving time and sanity. Let's get it installed in our project.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;composer require flightphp/active-record
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you can use &lt;code&gt;runway&lt;/code&gt; to create your active record classes automatically for you and it will create your properties as comments automatically (for autocomplete)! &lt;/p&gt;

&lt;p&gt;First let's create the posts class. The first time you run this, it needs to setup the connection for the database.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ php runway make:record posts
Database configuration not found. Please provide the following details:
Driver (mysql/pgsql/sqlite): sqlite
Database file path [database.sqlite]: app/database.sqlite
Username (for no username, press enter) []: 
Password (for no password, press enter) []: 
Writing database configuration to .runway-config.json
Creating directory app/records
Active Record successfully created at app/records/PostRecord.php
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we'll create the comments record class:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ php runway make:record comments
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  It's Time for your First Page!
&lt;/h2&gt;

&lt;p&gt;Flight uses the MVC pattern. In order to create a new page you need to define a route in your &lt;code&gt;routes.php&lt;/code&gt; file, create a new method in a controller, and then create the HTML file that the browser will serve. You can use runway to help you get started with a new controller class:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;php runway make:controller Home
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And you should see something similar to the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ php runway make:controller Home
Controller successfully created at app/controllers/HomeController.php
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you go to &lt;code&gt;app/controllers/HomeController.php&lt;/code&gt; go ahead and add this new method to your &lt;code&gt;HomeController&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cd"&gt;/**
 * Index
 * 
 * @return void
 */&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'home.latte'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="s1"&gt;'page_title'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'Home'&lt;/span&gt; &lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And create a new file in &lt;code&gt;app/views/home.latte&lt;/code&gt; and put in this code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;{extends 'layout.latte'}

{block content}
&lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;My Home Page&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;p&amp;gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/blog"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;View My Blog!&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
{/block}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally let's change up the routes to the &lt;code&gt;routes.php&lt;/code&gt; file. Go ahead and remove any code in the routes file that begins with &lt;code&gt;$router-&amp;gt;&lt;/code&gt; and add a new route for your home router:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nv"&gt;$router&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'/'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;\app\controllers\HomeController&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="s1"&gt;'-&amp;gt;index'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Make sure you run &lt;code&gt;composer start&lt;/code&gt; so that your development server is up. If you go to &lt;code&gt;http://localhost:8000/&lt;/code&gt; in your browser, you should see something like this!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzhj51txzkkzlyk2fgwvt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzhj51txzkkzlyk2fgwvt.png" alt="Flight Demo Home Page" width="352" height="207"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now we're cookin'!&lt;/p&gt;

&lt;h2&gt;
  
  
  Adding Routes for the Blog
&lt;/h2&gt;

&lt;p&gt;Let's go ahead and add all the methods in your controller, routes, and html files. Let's start with adding the routes in your &lt;code&gt;routes.php&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Blog&lt;/span&gt;
&lt;span class="nv"&gt;$router&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;group&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'/blog'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Router&lt;/span&gt; &lt;span class="nv"&gt;$router&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="c1"&gt;// Posts&lt;/span&gt;
    &lt;span class="nv"&gt;$router&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;\app\controllers\PostController&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="s1"&gt;'-&amp;gt;index'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nv"&gt;$router&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'/create'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;\app\controllers\PostController&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="s1"&gt;'-&amp;gt;create'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nv"&gt;$router&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;\app\controllers\PostController&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="s1"&gt;'-&amp;gt;store'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nv"&gt;$router&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'/@id'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;\app\controllers\PostController&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="s1"&gt;'-&amp;gt;show'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nv"&gt;$router&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'/@id/edit'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;\app\controllers\PostController&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="s1"&gt;'-&amp;gt;edit'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nv"&gt;$router&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'/@id/edit'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;\app\controllers\PostController&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="s1"&gt;'-&amp;gt;update'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nv"&gt;$router&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'/@id/delete'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;\app\controllers\PostController&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="s1"&gt;'-&amp;gt;destroy'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So you'll notice we use a &lt;code&gt;group()&lt;/code&gt; method here to group all the routes together that start with &lt;code&gt;/blog&lt;/code&gt;. We could actually rewrite the routes like the following with the &lt;code&gt;group()&lt;/code&gt; method and the same thing would happen:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Posts&lt;/span&gt;
&lt;span class="nv"&gt;$router&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'/blog'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;\app\controllers\PostController&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="s1"&gt;'-&amp;gt;index'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nv"&gt;$router&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'/blog/create'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;\app\controllers\PostController&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="s1"&gt;'-&amp;gt;create'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With the controller, first let's create an empty controller with &lt;code&gt;runway&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;php runway make:controller Post
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can copy the code below for your &lt;code&gt;PostController.php&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class="k"&gt;declare&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;strict_types&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;app\controllers&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;app\records\CommentRecord&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;app\records\PostRecord&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;flight\Engine&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PostController&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="cd"&gt;/** @var Engine */&lt;/span&gt;
    &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="kt"&gt;Engine&lt;/span&gt; &lt;span class="nv"&gt;$app&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="cd"&gt;/**
     * Constructor
     */&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;__construct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Engine&lt;/span&gt; &lt;span class="nv"&gt;$app&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$app&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="cd"&gt;/**
     * Index
     *
     * @return void
     */&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$PostRecord&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;PostRecord&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;db&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
        &lt;span class="nv"&gt;$posts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$PostRecord&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;order&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'id DESC'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;findAll&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="nv"&gt;$CommentRecord&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;CommentRecord&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;db&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
        &lt;span class="k"&gt;foreach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$posts&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nv"&gt;$post&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nv"&gt;$post&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;comments&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$CommentRecord&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;eq&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'post_id'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$post&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;findAll&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'posts/index.latte'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="s1"&gt;'page_title'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'Blog'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'posts'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$posts&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="cd"&gt;/**
     * Create
     *
     * @return void
     */&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;create&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'posts/create.latte'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="s1"&gt;'page_title'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'Create Post'&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="cd"&gt;/**
     * Store
     *
     * @return void
     */&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;store&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$postData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;request&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nv"&gt;$PostRecord&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;PostRecord&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;db&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
        &lt;span class="nv"&gt;$PostRecord&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$postData&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nv"&gt;$PostRecord&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$postData&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nv"&gt;$PostRecord&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$postData&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nv"&gt;$PostRecord&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;created_at&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;gmdate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Y-m-d H:i:s'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nv"&gt;$PostRecord&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;updated_at&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nv"&gt;$PostRecord&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;save&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;redirect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'/blog'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="cd"&gt;/**
     * Show
     *
     * @param int $id The ID of the post
     * @return void
     */&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;show&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nv"&gt;$id&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$PostRecord&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;PostRecord&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;db&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
        &lt;span class="nv"&gt;$post&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$PostRecord&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nv"&gt;$CommentRecord&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;CommentRecord&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;db&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
        &lt;span class="nv"&gt;$post&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;comments&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$CommentRecord&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;eq&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'post_id'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$post&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;findAll&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'posts/show.latte'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="s1"&gt;'page_title'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$post&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'post'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$post&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="cd"&gt;/**
     * Edit
     *
     * @param int $id The ID of the post
     * @return void
     */&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;edit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nv"&gt;$id&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$PostRecord&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;PostRecord&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;db&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
        &lt;span class="nv"&gt;$post&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$PostRecord&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'posts/edit.latte'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="s1"&gt;'page_title'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'Update Post'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'post'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$post&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="cd"&gt;/**
     * Update
     *
     * @param int $id The ID of the post
     * @return void
     */&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nv"&gt;$id&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$postData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;request&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nv"&gt;$PostRecord&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;PostRecord&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;db&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
        &lt;span class="nv"&gt;$PostRecord&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nv"&gt;$PostRecord&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$postData&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nv"&gt;$PostRecord&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$postData&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nv"&gt;$PostRecord&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$postData&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nv"&gt;$PostRecord&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;updated_at&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;gmdate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Y-m-d H:i:s'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nv"&gt;$PostRecord&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;save&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;redirect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'/blog'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="cd"&gt;/**
     * Destroy
     *
     * @param int $id The ID of the post
     * @return void
     */&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;destroy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nv"&gt;$id&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$PostRecord&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;PostRecord&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;db&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
        &lt;span class="nv"&gt;$post&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$PostRecord&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nv"&gt;$post&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nb"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;redirect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'/blog'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's kill some time and talk about a few things that are going on in the controller.&lt;/p&gt;

&lt;p&gt;First off we are now using our new active record classes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nv"&gt;$PostRecord&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;PostRecord&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;db&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="nv"&gt;$posts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$PostRecord&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;order&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'id DESC'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;findAll&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We are injecting the database we setup in the &lt;code&gt;services.php&lt;/code&gt; file above with &lt;code&gt;$this-&amp;gt;app-&amp;gt;db();&lt;/code&gt;. Technically we could also just use &lt;code&gt;Flight::db()&lt;/code&gt; as this points to the global &lt;code&gt;$app&lt;/code&gt; variable. &lt;/p&gt;

&lt;p&gt;Active Record classes are really helpful to simplify interactions with a database. We could rewrite the above in the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nv"&gt;$posts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;db&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;fetchAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"SELECT * FROM posts ORDER BY id DESC"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This might not be the best example of how helpful an active record could be. But &lt;a href="https://dev.to/n0nag0n/building-a-simple-blog-with-flight-part-2-22ol"&gt;in part 2&lt;/a&gt; I'll show you some hidden gems inside these classes that make it so much better than writing raw SQL.&lt;/p&gt;

&lt;p&gt;Now let's talk HTML files. Here are the files we'll need for the post routes:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;app/views/posts/index.latte&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;{extends '../layout.latte'}

{block content}

&lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;My Amazing Blog&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;Welcome to my blog!&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;p&amp;gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"button"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/blog/create"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Create a new post&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
{foreach $posts as $post}
    {first}
    &lt;span class="nt"&gt;&amp;lt;h2&amp;gt;&lt;/span&gt;Recent Posts&lt;span class="nt"&gt;&amp;lt;/h2&amp;gt;&lt;/span&gt;
    {/first}
    &lt;span class="nt"&gt;&amp;lt;hr&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;h3&amp;gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/blog/{$post-&amp;gt;id}"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;{$post-&amp;gt;title}&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&amp;lt;/h3&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&amp;lt;small&amp;gt;&lt;/span&gt;By: {$post-&amp;gt;username} on {$post-&amp;gt;created_at|date:'d.m.Y G:i a'}&lt;span class="nt"&gt;&amp;lt;/small&amp;gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;Comments: {count($post-&amp;gt;comments)}
    &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;{$post-&amp;gt;content|truncate:100}&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;hr&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"pseudo button"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/blog/{$post-&amp;gt;id}/edit"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Update&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt; - &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"pseudo button"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/blog/{$post-&amp;gt;id}/delete"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Delete&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
{/foreach}

{/block}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;app/views/posts/show.latte&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;{extends '../layout.latte'}

{block content}
&lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/blog"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;&lt;span class="ni"&gt;&amp;amp;lt;&lt;/span&gt; Back to blog&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;{$post-&amp;gt;title}&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;Created by: {$post-&amp;gt;username} on {$post-&amp;gt;created_at|date:'d.m.Y G:i a'}.&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;
    {$post-&amp;gt;content|breakLines}
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;p&lt;/span&gt; &lt;span class="na"&gt;n:if=&lt;/span&gt;&lt;span class="s"&gt;"$post-&amp;gt;update_at"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Last update: {$post-&amp;gt;update_at|date:'d.m.Y G:i a'}.&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;h2&amp;gt;&lt;/span&gt;Comments&lt;span class="nt"&gt;&amp;lt;/h2&amp;gt;&lt;/span&gt;
{foreach $post-&amp;gt;comments as $comment}
&lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;{$comment-&amp;gt;username} on {$comment-&amp;gt;created_at|date:'d.m.Y G:i a'}.&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;
        {$comment-&amp;gt;content|breakLines}
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;hr&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"pseudo button"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/blog/{$post-&amp;gt;id}/comment/{$comment-&amp;gt;id}/delete"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Delete&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
{else}
&lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;No comments yet.&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
{/foreach}

&lt;span class="nt"&gt;&amp;lt;h2&amp;gt;&lt;/span&gt;Add comment&lt;span class="nt"&gt;&amp;lt;/h2&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;form&lt;/span&gt; &lt;span class="na"&gt;action=&lt;/span&gt;&lt;span class="s"&gt;"/blog/{$post-&amp;gt;id}/comment"&lt;/span&gt; &lt;span class="na"&gt;method=&lt;/span&gt;&lt;span class="s"&gt;"post"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;label&lt;/span&gt; &lt;span class="na"&gt;for=&lt;/span&gt;&lt;span class="s"&gt;"username"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Username:&lt;span class="nt"&gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"username"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"username"&lt;/span&gt; &lt;span class="na"&gt;placeholder=&lt;/span&gt;&lt;span class="s"&gt;"Username"&lt;/span&gt; &lt;span class="na"&gt;required&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;label&lt;/span&gt; &lt;span class="na"&gt;for=&lt;/span&gt;&lt;span class="s"&gt;"content"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Comment:&lt;span class="nt"&gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;textarea&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"content"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"content"&lt;/span&gt; &lt;span class="na"&gt;placeholder=&lt;/span&gt;&lt;span class="s"&gt;"Comment"&lt;/span&gt; &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/textarea&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"submit"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Add Comment&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/form&amp;gt;&lt;/span&gt;
{/block}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;app/views/posts/create.latte&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;{extends '../layout.latte'}

{block content}
&lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;Create a Post&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;form&lt;/span&gt; &lt;span class="na"&gt;action=&lt;/span&gt;&lt;span class="s"&gt;"/blog"&lt;/span&gt; &lt;span class="na"&gt;method=&lt;/span&gt;&lt;span class="s"&gt;"post"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;label&amp;gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"title"&lt;/span&gt; &lt;span class="na"&gt;placeholder=&lt;/span&gt;&lt;span class="s"&gt;"Title"&lt;/span&gt; &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;label&amp;gt;&amp;lt;textarea&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"content"&lt;/span&gt; &lt;span class="na"&gt;placeholder=&lt;/span&gt;&lt;span class="s"&gt;"Content"&lt;/span&gt; &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/textarea&amp;gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;label&amp;gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"username"&lt;/span&gt; &lt;span class="na"&gt;placeholder=&lt;/span&gt;&lt;span class="s"&gt;"Username"&lt;/span&gt; &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/label&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"submit"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Create&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/form&amp;gt;&lt;/span&gt;
{/block}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;app/views/posts/edit.latte&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;{extends '../layout.latte'}

{block content}
&lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;Update a Post&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;form&lt;/span&gt; &lt;span class="na"&gt;action=&lt;/span&gt;&lt;span class="s"&gt;"/blog/{$post-&amp;gt;id}/edit"&lt;/span&gt; &lt;span class="na"&gt;method=&lt;/span&gt;&lt;span class="s"&gt;"post"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;label&lt;/span&gt; &lt;span class="na"&gt;for=&lt;/span&gt;&lt;span class="s"&gt;"title"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Title&lt;span class="nt"&gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"title"&lt;/span&gt; &lt;span class="na"&gt;placeholder=&lt;/span&gt;&lt;span class="s"&gt;"Title"&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"{$post-&amp;gt;title}"&lt;/span&gt; &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;label&lt;/span&gt; &lt;span class="na"&gt;for=&lt;/span&gt;&lt;span class="s"&gt;"content"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Content&lt;span class="nt"&gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;label&amp;gt;&amp;lt;textarea&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"content"&lt;/span&gt; &lt;span class="na"&gt;placeholder=&lt;/span&gt;&lt;span class="s"&gt;"Content"&lt;/span&gt; &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;{$post-&amp;gt;content}&lt;span class="nt"&gt;&amp;lt;/textarea&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;label&lt;/span&gt; &lt;span class="na"&gt;for=&lt;/span&gt;&lt;span class="s"&gt;"username"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Username&lt;span class="nt"&gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;label&amp;gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"username"&lt;/span&gt; &lt;span class="na"&gt;placeholder=&lt;/span&gt;&lt;span class="s"&gt;"Username"&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"{$post-&amp;gt;username}"&lt;/span&gt; &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"submit"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Update&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/form&amp;gt;&lt;/span&gt;
{/block}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Create a new post
&lt;/h2&gt;

&lt;p&gt;Now that we've got all the pieces in place, you should be able to load up your blog page, create a new post, see a post, and delete a post. You may have noticed we've included a comment form but the form doesn't actually work. We can fix that real quick! Let's create a controller with &lt;code&gt;runway&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;php runway make:controller Comment
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you can make the &lt;code&gt;CommentController.php&lt;/code&gt; look like the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class="k"&gt;declare&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;strict_types&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;app\controllers&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;app\records\CommentRecord&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;flight\Engine&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CommentController&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="cd"&gt;/** @var Engine */&lt;/span&gt;
    &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="kt"&gt;Engine&lt;/span&gt; &lt;span class="nv"&gt;$app&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="cd"&gt;/**
     * Constructor
     */&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;__construct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Engine&lt;/span&gt; &lt;span class="nv"&gt;$app&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$app&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="cd"&gt;/**
     * Store
     * 
     * @param int $id The post ID
     * 
     * @return void
     */&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;store&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nv"&gt;$id&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$postData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;request&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nv"&gt;$CommentRecord&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;CommentRecord&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;db&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
        &lt;span class="nv"&gt;$CommentRecord&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;post_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$id&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nv"&gt;$CommentRecord&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$postData&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nv"&gt;$CommentRecord&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$postData&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nv"&gt;$CommentRecord&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;created_at&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;gmdate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Y-m-d H:i:s'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nv"&gt;$CommentRecord&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;updated_at&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nv"&gt;$CommentRecord&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;save&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;redirect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'/blog/'&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nv"&gt;$id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="cd"&gt;/**
     * Destroy
     * 
     * @param int $id The post ID
     * @param int $comment_id The comment ID
     * 
     * @return void
     */&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;destroy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nv"&gt;$id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nv"&gt;$comment_id&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$CommentRecord&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;CommentRecord&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;db&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
        &lt;span class="nv"&gt;$CommentRecord&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$comment_id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nv"&gt;$CommentRecord&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nb"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;redirect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'/blog/'&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nv"&gt;$id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now let's add a couple other routes in the group chunk of code in &lt;code&gt;routes.php&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Blog&lt;/span&gt;
&lt;span class="nv"&gt;$router&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;group&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'/blog'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Router&lt;/span&gt; &lt;span class="nv"&gt;$router&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="c1"&gt;// Posts&lt;/span&gt;

    &lt;span class="c1"&gt;// post routes...&lt;/span&gt;

    &lt;span class="c1"&gt;// Comments&lt;/span&gt;
    &lt;span class="nv"&gt;$router&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'/@id/comment'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;\app\controllers\CommentController&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="s1"&gt;'-&amp;gt;store'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nv"&gt;$router&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'/@id/comment/@comment_id/delete'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;\app\controllers\CommentController&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="s1"&gt;'-&amp;gt;destroy'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion (sort of)
&lt;/h2&gt;

&lt;p&gt;With these two additions to the code, you have a fully functioning blog built with Flight! This got the job done and you now have a blog, but the code is somewhat clunky and could be improved to have some pretty nifty features like middleware, permissions, and writing less code! &lt;a href="https://dev.to/n0nag0n/building-a-simple-blog-with-flight-part-2-5acb"&gt;Hop over to part 2&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Go ahead and leave any questions in comments below or &lt;a href="https://matrix.to/#/#flight-php-framework:matrix.org" rel="noopener noreferrer"&gt;join us in the chatroom&lt;/a&gt;!&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If you want to see the final product with all the improvements &lt;a href="https://github.com/n0nag0n/flightphp-blog" rel="noopener noreferrer"&gt;here's the code&lt;/a&gt;!&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>php</category>
      <category>tutorial</category>
      <category>blog</category>
      <category>api</category>
    </item>
    <item>
      <title>Creating a RESTful API with Flight Framework</title>
      <dc:creator>n0nag0n</dc:creator>
      <pubDate>Sat, 15 Jun 2024 20:38:03 +0000</pubDate>
      <link>https://dev.to/n0nag0n/creating-a-restful-api-with-flight-framework-56lj</link>
      <guid>https://dev.to/n0nag0n/creating-a-restful-api-with-flight-framework-56lj</guid>
      <description>&lt;p&gt;In this article, we'll walk through building a RESTful API using the &lt;a href="https://docs.flightphp.com" rel="noopener noreferrer"&gt;Flight framework&lt;/a&gt;, which is a simple yet powerful PHP micro-framework. Flight aims to be simple to understand what is going on with your application and leave you in control without too much "magic" happening. We'll cover the basics of setting up the framework, creating a user resource in a SQLite database, and implementing a simple authentication middleware. &lt;/p&gt;

&lt;h3&gt;
  
  
  Getting Started with Flight
&lt;/h3&gt;

&lt;p&gt;First, let's set up Flight and create our project. You can download Flight from its &lt;a href="https://github.com/flightphp/core" rel="noopener noreferrer"&gt;GitHub repository&lt;/a&gt; or installed via &lt;a href="https://getcomposer.org" rel="noopener noreferrer"&gt;composer&lt;/a&gt;. Composer is generally the way to go.&lt;/p&gt;

&lt;h4&gt;
  
  
  Installation
&lt;/h4&gt;

&lt;p&gt;You can install Flight via Composer. Create a new directory for your project and run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;composer require flightphp/core
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Setting Up Your Project
&lt;/h4&gt;

&lt;p&gt;Here is the example directory structure for your project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;project-root/
├── public/
│   └── index.php
├── config/
│   └── config.php
├── middleware/
│   └── AuthMiddleware.php
├── vendor/
└── composer.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create an &lt;code&gt;index.php&lt;/code&gt; file in your public directory. This file will serve as the entry point for your application.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;
&lt;span class="k"&gt;require&lt;/span&gt; &lt;span class="k"&gt;__DIR__&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="s1"&gt;'/../vendor/autoload.php'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nc"&gt;Flight&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'/'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;
    &lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'Hello, world!'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nc"&gt;Flight&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;start&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Open up your terminal application and type &lt;code&gt;php -S localhost:8080 -t public/&lt;/code&gt; and navigate to &lt;code&gt;http://localhost:8080&lt;/code&gt; to see the "Hello, world!" message. If you get an error message about a port already being used, go ahead and try another port like &lt;code&gt;8081&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating the User Resource
&lt;/h3&gt;

&lt;p&gt;Now, let's create a user resource with CRUD operations. We'll use SQLite for the database for the simplicity of this tutorial, but you can use any database of your choice.&lt;/p&gt;

&lt;h4&gt;
  
  
  Database Connection
&lt;/h4&gt;

&lt;p&gt;Create a &lt;code&gt;config.php&lt;/code&gt; file to store your database credentials:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;
&lt;span class="c1"&gt;// config.php&lt;/span&gt;
&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="s1"&gt;'database_path'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;__DIR__&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="s1"&gt;'/../flight_app.sqlite'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  CRUD Operations
&lt;/h4&gt;

&lt;p&gt;In your &lt;code&gt;index.php&lt;/code&gt; file, include the database connection and define CRUD operations for the user resource.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;
&lt;span class="k"&gt;require&lt;/span&gt; &lt;span class="k"&gt;__DIR__&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="s1"&gt;'/../vendor/autoload.php'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nv"&gt;$config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;require&lt;/span&gt; &lt;span class="k"&gt;__DIR__&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="s1"&gt;'/../config/config.php'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// This is where you can register a database connection so you can use it in any of your routes below&lt;/span&gt;
&lt;span class="nc"&gt;Flight&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'db'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;\flight\database\PdoWrapper&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="s1"&gt;'sqlite:'&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;$config&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'database_path'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$db&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
    &lt;span class="nv"&gt;$db&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;setAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;PDO&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;ATTR_ERRMODE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;PDO&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;ERRMODE_EXCEPTION&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nv"&gt;$db&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;setAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;PDO&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;ATTR_DEFAULT_FETCH_MODE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;PDO&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;FETCH_ASSOC&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// This will create the database and the users table if it doesn't exist already&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;file_exists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$config&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'database_path'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$db&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Flight&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;db&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nv"&gt;$db&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;runQuery&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"CREATE TABLE users (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, email TEXT NOT NULL UNIQUE, password TEXT NOT NULL)"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// A group helps group together similar routes for convenience&lt;/span&gt;
&lt;span class="nc"&gt;Flight&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;group&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'/users'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;\flight\net\Router&lt;/span&gt; &lt;span class="nv"&gt;$router&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="c1"&gt;// Get all users&lt;/span&gt;
    &lt;span class="nv"&gt;$router&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;
        &lt;span class="nv"&gt;$db&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Flight&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;db&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="nv"&gt;$users&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$db&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;fetchAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"SELECT * FROM users"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nc"&gt;Flight&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$users&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="c1"&gt;// Get user by id&lt;/span&gt;
    &lt;span class="nv"&gt;$router&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'/@id'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$id&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
        &lt;span class="nv"&gt;$db&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Flight&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;db&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="nv"&gt;$user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$db&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;fetchRow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"SELECT * FROM users WHERE id = :id"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="s1"&gt;':id'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$id&lt;/span&gt; &lt;span class="p"&gt;]);&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="k"&gt;empty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'id'&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nc"&gt;Flight&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nc"&gt;Flight&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;jsonHalt&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt; &lt;span class="s1"&gt;'message'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'User not found'&lt;/span&gt; &lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="mi"&gt;404&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="c1"&gt;// Create new user&lt;/span&gt;
    &lt;span class="nv"&gt;$router&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;
        &lt;span class="nv"&gt;$data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Flight&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;request&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nv"&gt;$db&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Flight&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;db&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="nv"&gt;$result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$db&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;runQuery&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"INSERT INTO users (name, email, password) VALUES (:name, :email, :password)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; 
            &lt;span class="s1"&gt;':name'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'name'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; 
            &lt;span class="s1"&gt;':email'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'email'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; 
            &lt;span class="s1"&gt;':password'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;password_hash&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'password'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="no"&gt;PASSWORD_BCRYPT&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
        &lt;span class="p"&gt;]);&lt;/span&gt;
        &lt;span class="nc"&gt;Flight&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt; &lt;span class="s1"&gt;'id'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$db&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;lastInsertId&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="mi"&gt;201&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="c1"&gt;// Update user&lt;/span&gt;
    &lt;span class="nv"&gt;$router&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;put&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'/@id'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$id&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
        &lt;span class="nv"&gt;$data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Flight&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;request&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getData&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="nv"&gt;$db&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Flight&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;db&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="nv"&gt;$result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$db&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;runQuery&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"UPDATE users SET name = :name, email = :email, password = :password WHERE id = :id"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
            &lt;span class="s1"&gt;':id'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s1"&gt;':name'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'name'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
            &lt;span class="s1"&gt;':email'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'email'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
            &lt;span class="s1"&gt;':password'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;password_hash&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'password'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="no"&gt;PASSWORD_BCRYPT&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;]);&lt;/span&gt;
        &lt;span class="nc"&gt;Flight&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt; &lt;span class="s1"&gt;'message'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'User updated successfully'&lt;/span&gt; &lt;span class="p"&gt;]);&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="c1"&gt;// Delete user&lt;/span&gt;
    &lt;span class="nv"&gt;$router&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nb"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'/@id'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$id&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
        &lt;span class="nv"&gt;$db&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Flight&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;db&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="nv"&gt;$stmt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$db&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;runQuery&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"DELETE FROM users WHERE id = :id"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="s1"&gt;':id'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$id&lt;/span&gt; &lt;span class="p"&gt;]);&lt;/span&gt;
        &lt;span class="nc"&gt;Flight&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt; &lt;span class="s1"&gt;'message'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'User deleted successfully'&lt;/span&gt; &lt;span class="p"&gt;]);&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nc"&gt;Flight&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;start&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Simple Authentication Middleware
&lt;/h3&gt;

&lt;p&gt;Next, let's implement a simple authentication middleware to protect our API routes.&lt;/p&gt;

&lt;p&gt;Create a new file called &lt;code&gt;AuthMiddleware.php&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;
&lt;span class="c1"&gt;// AuthMiddleware.php&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AuthMiddleware&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;before&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$headers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Flight&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;request&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getHeaders&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;isset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$headers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'Authorization'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nv"&gt;$token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$headers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'Authorization'&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
            &lt;span class="c1"&gt;// Normally, you would validate the token here. For simplicity, we'll just check if it's "secret"&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$token&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;'secret'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="nc"&gt;Flight&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;jsonHalt&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt; &lt;span class="s1"&gt;'message'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'Unauthorized'&lt;/span&gt; &lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="mi"&gt;401&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Include this middleware in your &lt;code&gt;index.php&lt;/code&gt; file and protect your routes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;
&lt;span class="k"&gt;require&lt;/span&gt; &lt;span class="k"&gt;__DIR__&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="s1"&gt;'/../vendor/autoload.php'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nv"&gt;$config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;require&lt;/span&gt; &lt;span class="k"&gt;__DIR__&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="s1"&gt;'/../config/config.php'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;require&lt;/span&gt; &lt;span class="k"&gt;__DIR__&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="s1"&gt;'/../middleware/AuthMiddleware.php'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// code to set up database connection (as shown above)&lt;/span&gt;

&lt;span class="nc"&gt;Flight&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;group&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'/users'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;\flight\net\Router&lt;/span&gt; &lt;span class="nv"&gt;$router&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="c1"&gt;// previously defined routes here&lt;/span&gt;

&lt;span class="c1"&gt;// This is where you put the middleware&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;AuthMiddleware&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;]);&lt;/span&gt;

&lt;span class="c1"&gt;// Repeat for other routes...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Example Usage
&lt;/h3&gt;

&lt;p&gt;To test your API, you can use tools like Postman or cURL. Here’s an example using cURL to get all users:&lt;/p&gt;

&lt;h4&gt;
  
  
  Creating a User
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Authorization: secret"&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"name":"John Doe", "email":"john@example.com", "password":"password"}'&lt;/span&gt; http://localhost:8080/users
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will create a new user and return the user ID.&lt;/p&gt;

&lt;h4&gt;
  
  
  Getting All Users
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Authorization: secret"&lt;/span&gt; http://localhost:8080/users
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will return a JSON response with all the users in your database.&lt;/p&gt;

&lt;h4&gt;
  
  
  Getting a User by ID
&lt;/h4&gt;

&lt;p&gt;Now that you have created a user, you can get the user by ID. You can get the ID from the response of the previous request.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Authorization: secret"&lt;/span&gt; http://localhost:8080/users/1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Updating a User
&lt;/h4&gt;

&lt;p&gt;You can update a user by sending a PUT request with the user ID and the updated data.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; PUT &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Authorization: secret"&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"name":"Jane Doe", "email":"jane@example.com", "password":"mynewpassword"}'&lt;/span&gt; http://localhost:8080/users/1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Deleting a User
&lt;/h4&gt;

&lt;p&gt;You can delete a user by sending a DELETE request with the user ID.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; DELETE &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Authorization: secret"&lt;/span&gt; http://localhost:8080/users/1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Wrapping Up
&lt;/h3&gt;

&lt;p&gt;Flight is a great choice for building simple and lightweight applications quickly. It offers the essential features needed for creating a RESTful API while being easy to learn and use. For many projects, Flight has plenty of features to help maintain the long term needs for your project. For more complex applications, you might consider using more robust frameworks like Laravel, CakePHP, or CodeIgniter, depending on your specific needs.&lt;/p&gt;

&lt;p&gt;If you made it this far, here is the &lt;a href="https://github.com/n0nag0n/flightphp-restapi-user" rel="noopener noreferrer"&gt;code&lt;/a&gt; used in this article.&lt;/p&gt;

</description>
      <category>php</category>
      <category>restapi</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Unveiling the Mystery: How the `DESCRIBE` Command Can Bring Down a Server</title>
      <dc:creator>n0nag0n</dc:creator>
      <pubDate>Thu, 10 Aug 2023 01:29:09 +0000</pubDate>
      <link>https://dev.to/n0nag0n/unveiling-the-mystery-how-the-desc-command-creates-temporary-tables-in-mysqlmariadb-2m6e</link>
      <guid>https://dev.to/n0nag0n/unveiling-the-mystery-how-the-desc-command-creates-temporary-tables-in-mysqlmariadb-2m6e</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;For the past eight months, our team has been on a detective mission. A mysterious graph started showing usage when some code went live, and it's been a rollercoaster ride trying to figure out the root cause. The culprit? The MySQL or MariaDB &lt;code&gt;DESC&lt;/code&gt;, &lt;code&gt;DESCRIBE&lt;/code&gt;, or &lt;code&gt;EXPLAIN&lt;/code&gt; table commands.&lt;/p&gt;

&lt;p&gt;The graph in Zabbix for temporary tables created per second began to fluctuate, and we were at a loss as to why. The situation escalated during a recent spike in usage, when our server became overloaded, and we started to notice a lot of &lt;code&gt;DESCRIBE table&lt;/code&gt; commands in our process list.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff5xx1i2xkiq3pvi8eu6p.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff5xx1i2xkiq3pvi8eu6p.png" alt="Image description" width="658" height="342"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This article uncovers the behavior of the &lt;code&gt;DESCRIBE&lt;/code&gt; command and its link to temporary table creation, a discovery that illuminated our understanding and allowed us to resolve the issue.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is the &lt;code&gt;DESCRIBE&lt;/code&gt; Command?
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;DESCRIBE&lt;/code&gt; command in MySQL or MariaDB is used to describe the structure of a table. It provides information about the columns, types, and other properties of the table. Here's a simple example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;DESCRIBE&lt;/span&gt; &lt;span class="n"&gt;employees&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;-- also EXPLAIN employees; and DESC employees;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This would display the structure of the &lt;code&gt;employees&lt;/code&gt; table, including column names, data types, etc.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;+------------+--------------+------+-----+---------+-------+
| Field      | Type         | Null | Key | Default | Extra |
+------------+--------------+------+-----+---------+-------+
| id         | int          | NO   | PRI | NULL    |       |
| first_name | varchar(50)  | YES  |     | NULL    |       |
| last_name  | varchar(50)  | YES  |     | NULL    |       |
| salary     | decimal      | YES  |     | NULL    |       |
| hire_date  | date         | YES  |     | NULL    |       |
+------------+--------------+------+-----+---------+-------+

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The Unexpected Behavior: Temporary Table Creation
&lt;/h2&gt;

&lt;p&gt;What caught our attention was that in MariaDB, the description "Creating Temporary Table" appeared when running the &lt;code&gt;DESCRIBE&lt;/code&gt; command. This was puzzling and led us to investigate further.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why are Temporary Tables Created?
&lt;/h3&gt;

&lt;p&gt;Temporary tables are often used to store intermediate results for complex queries. However, we didn't expect them to be linked to the &lt;code&gt;DESCRIBE&lt;/code&gt; command. After digging into the MySQL/MariaDB documentation and source code, we realized that the &lt;code&gt;DESCRIBE&lt;/code&gt; command indeed creates a temporary table to store and display the structure of the queried table.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Impact on Performance
&lt;/h3&gt;

&lt;p&gt;The frequent creation of temporary tables was taking a toll on our system. The server became overloaded, and the website's performance deteriorated.&lt;/p&gt;

&lt;p&gt;Our code was using the &lt;code&gt;DESC&lt;/code&gt; command to populate database mappers, and it seemed that the cache was not working properly. This resulted in an excessive number of &lt;code&gt;DESC&lt;/code&gt; commands, leading to the unexpected creation of temporary tables.&lt;/p&gt;

&lt;h2&gt;
  
  
  How We Fixed the Issue
&lt;/h2&gt;

&lt;p&gt;Our solution involved correcting the caching mechanism. Once the cache was functioning properly, the number of &lt;code&gt;DESC&lt;/code&gt; commands plummeted, and the graph flatlined.&lt;/p&gt;

&lt;p&gt;Here's a brief outline of the steps we took:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Analyzed the Caching Behavior:&lt;/strong&gt; We found that the cache was not retaining the &lt;code&gt;DESCRIBE&lt;/code&gt; command results.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Implemented Proper Caching:&lt;/strong&gt; We modified our code to properly store and retrieve the table descriptions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Monitored Performance:&lt;/strong&gt; We closely watched the system performance and the graph in Zabbix. The result was a noticeable improvement.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb8r4ou2bk5zqxut4pe3b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb8r4ou2bk5zqxut4pe3b.png" alt="Image description" width="800" height="203"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;The discovery that the &lt;code&gt;DESCRIBE&lt;/code&gt; command creates temporary tables in MySQL/MariaDB was an unexpected revelation that solved a long-standing mystery. By understanding this behavior and implementing proper caching, we were able to boost our system's performance.&lt;/p&gt;

&lt;p&gt;Sometimes, the solutions to complex problems are hidden in the most unexpected places. This experience reminds us to leave no stone unturned in our pursuit of understanding and optimizing our systems. Whether you're a seasoned database administrator or new to MySQL/MariaDB, I hope this article sheds light on a lesser-known aspect of these database systems and helps you in your journey.&lt;/p&gt;

</description>
      <category>mysql</category>
      <category>mariadb</category>
      <category>troubleshooting</category>
      <category>debug</category>
    </item>
    <item>
      <title>Dependency Injection in Mako Framework for PHP</title>
      <dc:creator>n0nag0n</dc:creator>
      <pubDate>Sat, 29 Jul 2023 20:57:01 +0000</pubDate>
      <link>https://dev.to/n0nag0n/dependency-injection-in-mako-framework-for-php-468o</link>
      <guid>https://dev.to/n0nag0n/dependency-injection-in-mako-framework-for-php-468o</guid>
      <description>&lt;p&gt;Dependency injection is so important in the architecture of your PHP app. When you start out with a tiny project, it's workable without it. When that project gets bigger, oh man! So let's go over Dependency Injection in the Mako Framework!&lt;/p&gt;

&lt;h1&gt;
  
  
  Understanding Dependency Injection
&lt;/h1&gt;

&lt;p&gt;Let's say we have a &lt;code&gt;Car&lt;/code&gt; class and this class needs an instance of an &lt;code&gt;Engine&lt;/code&gt; class to work. Instead of creating an instance of the &lt;code&gt;Engine&lt;/code&gt; class inside the &lt;code&gt;Car&lt;/code&gt; class, we "inject" the &lt;code&gt;Engine&lt;/code&gt; instance into the &lt;code&gt;Car&lt;/code&gt; when we create it. This is the core idea of Dependency Injection.&lt;/p&gt;

&lt;h1&gt;
  
  
  Registering a Dependency
&lt;/h1&gt;

&lt;p&gt;In Mako, we can register these dependencies in a container. The container is a special object that holds and manages instances of our classes. When we register a dependency, we're telling the container how to create an instance of a certain class.&lt;/p&gt;

&lt;p&gt;Here's an example of how to register a dependency:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nv"&gt;$container&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;EngineInterface&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Engine&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this case, &lt;code&gt;EngineInterface::class&lt;/code&gt; is the key we use to refer to the dependency in the container, and &lt;code&gt;Engine::class&lt;/code&gt; is the concrete class that will be instantiated when we ask the container for this dependency.&lt;/p&gt;

&lt;h1&gt;
  
  
  Registering a Dependency with a Key
&lt;/h1&gt;

&lt;p&gt;We can also associate a key with our dependency. This can make our code easier to read and write, and it also allows us to access our dependencies in a more flexible way.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nv"&gt;$container&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;register&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nc"&gt;EngineInterface&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'engine'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nc"&gt;Engine&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, we're associating the key 'engine' with our &lt;code&gt;Engine::class&lt;/code&gt; dependency. Now we can retrieve our &lt;code&gt;Engine&lt;/code&gt; instance from the container using either &lt;code&gt;EngineInterface::class&lt;/code&gt; or 'engine' as the key.&lt;/p&gt;

&lt;h1&gt;
  
  
  Registering a Dependency with a Closure
&lt;/h1&gt;

&lt;p&gt;Sometimes, creating an instance of a class might involve some complex logic or additional configuration. In these cases, we can use a closure to define how the instance should be created.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nv"&gt;$container&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;register&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nc"&gt;WheelInterface&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'wheel'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$container&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Wheel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'parameter value'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, we're telling the container to create a new instance of &lt;code&gt;Wheel&lt;/code&gt; with 'parameter value' as an argument. The closure gives us a lot of flexibility when it comes to creating our instances.&lt;/p&gt;

&lt;h1&gt;
  
  
  Registering a Singleton Dependency
&lt;/h1&gt;

&lt;p&gt;Sometimes, we want to ensure that there's only one instance of a certain class in our application. There are times like when you only want one guaranteed instance of a Database Connection no matter how many times you call a service from a container. This is known as a singleton. We can register a singleton dependency in the container like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nv"&gt;$container&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;registerSingleton&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nc"&gt;EngineInterface&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'engine'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$container&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Engine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'parameter value'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, every time we ask the container for the 'engine' dependency, it will always return the same instance of &lt;code&gt;Engine&lt;/code&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  Registering an Existing Instance
&lt;/h1&gt;

&lt;p&gt;If we already have an instance of a class and we want to register it in the container, we can do so using the &lt;code&gt;registerInstance&lt;/code&gt; method.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nv"&gt;$container&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;registerInstance&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nc"&gt;WheelInterface&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'wheel'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Wheel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'parameter value'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This can be useful if we need to register an instance that was created outside of the container, or if we want to share a specific instance across different parts of our application.&lt;/p&gt;

&lt;h1&gt;
  
  
  Resolving a Dependency
&lt;/h1&gt;

&lt;p&gt;Once we've registered our dependencies in the container, we can retrieve them using the &lt;code&gt;get&lt;/code&gt; method. This is known as resolving a dependency.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nv"&gt;$engine&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$container&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;EngineInterface&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or using the optional key:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nv"&gt;$engine&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$container&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'engine'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When we resolve a dependency, the container will give us an instance of the class associated with the given key. If the dependency was registered with a closure, the container will execute the closure to create the instance.&lt;/p&gt;

&lt;p&gt;And that's it! You now know how to add a new dependency to the application container using the Mako PHP framework. Remember, the key to understanding Dependency Injection is practice, so don't hesitate to experiment with these concepts in your own projects. Happy coding!&lt;/p&gt;

</description>
      <category>php</category>
      <category>webdev</category>
      <category>beginners</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
