Overview Laravel 13 introduces a significant shift in how developers configure classes by implementing 36 new PHP attributes. These attributes replace traditional protected properties—like `$fillable` or `$hidden`—with metadata directly above the class or method definition. This change aims to clean up class bodies and utilize native PHP 8 language features for better static analysis and cleaner syntax. Prerequisites To use these features, you should have a solid grasp of PHP 8 attribute syntax (`#[Attribute]`). You should also be familiar with Laravel's Eloquent ORM, job dispatching, and Artisan command structures. Key Libraries & Tools - **Laravel 13**: The latest version of the PHP framework. - **Eloquent**: The database mapper now supporting attribute-based model configuration. - **Livewire**: Often paired with these attributes in modern starter kits. Code Walkthrough Refactoring Eloquent Models Previously, you defined model behavior using class properties. In the new version, you apply them as attributes: ```php use Illuminate\Database\Eloquent\Attributes\Fillable; use Illuminate\Database\Eloquent\Attributes\Hidden; #[Fillable(['name', 'email'])] #[Hidden(['password'])] class User extends Model {} ``` Laravel reads these attributes at runtime, effectively populating the internal protected properties for you. Enhancing Queued Jobs For background tasks, you can now set retry limits and timeouts directly on the class: ```php use Illuminate\Queue\Attributes\Tries; use Illuminate\Queue\Attributes\Timeout; #[Tries(5)] #[Timeout(60)] class ProcessPodcast implements ShouldQueue {} ``` Syntax Notes Attributes utilize the `#[ ]` syntax. Unlike properties, attributes can take constructor arguments, allowing for cleaner configuration of complex settings like `ExponentialBackoff` within a single line. This moves configuration logic out of the class body and into the header. Practical Examples You can now define Artisan command signatures and descriptions without declaring variables: ```php #[Signature('app:send-emails {user}')] #[Description('Send a notification email to a specific user')] class SendEmails extends Command {} ``` Tips & Gotchas While Laravel now defaults to this style in its starter kits, these attributes are strictly optional. If you find multiple attributes on a single controller method hard to read, stick to the traditional `$middleware` arrays. Additionally, always ensure you import the correct namespace for each attribute to avoid "Attribute not found" errors.
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.
- Mar 19, 2026
- Feb 23, 2026
- Feb 5, 2026
- Dec 23, 2025
- Dec 17, 2025
Overview 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, 2024Overview Testing serves as the safety net for your application. It ensures that as you add features or refactor code, you don't accidentally break existing functionality. In the Laravel ecosystem, testing is a first-class citizen, providing developers with the tools to simulate user behavior, verify database states, and validate component rendering. Writing tests transforms your development process from "hoping it works" to "knowing it works." Prerequisites To follow along, you should have a baseline understanding of PHP and the Laravel framework. Familiarity with the command line is necessary for running Artisan commands. You should also understand the basics of Eloquent models and how routing works within a web application. Key Libraries & Tools * PEST: A functional testing framework for PHP focused on simplicity and readability. It offers a more expressive syntax compared to traditional class-based tests. * PHPUnit: The industry-standard testing framework for PHP. It uses a class-based approach where tests are defined as methods within a class. * Livewire%20Volt: An elegant, single-file component syntax for Livewire. It includes dedicated testing utilities for asserting component state. * Laravel%20Breeze: A minimal authentication scaffolding that comes pre-packaged with a comprehensive suite of tests, making it an excellent learning resource. Code Walkthrough: Your First Feature Test Let's break down the creation of a feature test for a To-Do manager. We want to ensure the page renders and that we can actually save data. Step 1: Generating the Test Run the following command to create a new test file: ```bash php artisan make:test ToDoTest ``` This creates a file in the `tests/Feature` directory. If you chose PEST during installation, it will use functional syntax; otherwise, it will use PHPUnit. Step 2: Testing Component Rendering We need to verify that a logged-in user can see our Livewire%20Volt component. ```python test('to do page is displayed', function () { $user = User::factory()->create(); $response = $this->actingAs($user) ->get('/dashboard'); $response->assertStatus(200); $response->assertSeeVolt('to-do-manager'); }); ``` Here, we use a factory to create a temporary user and `actingAs()` to simulate an authenticated session. The `assertSeeVolt` helper specifically checks if the Volt component is present on the page. Step 3: Testing Data Interaction Next, we test the logic of adding a task. We interact directly with the component state. ```python test('new to do can be added', function () { $user = User::factory()->create(); Volt::test('to-do-manager') ->set('title', 'My First Task') ->call('addToDo') ->assertHasNoErrors(); $this->assertDatabaseHas('to_dos', [ 'title' => 'My First Task', 'user_id' => $user->id, ]); }); ``` We use `Volt::test()` to mount the component, `set()` to fill the input field, and `call()` to execute the submission method. Finally, we check the database to ensure the record exists. Syntax Notes Notice the difference between **Feature** and **Unit** tests. Feature tests often use `$this->get()` or `$this->post()` to simulate HTTP requests. In PEST, we use the `test()` or `it()` functions, whereas PHPUnit requires `public function test_something()`. Always use the `refresh()` method on a model if you need to check its updated state after a database operation. Practical Examples * **Auth Gates:** Testing that only admins can access a specific dashboard. * **Form Validation:** Ensuring a user receives an error when they leave a required field blank. * **API Integrations:** Mocking a third-party payment gateway to verify your app handles successful and failed payments correctly. Tips & Gotchas Avoid the trap of testing implementation details. Focus on outcomes. If you change a variable name inside a method but the result remains the same, your test should still pass. A common mistake is forgetting to use the `RefreshDatabase` trait, which results in tests leaking data into each other. Always ensure your testing environment uses a dedicated database (like an in-memory SQLite instance) to keep runs fast and isolated.
Jul 30, 2024Overview Laravel continues to evolve by narrowing the gap between dynamic flexibility and static analysis. The latest updates to the Laravel Framework focus on three core pillars: developer experience through IDE support, streamlined CLI workflows, and a significant overhaul of the database migration engine. These changes ensure that whether you are sending emails or restructuring large databases, the framework behaves more predictably. Prerequisites To follow along with these updates, you should be comfortable with PHP and the Laravel ecosystem. Knowledge of the command-line interface (CLI) and basic database migration concepts is essential. You should have Laravel 11.15 or higher installed to access the interactive mail features. Key Libraries & Tools - **Eloquent ORM**: The built-in Active Record implementation, now supporting improved generics. - **Artisan**: Laravel's command-line interface used for generating boilerplate code. - **Laravel Prompts**: A package that provides beautiful, user-friendly forms for command-line applications. - **SQLite**: A lightweight database engine that received major migration compatibility updates. Code Walkthrough Interactive Mailable Generation Previously, creating a mailable with a view required passing multiple flags. Now, Artisan uses Laravel Prompts to guide you through the process. ```bash php artisan make:mail OrderShipped ``` Upon running this, the CLI will prompt you to select the view type. You can choose between **Markdown**, **Empty View**, or **No View**. This eliminates the need to remember specific flags like `--markdown` and ensures your mailable and template are linked correctly from the start. Predictable Migration Ordering One of the most critical fixes involves how commands are processed within a migration closure. In older versions, certain operations might execute out of order, leading to failures when renaming and recreating columns in a single step. ```python Schema::table('users', function (Blueprint $table) { $table->renameColumn('username', 'email'); $table->string('username'); // Now executes AFTER the rename }); ``` Laravel now preserves the exact order of these commands. This is particularly vital for SQLite, where the framework must recreate the entire table to apply schema changes. Syntax Notes - **Generics**: The inclusion of generics in the Eloquent Builder allows for better static analysis. This means your IDE can now understand exactly which model type a query will return without requiring third-party plugins. - **Migration Logic**: The framework now supports adding and dropping foreign and primary keys on SQLite, bringing its feature set closer to MySQL. Tips & Gotchas Always check your SQLite version. While the framework has lowered the version requirement to below 3.3.5, keeping your environment updated ensures compatibility with the new table-recreation logic used for complex migrations. When using `make:mail`, if you prefer the non-interactive way, you can still pass flags to bypass the prompts and maintain your automated scripts.
Jul 16, 2024