Members | Series | Title | Release | Length |
---|---|---|---|---|
Pragmatic PHP |
Fluent Validation
In this step, we introduced a flexible and expressive validation system.
🧱 Created the Framework/Validation class and added a validate() helper to globals.php. ✍️ The goal was to write intuitive validation logic like: validate('rating')->integer()->min(0)->max(5)->required(); validate('name')->string()->max(100); validate('comment')->string()->max(1000); 🧪 This fluent API allowed chaining validation rules for each input field, improving both readability and maintainability. 🔧 We fixed the num_stars constraint in the migration SQL to properly enforce the rating range. 🧹 Ran the migration and reseeded the database to apply the changes. 🕵️ Also refined the reviews logic to default the name to “Anonymous” when one isn’t provided. This new validation infrastructure enhances data safety and gives us a consistent, clean way to validate user input throughout the application. |
Thu, Jun 19, 2025 | 17m:11s | |
Pragmatic PHP |
User Registration
🔹 Controller Setup
- Create a new RegistrationController inside Http/, with index() and store() methods - index() displays the registration form - store() temporarily calls dd($_POST) to confirm input 🔹 View - Add the form view at views/registration.index.view.php 🔹 Validation - Write validation rules in fluent style: - $email = validate('email')->email()->required()->unique('users', 'email'); - Build out the validation logic to support this pattern 🔹 User Model - Create a Models/User class - Move relevant DB logic from the controller into the model 🔹 Model Base Enhancements - In the Model base class: - Add $is_count to build_query() - Implement a count() method that supports basic tallying - In the Database class: - Add a count() method to execute counting queries - Add a unique() validation method using model and count 🔹 Data Insertion - Assemble a $data array with validated inputs - Call User::insert($data) to create the new user That’ll wrap up the registration feature and land us at v22-registering-users 🏁 |
Tue, Jun 24, 2025 | 20m:42s | |
Pragmatic PHP |
User Authentication
📁 Controller Setup
- Create a new AuthenticationController inside Http/ with three methods: - login() – shows the login form - authenticate() – handles login logic - logout() – clears user session 📄 View - Add views/login/index.view.php to render the login form 🔀 Routing - Register the necessary routes: - GET /login → shows the login form - POST /login → processes authentication - POST /logout (or GET) → logs the user out 🧠 Authentication Logic - Inside authenticate(): - Validate email and password inputs - Lookup user by email from the database - Use password_verify() to check if password matches - On success → Session::login($user_id) - On failure → redirect back with error message 🔐 Session Enhancements - Add login($user_id) to store user ID in session - Add logout() to destroy the session cleanly 📌 And that lands us at v23-authentication. |
Thu, Jun 26, 2025 | 9m:3s | |
Pragmatic PHP |
Auth & Application Workflow
🛠️ Session Enhancements
- Add guest() and user() methods to the Session class - guest() → returns true if no user is logged in - user() → returns current user object (or null) 🎨 Navigation Improvements - Update the top navigation bar to reflect authentication state: - Show Register / Login links when user is not logged in - Show user avatar and menu when logged in - Fix any related JavaScript issues 👤 Gravatar Integration - Create a new helper class: app/Code/Gravatar.php - Use the user’s email to generate their avatar - Display avatar in the nav for logged-in users 🖼️ Conditional Upload View - Modify the upload page to only display the upload form if the user is logged in 📌 And that ties up the loose ends, landing us at v24-authentication-loose-ends. |
Tue, Jul 1, 2025 | 15m:30s | |
Pragmatic PHP |
Uploading Photos
🔒 UI Adjustments Based on Auth State
• Hide the notification bell in the top nav if the user isn’t logged in 🧭 Routing & Form Setup • Create an /upload route • Set the form’s action and stub in the store() method with a dd($_POST) to start • Remove the unused “title” field from the upload form 🧪 Validation Process • Define validation for the uploaded photo: $file = validate('photo')->file($allowed_mimes)->max(4016053)->required(); • Add $allowed_mimes and $max_file_size constants to the Photo model • Implement file() and update the max() method in the Validation class • Fix Validation::clean_value() to properly handle file inputs ⚠️ Missing Validation Messages • Ensure validation errors are displayed in these views: • registration.index • auth.index • upload.index 💾 File Storage & DB Entry • Save the uploaded file to the appropriate location • Create a new photo record in the database 🚫 .gitignore Update • Add public/photos to the .gitignore file to prevent uploaded files from being committed ⸻ 📌 And that completes the upload feature, bringing us to v25-upload-photos. Ready to show off some pictures! |
Thu, Jul 3, 2025 | 19m:17s | |
Pragmatic PHP |
Photo Deletion
🖼️ Improved Photo Show Page
In photo.show, hide the summary and reviews if none exist 🔗 Delete Route & Form Add a new route using the DELETE method In photo.show, display a delete form only if the logged-in user owns the photo Include a hidden input field: _METHOD = DELETE Update the Router class to detect the method via: $_POST['_METHOD'] ?? $_SERVER['REQUEST_METHOD'] 🔧 Controller Refactor Split responsibilities: ReviewController: keep only the store method, and fix redirect_back() usage PhotoController: remove the store method 🧨 Destroy Method in PhotoController Ensure the user is authenticated Validate the photo exists Validate ownership of the photo Delete the photo file: Add directory() method to the Photo model Add convert_to_path() method to the Photo model Delete the corresponding database record: Add a delete() method to the base Model class 📌 That wraps up the deletion flow and lands us at v26-delete-photos — now users can clean up after themselves! |
Tue, Jul 8, 2025 | 22m:11s | |
Pragmatic PHP |
Second Refactor & Review
🧠 Model Hydration Fixes
- Solved the issue where results weren’t instances of the child model class - Introduced hydrate() and hydrate_rows() to handle model instantiation - Added PHPDoc annotations with generics to assist with static analysis and better typing - Updated type hints across Policies and Controllers for clarity and consistency 📦 Model Enhancements - Added an update() method - Introduced pagination support with skip() and take() - Added sorting via order_by() and order_by_desc() - Modified / route to use pagination 🛡️ New Policy Classes - PhotoController: created Http/Policies/PhotoPolicy - AuthController: created and used AuthPolicy - RegisterController: created UserPolicy - ReviewController: created ReviewPolicy - UploadController: updated to use PhotoPolicy - Fixed return $data in UploadController to include a proper URL 📌 All of that polish and organization lands us at v26-review-refactor — making the codebase smoother, smarter, and more maintainable. |
Thu, Jul 10, 2025 | 19m:31s | |
Pragmatic PHP |
Blade / Twig Style Templates
In this video, we upgrade our templating engine to support Blade-style syntax, bringing a more expressive and readable feel to our views. Here’s what we did:
Enhanced the View class to support: - Escaped output: {{ $user->name }} - Raw output: {!! $user->name !!} Updated all relevant views to use the new shorthand syntax for cleaner templates. - 🛠️ Fixed a display issue in photo.show where old_rating wasn’t mapping correctly (it was showing a 4 instead of the correct 1). ✨ With this little dose of syntax sugar, we land at v27-blade-envy — giving our views a modern touch without bringing in a full framework. |
Tue, Jul 15, 2025 | 7m:48s | |
Pragmatic PHP |
Final Review & Refactor
This video is all about the last layer of polish — a final walkthrough to tidy up code, views, and structure across the project. Here’s what we touched:
🖼️ Views - index.view.php: added wider screen support with max-w-7xl. - Removed a duplicate header to clean up the layout. 🧱 Framework Cleanup - Database.php: fixed IDE issues and added helpful annotations. - globals.php: minor tweaks to smooth dev experience. - Model.php: highlighted PHPDoc comments, reviewed skip(), take(), and orderBy() methods. - Session.php and View.php: both got the “FII” treatment (Fix IDE Issues). 📦 Http Layer - Policies: - UserPolicy: FII. - Controllers: - AuthenticationController, PhotoController, RegisterController, ReviewController, and UploadController: all reviewed and cleaned up. 🌐 Public Entry Point - index.php: adjusted try/catch block for better error handling and clarity. 🎯 And that wraps things up at v28-review-refactor — setting the stage for a maintainable, scalable app with a solid foundation. |
Thu, Jul 17, 2025 | 12m:54s |