The digital landscape shifted significantly this past Saturday when Laravel Lang fell victim to a sophisticated supply chain attack. This wasn't a standard SQL injection or a cross-site scripting flaw. Instead, attackers utilized compromised credentials to push malicious Git tags on forks, bypassing main branch security checks. This incident serves as a wake-up call for the PHP community, signaling a new era of AI-driven, highly sophisticated repository breaches that target the very tools we trust to build our applications. Autoload malware executes without function calls The most terrifying aspect of the Laravel Lang breach is that the payload executes at the autoload stage. In a standard Laravel application, every request—whether it's a web visit, an Artisan command, or a background job—passes through the public `index.php` file. This file initiates the Composer autoloader. Because the malware was embedded at this level, a developer didn't even need to call a specific function from the compromised package to trigger the attack. Simply having the package installed and loading the site was enough to execute the malicious script silently in the background. Credentials are the primary target Modern attacks have moved beyond simple database drops. This specific breach deployed a "stealer" script designed to scour the environment for high-value targets. It didn't just look for `.env` files; it searched for SSH keys, AWS credentials, and GitHub tokens. The goal is lateral movement: using your local machine or server as a jumping-off point to compromise even larger systems. If you ran `composer update` during the window when these malicious tags were active, your entire development environment—not just your project—should be considered compromised. Stop running naked composer updates The habit of running a blind `composer update` to stay "current" is now a liability. To mitigate risk, you must commit your `composer.lock` file to version control. This ensures that every environment—from staging to production—uses the exact same dependency versions verified by the lead developer. When updates are necessary, perform them selectively. Instead of updating the entire tree, use `composer update vendor/package` to limit changes to a single dependency. This reduces the surface area for
Artisan
Products
Laravel Daily (3 mentions) discusses Artisan commands within Laravel development, showcasing techniques for testing translations and generating observers. Laravel (1 mention) covers updates to Laravel, noting prerequisites like PHP and Eloquent concepts.
- May 25, 2026
- May 7, 2026
- Mar 19, 2026
- Feb 23, 2026
- Feb 5, 2026
Overview: The Context Gap in AI Development Standard AI models often stumble when working with Laravel because they lack two critical components: up-to-date documentation and framework-specific context. Generic agents rely on static training data, which means they are unaware of the latest features like request batching in Laravel 12. Laravel Boost bridges this gap by providing Model Context Protocol (MCP) servers and tailored guidelines directly to your AI agent, transforming it from a general coder into a framework expert. Prerequisites To follow this guide, you should be comfortable with the Artisan CLI and have a basic understanding of Composer package management. You will also need an AI-capable code editor such as Cursor or Claude Code. Key Libraries & Tools - **Laravel Boost**: The core package that provides tools and context to AI agents. - **Claude Code**: A command-line AI agent from Anthropic that integrates with MCP servers. - **Pest**: A testing framework for PHP included in the automated guidelines. - **Tailwind CSS**: A utility-first CSS framework supported by Boost's styling guidelines. Installation and Configuration After adding the package via Composer, you initialize the environment using a specialized Artisan command. This process generates specific guidelines by scanning your `composer.json` to see exactly which versions of tools like PHP or Alpine.js you are using. ```bash php artisan boost:install ``` During setup, you select your preferred editor and agent. Boost then injects best practices into your workspace, ensuring the AI adheres to the latest community standards and version-specific syntax. The Power of MCP Tools Once connected to the Model Context Protocol server, your agent gains "superpowers" through specialized tools: - **Search Docs**: Allows the AI to query the live Laravel documentation for brand-new features. - **Database Query**: Enables the agent to check record counts or table structures directly. - **Tinker**: Lets the AI run Laravel Tinker commands to test logic without creating temporary files. - **Browser Logs**: Helps the agent read error logs to debug issues autonomously. Syntax Notes & Best Practices Boost focuses on **version-aware syntax**. If your project uses Laravel 12, the AI will prioritize new hooks and features over deprecated Laravel 11 patterns. It also enforces strict testing standards for Pest, ensuring your generated tests are modern and readable. Tips & Gotchas Always ensure your MCP server is actually connected in your editor settings. If the AI claims it doesn't know about a feature, check if the `search_docs` tool is active. Using the **Tinker tool** is significantly safer than letting an AI create random PHP scripts, as it prevents leftover "junk" files from cluttering your production-ready codebase.
Dec 23, 2025Overview Standard Laravel Eloquent Observers often feel repetitive. Developers frequently find themselves writing the same notification or logging logic across dozens of models. This guide explores a highly efficient refactoring pattern that uses custom Artisan commands and framework stubs to generate boilerplate-free observers automatically. By shifting logic into traits and templates, you can maintain a consistent audit log or notification system without manual coding. Prerequisites To implement this pattern, you should be comfortable with PHP and the Laravel framework. You need a basic understanding of Eloquent model events (created, updated, deleted) and how Artisan CLI commands interact with the file system. Key Libraries & Tools * **Laravel Framework**: The core environment providing the Eloquent ORM. * **Artisan CLI**: Used for generating code and publishing framework templates. * **PHP File System**: Utilized by custom commands to iterate through model directories. Code Walkthrough Step 1: Create the Base Notification Trait Instead of defining notification logic in every observer, move it to a shared trait. This keeps your observers slim. ```php trait SendsNotifications { public function sendSuccessNotification($model, $action) { // Logic to send database notification } public function sendDangerNotification($model, $action) { // Logic for deletions or errors } } ``` Step 2: Customizing the Observer Stub Run `php artisan stub:publish` to bring Laravel's internal templates into your `stubs/` directory. Modify `observer.stub` to include your trait and default methods. ```php namespace {{ namespace }}; use {{ namespacedModel }}; use App\Traits\SendsNotifications; class {{ class }} { use SendsNotifications; public function created({{ model }} ${{ modelVariable }}) { $this->sendSuccessNotification(${{ modelVariable }}, 'created'); } } ``` Step 3: The Bulk Generation Command A custom Artisan command can automate the creation for all models in your app. ```php public function handle() { $models = File::allFiles(app_path('Models')); foreach ($models as $file) { $modelName = $file->getFilenameWithoutExtension(); $this->call('make:observer', [ 'name' => "{$modelName}Observer", '--model' => $modelName ]); } } ``` Syntax Notes Laravel uses mustache-style placeholders like `{{ model }}` in its stubs. When you run a `make` command, the framework's generator replaces these with the actual class names you provide in the terminal. This allows for dynamic code generation while maintaining strict typing. Practical Examples This approach shines in large-scale applications requiring a robust activity log or audit trail. Instead of installing heavy packages, you generate lightweight observers that trigger database notifications every time a record changes. It ensures every new model added to the system is automatically tracked without additional developer effort. Tips & Gotchas Watch out for infinite loops. If your observer saves data back to the same model it is observing, it will trigger itself again. Always use the `saveQuietly()` method if you need to update the model instance within the observer logic to prevent recursive crashes.
Dec 17, 2025Overview of Local Log Tailining Traditional log monitoring often feels like a chore. You open a massive text file, scroll through endless lines of unformatted text, and try to pinpoint where an exception occurred among thousands of entries. While the `tail -f` command offers a glimpse into real-time updates, it lacks the context and readability developers need for rapid iteration. Laravel Pail solves this by providing a dedicated terminal interface that streams application logs, exceptions, and stack traces with visual clarity. Prerequisites and Setup To use this tool effectively, you should have a solid grasp of Laravel architecture, specifically how the framework handles logging through its configuration files. You will need a functioning local development environment running PHP and the Composer package manager to install the utility. Familiarity with Artisan commands is essential, as the tool operates directly within your terminal. Key Libraries & Tools - **Laravel Pail**: A CLI package that captures and formats logs in real-time. - **Artisan**: The command-line interface for Laravel used to execute the tool. - **Sentry/Flare**: External error tracking services that Laravel Pail can complement by showing local streams even when physical log files are absent. Code Walkthrough To see the tool in action, you can trigger a log from a standard controller method: ```php public function index() { Log::info('User visited the homepage'); return view('welcome'); } ``` When you start the tool with `php artisan pail`, it listens for these events. If you purposely break your code to trigger an exception: ```php public function store(Request $request) { throw new \Exception('Data processing failed'); } ``` Laravel Pail immediately catches the crash. It displays the specific file and line number, the request type (e.g., GET or POST), and even the authentication status of the user who triggered the error. Practical Examples and Background Tasks This utility isn't limited to HTTP requests. If you have an Artisan command that dispatches a Queue job, Laravel Pail tracks those as well. It identifies which queue the job ran on and logs the output in the same unified stream. This is particularly useful when debugging asynchronous processes where traditional file logging becomes tangled. Tips & Gotchas A major advantage of this tool is its ability to function when using external log drivers like Sentry or Flare. Often, these drivers bypass local physical files, making it hard to see logs instantly. This tool captures the data before it leaves your application. For a cleaner experience, utilize filtering options to hide noise and focus strictly on specific log levels like `critical` or `error`.
Dec 4, 2025Overview of Multi-Tenancy Models Multi-tenancy allows a single application to serve multiple distinct groups of users, or tenants, while keeping their data invisible to one another. In the Laravel ecosystem, this architecture usually takes two forms: **single-database** and **multi-database** isolation. Choosing between them depends on your scale, legal requirements, and the nature of your customers. For B2C apps where users are individuals, a shared database with simple filtering is often sufficient. However, for B2B enterprises requiring strict data privacy, physically separating data into different databases is the standard. Prerequisites To follow this guide, you should be comfortable with PHP and the Laravel framework. Familiarity with Eloquent models, Middleware, and Artisan commands is essential. You should also understand basic DNS concepts like wildcards and subdomains if you plan to implement database-per-tenant isolation. Key Libraries & Tools * **stancl/tenancy**: A powerful package (also known as Tenancy for Laravel) that automates database creation, switching, and routing for multi-tenant apps. * **Laravel Fortify**: A front-end agnostic authentication backend used to handle registration and login logic. * **Laravel Herd**: A local development environment that simplifies managing subdomains and local testing. Code Walkthrough: Implementing Logic 1. Single Database Filtering In a shared database, you typically include an `organization_id` on every table. You can then use Eloquent scopes to ensure users only see their own data. ```php // TaskController.php public function store(Request $request) { // Automatically associate task with the user's organization $task = Task::create([ 'title' => $request->title, 'user_id' => auth()->id(), 'organization_id' => auth()->user()->organization_id, ]); } ``` 2. Multi-Database Setup with stancl/tenancy When using stancl/tenancy, the package handles the heavy lifting of switching database connections based on the current subdomain. You must define a `Tenant` model to track these entities. ```php // config/tenancy.php 'tenant_model' => App\Models\Tenant::class, // Creating a tenant during registration $tenant = Tenant::create(['id' => $subdomain]); $tenant->domains()->create(['domain' => $subdomain . '.yourapp.test']); ``` Syntax Notes & Authentication Pitfalls Modern Laravel starter kits often use Laravel Fortify, which abstracts routes into internal actions. When implementing subdomains, you must override the `LogoutResponse` and `LoginResponse` to ensure users are redirected to the correct tenant-specific URL. Without these overrides, the application might attempt to authenticate a user against the central database rather than the tenant-specific database, leading to failed logins. Tips & Gotchas When scaling a multi-database architecture, remember that you cannot easily perform cross-database joins. If your users are stored in the central database but tasks are in tenant databases, standard Eloquent relationships will fail. Furthermore, always use `tenants:migrate` instead of the standard migration command to ensure every tenant schema stays in sync. If one tenant grows massively, you may eventually need to move their specific database to a dedicated server, a process that requires robust DevOps orchestration.
Dec 4, 2025Elevating the CLI Experience Laravel Prompts transforms the traditionally sterile environment of command-line tools into a modern, interactive interface. While Laravel has long supported console commands via Artisan, this package introduces a polished aesthetic with borders, hints, and real-time validation. It shifts the developer focus from merely capturing input to guiding the user through a structured workflow. Prerequisites & Tools To get started, you should have a functional PHP environment and a Laravel project installed. Familiarity with Artisan commands is essential, as you will be implementing these prompts within the `handle()` method of your command classes. The core library is `laravel/prompts`, which provides the functional API used throughout this guide. Implementation Walkthrough Using the `text` function creates a clean input field. Unlike the standard `ask` method, `text` supports advanced metadata like placeholders and hints. ```php use function Laravel\Prompts\text; $name = text( label: 'What is the backup name?', placeholder: 'e.g. daily_backup', hint: 'This will be the filename suffix.', required: true ); ``` For more complex interactions, the `multiselect` function allows users to toggle multiple options using the spacebar, returning an array of selected values. This is perfect for defining backup scopes like databases, files, or media assets. ```php use function Laravel\Prompts\multiselect; $categories = multiselect( label: 'What should we include?', options: ['Database', 'Files', 'Media'], default: ['Database'] ); ``` Input Validation and Defaults Reliable CLI tools must prevent bad data. Laravel Prompts allows you to pass a closure to the `validate` parameter. If the logic returns a string, the CLI displays it as a red error message, keeping the user in the prompt until they provide valid data. Combining this with `default` values—such as a timestamped string—drastically reduces the friction for end-users running routine tasks. Tips and Best Practices Always use named arguments to keep your prompt definitions readable. When building tools for other developers, leverage the `hint` parameter to explain specific requirements, such as character limits or file formats. This documentation-in-terminal approach reduces the need for external manuals and prevents "trial and error" execution.
Dec 2, 2025Overview Modern web development often feels fragmented, requiring developers to juggle disparate libraries for routing, authentication, and database management. Laravel changes this by providing a unified, elegant toolkit that handles the heavy lifting, allowing you to focus on the "what" rather than the "how." This guide walks you through building **Chirper**, a micro-blogging platform similar to Twitter. You will learn how to initialize a project, implement the Model-View-Controller (MVC) pattern, manage a database with SQLite, and secure your application with a custom authentication system. Prerequisites To follow this tutorial, you should have a baseline understanding of **HTML**, **CSS**, and **PHP**. You need PHP 8.2+ and Composer (the PHP dependency manager) installed on your machine. Familiarity with the terminal or command prompt is essential, as we will use Artisan, Laravel's command-line interface, to scaffold our application components. Key Libraries & Tools * **Laravel Framework**: The core PHP framework providing the foundation for our app. * **Blade Templating**: Laravel's powerful engine for creating dynamic HTML layouts. * **Eloquent ORM**: An Active Record implementation for interacting with your database using PHP syntax instead of raw SQL. * **Tailwind CSS**: A utility-first CSS framework for rapid UI development. * **Daisy UI**: A component library built on top of Tailwind to provide pre-styled elements like cards and buttons. * **Vite**: The modern build tool used to compile and serve your frontend assets. * **Laravel Cloud**: A specialized platform for deploying and hosting Laravel applications with minimal configuration. Project Setup and Routing Setting up a new project starts with the Laravel installer. Running the command `laravel new chirper` initiates a wizard where you select your database (we recommend SQLite for beginners) and testing framework. Once initialized, the directory structure might look daunting, but most of your work happens in three places: `app/` (logic), `resources/` (UI), and `routes/` (URLs). Defining Your First Route Routes are the entry points of your application. In `routes/web.php`, you map a URL to a specific action. Initially, Laravel points the root URL (`/`) to a default welcome page. ```php use Illuminate\Support\Facades\Route; Route::get('/', function () { return view('home'); }); ``` Creating a Blade Layout Code duplication is the enemy of maintainability. Instead of rewriting the HTML head and navigation on every page, we use a **Blade Layout Component**. Create a file at `resources/views/components/layout.blade.php`. This file acts as a shell, using the `$slot` variable to inject content from specific pages. ```php <!-- resources/views/components/layout.blade.php --> <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>{{ $title ?? 'Chirper' }}</title> @vite(['resources/css/app.css', 'resources/js/app.js']) </head> <body> <nav>...</nav> <main> {{ $slot }} </main> </body> </html> ``` You can then wrap your home page content in this layout using the `<x-layout>` tag: ```php <!-- resources/views/home.blade.php --> <x-layout> <x-slot:title>Welcome to Chirper</x-slot> <h1>Latest Chirps</h1> </x-layout> ``` The MVC Pattern and Controllers Laravel follows the Model-View-Controller (MVC) architectural pattern. Think of a restaurant: the **Controller** is the waiter taking orders, the **Model** is the kitchen preparing data, and the **View** is the plated meal presented to the customer. To keep our `web.php` file clean, we move logic into a Controller. Generate a controller using Artisan: ```bash php artisan make:controller ChirpController --resource ``` The `--resource` flag is a powerhouse. It generates seven methods (index, create, store, show, edit, update, destroy) that cover every standard CRUD (Create, Read, Update, Delete) operation. Passing Data to Views Inside `ChirpController.php`, the `index` method fetches data and hands it to the view: ```php public function index() { $chirps = [ ['author' => 'Dev Harper', 'message' => 'Hello Laravel!', 'time' => '1m ago'], ]; return view('home', ['chirps' => $chirps]); } ``` Update your route to point to this controller: ```php use App\Http\Controllers\ChirpController; Route::get('/', [ChirpController::class, 'index']); ``` Database Management with Migrations and Eloquent To store real data, we need a database schema. Laravel uses **Migrations**, which are essentially version control for your database. Instead of sharing SQL dumps, you share migration files. Creating the Chirps Table Run `php artisan make:migration create_chirps_table`. In the generated file, define your columns: ```php public function up(): void { Schema::create('chirps', function (Blueprint $table) { $table->id(); $table->foreignId('user_id')->nullable()->constrained()->cascadeOnDelete(); $table->string('message'); $table->timestamps(); }); } ``` Apply the changes by running `php artisan migrate`. This command creates the table in your `database.sqlite` file. The Eloquent Model An **Eloquent Model** is a PHP class that represents a table. To interact with the `chirps` table, create a `Chirp` model: ```bash php artisan make:model Chirp ``` Inside the model, define **Mass Assignment** protections and relationships. Relationships allow you to access the author of a chirp without writing complex JOIN queries. ```php namespace App\Models; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsTo; class Chirp extends Model { protected $fillable = ['message']; public function user(): BelongsTo { return $this->belongsTo(User::class); } } ``` Implementing Authentication While Laravel offers starter kits like Breeze or Jetstream, building basic authentication manually provides deep insight into how sessions work. Registration and Hashing When a user registers, we must never store their password in plain text. Laravel provides the `Hash` facade for this. Use an **Invocable Controller**—a controller with only one method—to handle registration logic. ```php public function __invoke(Request $request) { $validated = $request->validate([ 'name' => 'required|string|max:255', 'email' => 'required|string|email|unique:users', 'password' => 'required|confirmed|min:8', ]); $user = User::create([ 'name' => $validated['name'], 'email' => $validated['email'], 'password' => Hash::make($validated['password']), ]); Auth::login($user); return redirect('/')->with('success', 'Account created!'); } ``` Protecting Routes with Middleware **Middleware** acts as a filter. If you want to ensure only logged-in users can post chirps, use the `auth` middleware in your routes: ```php Route::middleware(['auth'])->group(function () { Route::post('/chirps', [ChirpController::class, 'store']); Route::delete('/chirps/{chirp}', [ChirpController::class, 'destroy']); }); ``` Securing the App with Authorization Policies Authentication identifies *who* the user is; **Authorization** determines *what* they can do. You don't want User A deleting User B's chirps. Generate a policy: `php artisan make:policy ChirpPolicy --model=Chirp`. ```php public function update(User $user, Chirp $chirp): bool { return $chirp->user()->is($user); } ``` In your controller, simply call `authorize` before performing an update: ```php public function update(Request $request, Chirp $chirp) { $this->authorize('update', $chirp); // logic to update the chirp } ``` Syntax Notes * **Artisan Commands**: Always use `php artisan` followed by a command (e.g., `make:model`, `migrate`). It is the heartbeat of Laravel productivity. * **Blade Directives**: Use `@` symbols for logic in views. `@foreach`, `@if`, and `@auth` make templates readable. * **CSRF Protection**: Every HTML form must include the `@csrf` directive. This generates a hidden token that prevents cross-site request forgery attacks. * **Route Model Binding**: If a route is defined as `/chirps/{chirp}`, Laravel automatically fetches the `Chirp` model with that ID if you type-hint it in the controller method. Practical Examples 1. **Micro-blogging**: The Chirper app demonstrates real-time data entry and display. 2. **SaaS Dashboards**: The MVC and Policy patterns are essential for building secure multi-tenant software. 3. **API Development**: Laravel makes it trivial to return JSON instead of HTML views, allowing you to use the same logic for mobile apps. Tips & Gotchas * **Mass Assignment Error**: If you get a "MassAssignmentException," ensure you have added the column names to the `$fillable` array in your Model. * **Eager Loading**: Use `Chirp::with('user')->get()` instead of `Chirp::all()`. This prevents the "N+1" query problem, where the app makes a separate database call for every single user's name. * **Validation**: Always validate on the server side. Client-side validation (HTML `required` attribute) is for UX; server-side validation is for security. * **Deployment**: When moving to Laravel Cloud, ensure your environment variables (like `APP_KEY`) are properly configured to keep your sessions secure.
Sep 16, 2025Overview Most developers reach for Laravel Breeze or Jetstream when they need authentication. While these starter kits are powerful, they often include more code than a specific project requires. Building a login and registration system from scratch using only Laravel and Blade gives you absolute control over the user experience and the underlying logic. This approach strips away the abstraction, allowing you to understand how Laravel's authentication guards, sessions, and request validation actually interact. Prerequisites To follow this tutorial, you should have PHP 8.2 or higher installed on your machine. You need a basic understanding of the MVC (Model-View-Controller) architecture and how Laravel handles routing. Familiarity with the Terminal for running Artisan commands and a local database setup (like SQLite) is also required. Key Libraries & Tools * **Laravel Framework**: The core PHP framework providing the auth facades and routing engine. * **Blade Templating**: Laravel's native templating engine for creating dynamic HTML forms. * **SQLite**: A lightweight, file-based database used for quick development and testing. * **PHPStorm**: The IDE used for writing and managing the codebase during this walkthrough. Code Walkthrough 1. Defining the Routes Everything starts in `routes/web.php`. You must define routes for displaying the forms and handling the post requests. Unlike starter kits, we explicitly name our routes to keep our Blade templates clean. ```python Route::get('/login', function () { return view('login'); })->name('login'); Route::post('/login', LoginController::class)->name('login.attempt'); Route::get('/dashboard', function () { return view('dashboard'); })->name('dashboard')->middleware('auth'); ``` 2. The Login Controller Laravel makes manual authentication remarkably simple through the `Auth::attempt` method. This method automatically handles password hashing comparisons and session creation. Note the use of `request()->regenerate()` to prevent session fixation attacks. ```python public function __invoke(Request $request) { $credentials = $request->validate([ 'email' => ['required', 'email'], 'password' => ['required'], ]); if (Auth::attempt($credentials)) { $request->session()->regenerate(); return redirect()->intended('dashboard'); } return back()->withErrors([ 'email' => 'The provided credentials do not match our records.', ]); } ``` 3. Registering New Users For registration, you manually hash the password before saving it to the database. Laravel's `bcrypt` helper ensures the password isn't stored in plain text. After creating the user, use `Auth::login($user)` to immediately authenticate the new account. ```python public function store(Request $request) { $userData = $request->validate([ 'name' => 'required|string', 'email' => 'required|email|unique:users', 'password' => 'required|min:8', ]); $userData['password'] = bcrypt($userData['password']); $user = User::create($userData); Auth::login($user); return redirect()->route('dashboard'); } ``` Syntax Notes * **Single Action Controllers**: Using the `__invoke` method allows a controller to handle exactly one route, making your logic modular and easy to find. * **Blade Directives**: The `@csrf` directive is non-negotiable for any POST request in Laravel. It generates a hidden token field that protects your application against cross-site request forgery. * **Validation Arrays**: Passing an array of rules to `$request->validate()` is the standard way to ensure data integrity before it touches your database. Practical Examples This custom approach is ideal for specialized applications. For instance, if you are building an internal company tool that requires login via a unique **Username** instead of an email, you can simply swap the validation key in the controller and the input type in the Blade file. This flexibility is much harder to achieve when fighting against the rigid structures of a pre-built starter kit. Tips & Gotchas * **The Session Trap**: Always remember to call `session()->invalidate()` and `session()->regenerateToken()` during the logout process. If you don't, you leave the user's session vulnerable to hijacking. * **Rate Limiting**: Use the `throttle` middleware on your login routes. Without it, your app is an open target for brute-force attacks. A simple `middleware('throttle:5,1')` limits users to five attempts per minute. * **Fillable Property**: If you add new fields like `username` to your database, you must update the `$fillable` array in your `User` model. Otherwise, Laravel's mass-assignment protection will silently discard the data.
Apr 29, 2025Elevating Clean Code with Native Enum Support Laravel continues to bridge the gap between robust typing and configuration. In version 11.26, the framework expands its reach for native PHP enums into the caching layer. You can now use backed and unit enums directly for registering cache limiter configurations. This eliminates the need for hardcoded strings or messy class constants when defining rate limits. By allowing enums within named rate-limited middlewares, developers gain a centralized, type-safe way to manage application throttling, ensuring your infrastructure scales without losing its architectural integrity. Decoupling Logic with the Make Job Middleware Command Writing clean background jobs often becomes a challenge when you start mixing business logic with infrastructure concerns like rate limiting. Previously, you might find yourself cluttering a job's `handle` method with checks for timing or execution frequency. While job middleware existed, it lacked a dedicated scaffold. The new `make:job-middleware` Artisan command changes the workflow entirely. By moving rate-limiting logic into its own dedicated class, your primary job remains focused on its single responsibility—processing the data. This modular approach makes your codebase significantly easier to test and maintain, as you can now apply the same middleware across multiple job types with a simple array return in the `middleware()` method. Granular Control via the Stop Process Pool Method Managing concurrent tasks using the Symphony process wrapper in Laravel is already a massive productivity boost. However, stopping a running pool of tasks used to be an all-or-nothing affair that lacked a clean exit strategy. The latest update introduces a `stop()` method for process pools, allowing for immediate and graceful termination. When you trigger this method, Laravel leverages underlying system signals to shut down active processes without leaving orphaned tasks in the background. This is particularly useful for long-running CLI tasks where you need to abort a pool based on external conditions or user input while ensuring the server environment stays clean. Modernizing Your Backend Workflow These updates represent more than just minor patches; they reflect a commitment to developer experience. Whether it's the type-safety of enums or the CLI-first approach to job middleware, these features encourage best practices by making the right way the easy way. Start refactoring those bloated jobs into middleware today to see the difference in your code's readability.
Oct 9, 2024Overview Communication is the backbone of any application. Whether it is a welcome message or a critical system alert, you need to reach your users. Laravel provides two robust systems for this: **Notifications** and **Mailables**. While both can send emails, they serve different architectural purposes. Notifications excel at multi-channel delivery (Slack, SMS, database) to registered users, while Mailables offer a dedicated, view-centric approach for specific email-only communications. Prerequisites To follow this guide, you should have a baseline understanding of PHP and the Laravel framework. Familiarity with the Artisan CLI and basic MVC patterns will help you grasp the class-based structure of these features. Key Libraries & Tools * **Laravel Notifications**: A multi-channel system for sending alerts to models that use the `Notifiable` trait. * **Laravel Mail**: A dedicated system for building and sending rich email messages using Markdown or Blade. * **Laravel Herd**: A development environment used here to intercept and view sent emails locally. Code Walkthrough Implementing a Notification Use the CLI to generate a notification class for an organizer when a new signup occurs. ```bash php artisan make:notification NewSignup ``` Inside the class, define the data requirements and the email structure within the `toMail` method. By accepting the registrant's name and email in the constructor, you can inject dynamic data into the message. ```python public function toMail($notifiable) { return (new MailMessage) ->subject('New Meetup Registration') ->line('You have a new registered user: ' . $this->name) ->line('Email: ' . $this->email); } ``` Sending a Mailable For external guests who are not registered users, a Mailable is often cleaner. Generate it with a Markdown template: ```bash php artisan make:mail SignupConfirmed --markdown=emails.signup-confirmed ``` In your controller or Livewire component, trigger the delivery using the `Mail` facade. This targets a specific email address regardless of whether a corresponding user model exists. ```python Mail::to($email)->send(new SignupConfirmed($meetupName, $name)); ``` Syntax Notes * **Notifiable Trait**: Any model can receive notifications by including `use Notifiable;`. This enables the `$model->notify()` syntax. * **Fluent Interface**: Both systems use a fluent API (e.g., `->subject()`, `->line()`) to build message content programmatically. Practical Examples * **Notifications**: Use these for internal app events, like notifying a team on Slack when a high-value subscription is purchased. * **Mailables**: Use these for transactional requirements like invoices, password resets, or guest-facing newsletters where the recipient isn't in your `users` table. Tips & Gotchas * **Queuing**: Mail delivery can be slow. Always implement the `ShouldQueue` interface on your notification or mailable classes to keep your UI snappy. * **Testing**: Use `Mail::fake()` and `Notification::fake()` in your test suites to ensure communications trigger without actually hitting a mail server.
Sep 30, 2024Overview Command-line tools often feel rigid and unforgiving, but they don't have to. Laravel Prompts changes the game by bringing browser-like interactivity to the terminal. Instead of wrestling with complex SQL queries or manual PHP artisan tinker sessions for repetitive tasks, you can build elegant, validated interfaces. This tutorial demonstrates how to create a CLI tool to manage user data, specifically searching for users and deleting their archived posts with a modern UI. Prerequisites To follow along, you should be comfortable with PHP and the Laravel framework. You will need a working Laravel project with a database populated with users and posts. Familiarity with Composer for package management and Artisan commands is essential. Key Libraries & Tools - **Laravel Prompts**: The primary package used to create interactive terminal forms. - **PHP Artisan**: Laravel's built-in command-line interface for generating code and running tasks. - **Eloquent ORM**: Used for querying the database and handling model relationships. Code Walkthrough First, install the prompts package via Composer: ```bash composer require laravel/prompts ``` Generate your command using Artisan: ```bash php artisan make:command DeleteArchivedPosts ``` Interactive User Search Inside the `handle` method, we use the `search` function to find users. This provides an autocomplete experience that is far superior to typing raw IDs. ```php $userId = search( label: 'Search for the user to delete posts from', options: fn (string $value) => User::where('name', 'like', "%{$value}%") ->pluck('name', 'id') ->all() ); $user = User::find($userId); ``` Multi-Select and Validation We can validate that a user actually has posts before proceeding. If they do, the `multiselect` prompt allows us to cherry-pick specific records. ```php $postsToDelete = multiselect( label: 'Select the posts to delete', options: $user->posts()->where('is_archived', true)->pluck('title', 'id'), default: $user->posts()->where('is_archived', true)->pluck('id') ); ``` Handling Background Tasks with Spinners For long-running processes like bulk deletions or sending emails, the `spin` function keeps the user informed with a visual loading state. ```php spin( fn () => $user->posts()->whereIn('id', $postsToDelete)->delete(), 'Deleting posts...' ); ``` Syntax Notes Laravel Prompts utilizes functional wrappers around terminal I/O. Note how the `search` function accepts a closure for the `options` parameter, enabling real-time database filtering as the user types. The `pluck` method is frequently used here to map database results into the `[value => label]` format required by the prompts. Practical Examples Beyond deleting posts, this technique excels at: - **User Impersonation**: Finding a user and generating a temporary login URL. - **Resource Cleaning**: Identifying and removing orphaned files or old log entries. - **Onboarding Scripts**: Setting up local environment configurations via interactive questions. Tips & Gotchas Always ensure your search results return an associative array where the key is the unique identifier (like an ID) and the value is the display name. If you encounter an "Array to string conversion" error, double-check that you aren't trying to `echo` a collection returned by `multiselect`. Finally, wrap expensive operations in the `spin` function to prevent the terminal from looking frozen during execution.
Aug 14, 2024