PHP Learning Roadmap: Core Syntax to a Tested Laravel App

Follow a practical 12-week path from typed PHP and Composer to safe database access, feature tests and a Laravel rebuild, using one application throughout.

KnowledgeGate Team

Exam prep & CS education

Updated 4 Sep 20265 min read

Jumping straight into Laravel often leaves a beginner copying controllers without understanding PHP values, requests, SQL or security. Studying syntax for months creates the opposite problem: knowledge without a working application. Build the Study Tracker as a command-line script first, then as a tested Laravel app. The honest workload is 8 hours/week x 12 weeks = 96 hours, with a recovery rule for smaller weeks instead of a Sunday cramming fantasy.

1. Define the finished app and the 8-hour weekly contract

The finished tracker accepts a topic, minutes and date, validates minutes from 1 to 480, and lists sessions and per-topic totals. Tests enforce the same rules.

Fixed rows: PHP, 45, 2026-07-18; SQL, 75, 2026-07-19; and PHP, 30, 2026-07-20. They give PHP = 45 + 30 = 75, SQL = 75, and Total = 150.

Each normal week has four 75-minute Monday-to-Thursday blocks: 4 x 75 = 300 minutes = 5 hours. Saturday adds a 2-hour build; Sunday adds 1 hour for testing, review and planning. Finish with a runnable artefact or passing test.

Phase

Time

Weeks 1-2, core PHP

16 hours

Week 3, Composer and structure

8 hours

Weeks 4-5, HTTP and HTML

16 hours

Weeks 6-7, SQL and PDO

16 hours

Weeks 8-9, security and testing

16 hours

Weeks 10-12, Laravel

24 hours

Total: 16 + 8 + 16 + 16 + 16 + 24 = 96 hours.

2. Weeks 1-2: learn modern PHP through one domain model

Each PHP file starts with declare(strict_types=1);. Use scalar and return types, arrays, control flow, functions, exceptions and namespaces for tracker needs. Define a topic enum containing PHP, SQL and HTTP, then a StudySession holding that enum, validated minutes and a DateTimeImmutable date.

Predict the first calculation before running it. For weeklyMinutes([45, 75, 30]), the integer accumulator moves 0 -> 45 -> 120 -> 150, returning 150. Validation makes minutes = 0 and minutes = 481 throw InvalidArgumentException; boundary values 1 and 480 pass. Confirm it in code.

Use the C++ Tutorial, Complete Learning Path only as a parallel example of moving from fundamentals to projects. Its staging idea transfers; its syntax does not.

3. Week 3: use Composer to turn scripts into a small application

Create a Composer project with the PSR-4 mapping StudyTracker\\ to src/. Put the entity in src/Domain/StudySession.php, the calculation in src/Service/WeeklyMinutes.php, and load both through vendor/autoload.php. Checkpoint: php bin/summary.php prints PHP: 75, SQL: 75, and Total: 150 from the fixed rows.

Composer keeps dependencies and autoloading in one declared project. Keep domain code out of HTML, never hand-edit generated vendor code, and add the test runner as a development dependency only when testing begins.

4. Weeks 4-5: trace one HTTP form submission end to end

Before using a framework, build a plain PHP form. Send POST /sessions with topic=PHP, minutes=75, and studied_on=2026-07-18. The handler parses the request, rejects a missing topic and minutes=900, converts the valid date to DateTimeImmutable, calls the domain rule, saves through a repository interface, then redirects to GET /sessions. A refresh repeats the read, not the write.

Keep four jobs distinct: HTML collects values, HTTP carries them, PHP validates and coordinates, and storage persists them. Escape every rendered value. If labelled forms and tables are unfamiliar, use the Complete HTML Course as an optional prerequisite, not PHP instruction.

A browser form POSTs to a PHP handler that validates minutes, saves through a repository, then redirects to the sessions dashboard.

5. Weeks 6-7: persist the same values with SQL and PDO

Create study_sessions(id INTEGER PRIMARY KEY, topic VARCHAR(80) NOT NULL, minutes SMALLINT NOT NULL CHECK (minutes BETWEEN 1 AND 480), studied_on DATE NOT NULL). Insert all three rows with a prepared PDO statement, never by joining user input into SQL.

Dashboard groups rows by topic: PHP is 45 + 30 = 75, SQL is 75, and both groups total 75 + 75 = 150. Filtering from 2026-07-19 through 2026-07-20 retains the 75-minute SQL row and 30-minute PHP row, totalling 75 + 30 = 105. Filtering chooses rows first; grouping combines those remaining.

Once you can explain the aggregate, use SQL Queries and Joins in DBMS for adjacent practice, not as PHP or Laravel evidence.

6. Weeks 8-9: make security and tests part of the feature

Build a test matrix. Unit-test weeklyMinutes([45, 75, 30]) = 150. Accept 1 and 480; reject 0, 481, an empty topic and an invalid date. An integration test posts PHP, 75, 2026-07-18, confirms one stored row, follows the redirect and sees 75 on the dashboard. Use a disposable database, not personal rows.

Require and verify a CSRF token. Submit <script>alert(1)</script> as a topic and ensure the page displays text instead of executing it. Bind all SQL values as parameters. Keep secrets outside source control; never log tokens or database credentials. Authentication can wait because it does not prove this feature.

7. Weeks 10-12: rebuild the vertical slice in Laravel

Move proven behaviour, not file layout. Map GET /sessions and POST /sessions to a thin StudySessionController. Use a dedicated request validator, migration, StudySession model, weekly-total service and templates. Preserve 1..480, the seed rows and total 150 for comparison.

Checkpoints:

  1. End of Week 10: the migration and model store PHP, 75, 2026-07-18.

  2. End of Week 11: the form rejects minutes=900, accepts 75, redirects and shows the new total.

  3. End of Week 12: feature tests recreate a blank database, submit all three rows and assert PHP = 75, SQL = 75, Total = 150.

After finishing the PHP app, the MERN Stack Course offers an optional full-stack comparison. It is not PHP or Laravel instruction.

8. Recover from missed days and use a strict definition of done

If Thursday's 75-minute block is lost, keep Saturday's 2-hour build and use Sunday to document the failing test and next command. The week is 5 hours - 75 minutes + 2 hours + 1 hour = 6 hours 45 minutes. Carry 30 minutes of setup into Monday, drop the remaining 45 minutes, and avoid catch-up debt. If Saturday is also lost, keep the 5-hour weekday minimum and move the phase by one week.

Done means a fresh checkout installs through Composer, creates a blank database and passes every test. It rejects 0 and 481, stores the three seed rows, renders hostile text safely and shows 150 minutes.

The short version

Learn the language, trace HTTP, persist safely, test the rules, then remap the app into Laravel. Keep every phase runnable. Next, use the Coding & Skills hub to choose a course matching the gap your tracker revealed.