今日已更新 35 条资讯 | 累计 37284 条内容
关于我们

标签:#larave

找到 86 篇相关文章

AI 资讯

Stop rewriting your API responses in Laravel (Use this Trait instead)

If you are building API-driven applications, nothing clutters up your controllers faster than manually typing out response()->json(...) arrays every single time you need to return data or throw an error. When you have inconsistent response structures, your frontend (and the developers consuming your API) will constantly have to guess whether the data is nested under ['data'] , ['payload'] , or just at the root of the object. The cleanest way I've found to standardize this across an entire application is by creating a dedicated ApiResponse trait. Instead of rewriting your JSON structure in every controller method, create this trait in your app/Traits directory: namespace App\Traits ; use Illuminate\Http\JsonResponse ; trait ApiResponse { protected function success ( mixed $data , ?string $message = null , int $code = 200 ): JsonResponse { return response () -> json ([ 'status' => 'success' , 'message' => $message , 'data' => $data ], $code ); } protected function error ( string $message , int $code = 400 , array | string $errors = []): JsonResponse { // Force errors into an array format for consistent frontend parsing $formattedErrors = is_string ( $errors ) ? [ $errors ] : $errors ; return response () -> json ([ 'status' => 'error' , 'message' => $message , 'errors' => $formattedErrors ], $code ); } } Next, simply use this trait inside your base Controller.php . Now, your actual endpoints become incredibly readable and strictly standardized: namespace App\Http\Controllers ; use App\Models\Task ; use Illuminate\Http\Request ; use Illuminate\Http\JsonResponse ; use Throwable ; class TaskController extends Controller { public function store ( Request $request ): JsonResponse { $validated = $request -> validate ([ 'title' => 'required|string|max:255' , 'description' => 'nullable|string' ]); try { $task = Task :: create ( $validated ); return $this -> success ( $task , 'Task successfully generated' , 201 ); } catch ( Throwable $e ) { // Note: Exposing raw exception messa

2026-08-27 原文 →
开发者

I Built a Discord Server Discovery Platform

I Started Building a Discord Server Directory I’ve spent a lot of time around Discord communities, and one thing has always bothered me. Finding a good Discord server is harder than it should be. There are thousands of communities for gaming, anime, roleplay, technology, social groups and pretty much every niche you can think of. But finding the right one usually means jumping between invite links, old posts, server lists and search results. At some point I thought, why not build a better way to discover them? That’s how I started working on Dizord. The first version was pretty simple. I wanted a place where a server could be listed, people could discover it, and everything could be organized around interests instead of just one giant list of servers. Then the project started getting bigger. More servers meant more categories and tags. More tags meant better search and filtering. Server information changes constantly, so keeping listings updated became another problem to solve. I’m building the backend with Laravel and working with the Discord API to handle server information and synchronization. There are also a lot of small things behind the scenes that aren't obvious when you simply open a server listing page. One of the things I'm currently working on is making discovery better for smaller communities. A server shouldn't need tens of thousands of members just to be discoverable. The goal is pretty simple: Make it easier to find a Discord community you'll actually want to stay in. The project is still evolving, but the current version is live: https://dizord.com I'm still experimenting with search, categorization, server activity and ways to make a large directory useful instead of overwhelming. If you're building a directory, marketplace, or any project with thousands of constantly changing pages, I'd also be interested in hearing how you handle discovery and indexing at scale.

2026-08-27 原文 →
AI 资讯

How I Debugged a phpMyAdmin 500 Error While Importing a Large SQL File on Laragon

I recently ran into a weird issue while working on a Laravel project on Windows using Laragon . Everything was working fine until I tried to import a database through phpMyAdmin. Instead of an SQL error, phpMyAdmin simply returned: Internal Server Error The server encountered an internal error or misconfiguration... No useful message. Just HTTP 500. My SQL file was around 97 MB , so at first I thought it was probably a PHP upload limit issue. It wasn't that simple. Here is how I debugged it. 1. Check which PHP configuration is actually running From Laragon Terminal: php --ini Then I checked the important error settings: php.exe -r "echo 'error_log=' . ini_get('error_log') . PHP_EOL;" php.exe -r "echo 'log_errors=' . ini_get('log_errors') . PHP_EOL;" php.exe -r "echo 'display_errors=' . ini_get('display_errors') . PHP_EOL;" My output was: error_log=D:/C-data/laragon/tmp/php_errors.log log_errors=1 display_errors=1 One small Laragon/Git Bash issue I also found was: type php returned: php is aliased to `winpty php.exe' Because of that, commands like: php -i | grep ... sometimes returned: stdout is not a tty Using php.exe directly avoids that problem. 2. Check the PHP error log My PHP error log was: D:/C-data/laragon/tmp/php_errors.log I reproduced the import error and checked it: tail -n 50 /d/C-data/laragon/tmp/php_errors.log Nothing useful appeared. That was an important clue. 3. Make sure browser PHP and CLI PHP use the same php.ini I created a temporary file: <?php phpinfo (); Then opened it through the browser. Important values were: Server API: CGI/FastCGI PHP Version: 8.4.4 Loaded Configuration File: D:\C-data\laragon\bin\php\php-8.4.4-nts-Win32-vs17-x64\php.ini My PHP limits were already high enough: upload_max_filesize = 512M post_max_size = 512M memory_limit = 512M max_execution_time = 36000 So the 97 MB SQL file should have been allowed by PHP. 4. Check Apache logs I located the Apache error log with: grep -Ri "ErrorLog" /d/C-data/laragon/etc/apache2 /d/C-da

2026-08-25 原文 →
AI 资讯

Credits, plans and quotas in Laravel with Larameter

If your app sells an allowance, a number of credits a month, or a number of documents, or a number of anything. Whatever it is, you end up writing a balance somewhere, a reset when the period rolls over, a check before the expensive call, and a usage screen that has to agree with all of it. None of that is hard on its own. What gets you is that the pieces drift. The plan says a thousand a month, the reset runs on the first of the month, the subscription renews on the 18th, and the screen sums a table that the charging code stopped writing to two features ago. And then somebody adds a weekly cap and now there are two numbers per plan to keep consistent, times seven plans. So after repeating the same on many apps, just created Larameter. It's basically what you see in Claude or OpenAI subscription plans. It meters credits against a plan, enforces ceilings on things that exist rather than things that are spent, and works out which plan an account is on instead of storing it. How to install Just install the package via composer as usually: composer require edulazaro/larameter php artisan vendor:publish --tag = larameter-config php artisan vendor:publish --tag = larameter-migrations php artisan migrate Then add the trait to whatever you bill. An organisation, a user, a workspace: the package does not care, and it does not need a column on your table. use EduLazaro\Larameter\Concerns\HasCredits ; class Organization extends Model { use HasCredits ; } The account row appears the first time you touch it. What are allowances One period is rarely enough. A monthly figure alone lets a bad afternoon eat the month, so you want a weekly cap on top, and maybe a per-session one. Declare those windows once: 'windows' => [ 'session' => [ 'minutes' => 300 , 'anchor' => 'rolling' , 'share' => 0.04 ], 'weekly' => [ 'days' => 7 , 'anchor' => 'fixed' , 'share' => 0.25 ], 'monthly' => [ 'months' => 1 , 'anchor' => 'fixed' , 'share' => 1 ], ], And then a plan grants 1 figure , which every wi

2026-08-24 原文 →
AI 资讯

Building PickTool with Next.js and Laravel: Lessons from Creating a Software Discovery Platform

Finding software is easy. Finding the right software is not. Search for almost any category—email marketing, CRM, productivity, design, or AI—and you will find hundreds of options. Every product presents itself as the best choice, while many comparison articles repeat the same features without explaining which users each tool actually suits. That problem inspired me to build PickTool , a platform for discovering and comparing AI and SaaS tools. PickTool is still evolving. I am currently improving its content quality, tool coverage, comparison experience, performance, and SEO structure. This is not a polished launch announcement. It is an honest look at the architecture behind the project and some of the lessons I have learned while building it. What Is PickTool? The goal of PickTool is simple: Help people find the right software in minutes, not hours. Instead of creating a basic directory filled with product names and affiliate links, I want each important tool to include useful and structured information, such as: Core features Pricing model Best use cases Strengths and limitations Ratings and evaluation criteria Alternatives Direct comparisons Related guides and category pages The challenge is that this creates several interconnected types of content. A single product can appear on its own tool page, inside a category, in multiple comparisons, and in articles about the best software for a particular use case. Keeping all of this consistent requires more than publishing isolated blog posts. Why I Chose Next.js and Laravel PickTool uses a decoupled architecture: Next.js powers the public-facing website. Laravel powers the backend, API, database logic, and administration system. MySQL stores tools, categories, ratings, pricing information, and editorial content. I chose this combination because I wanted the frontend and content-management logic to evolve independently. Laravel provides a structured backend for managing relationships between tools and content. Next.js

2026-08-24 原文 →
AI 资讯

Building a Personal Blog with Laravel: A Real World Project

A personal blog sounds like a simple Laravel project. Create posts, show them on the homepage, and you are done. But once you start adding search, categories, tags, comments, SEO, authentication, analytics, and an admin panel, things become much more interesting. I built this Laravel Personal Blog as a real world project to explore those problems instead of building another basic CRUD application. The complete source code is available on GitHub: https://github.com/arafat-web/laravel-personal-blog Table of Contents What Is This Project? Technology Stack Main Features Project Structure How Visitor Analytics Works SEO and Content Management How to Run the Project What I Learned Final Thoughts What Is This Project? This is a complete single-author blogging platform built with Laravel. It includes both a public blog and a custom admin panel. The project was built without additional application packages, so most of the important functionality is visible in the codebase itself. The public side contains: Homepage Blog posts Categories Tags Search Comments RSS feed Sitemap SEO metadata Post view tracking The admin panel contains: Dashboard Post management Category and tag management Comment moderation User management General settings SEO settings Visitor analytics Technology Stack The project uses: PHP 8.3+ Laravel 13.17 MySQL or SQLite Blade Eloquent ORM JavaScript CSS PHPUnit The current project configuration requires PHP 8.3 and Laravel 13.17. Main Features The project goes beyond basic CRUD. For example, posts can have categories, tags, comments, authors, featured images, publishing status, and view counts. The Post model defines these relationships using Eloquent: public function user (): BelongsTo { return $this -> belongsTo ( User :: class ); } public function categories (): BelongsToMany { return $this -> belongsToMany ( Category :: class ); } public function tags (): BelongsToMany { return $this -> belongsToMany ( Tag :: class ); } public function comments (): HasMa

2026-08-23 原文 →
AI 资讯

5 Laravel Authorization Problems You're Probably Facing (And How to Solve Them in 2026)

TL;DR: Most Laravel apps hit the same 5 authorization walls as they grow — role explosion, exception handling, multi-tenancy, contextual permissions, and debugging nightmares. This deep dive shows how to solve each one with modern patterns, and introduces a package that combines all solutions: Laravel Permission Manager . 🔗 GitHub · 📦 Packagist 📋 Table of Contents Introduction: The Authorization Ceiling Problem #1: The Role Explosion Trap Problem #2: The "Except This One" Problem Problem #3: The Multi-Tenant Nightmare Problem #4: The "Can They Edit THIS Post?" Problem Problem #5: The Silent Cache Bug Bonus: The 3 AM Debugging Nightmare The Complete Solution Real-World Implementation Comparison with Spatie Final Thoughts 🎯 Introduction: The Authorization Ceiling Every Laravel project starts with the same authorization story: // Day 1: Simple and beautiful if ( $user -> is_admin ) { // show admin stuff } By month three, it looks like this: // Month 3: Starting to hurt if ( $user -> hasRole ( 'admin' ) || ( $user -> hasRole ( 'editor' ) && $post -> status === 'draft' ) || ( $user -> hasRole ( 'manager' ) && $post -> department_id === $user -> department_id )) { // ... } By year one, you've got authorization logic scattered across controllers, policies, middleware, and blade templates — with no clear source of truth. This is what I call "The Authorization Ceiling" : the point where basic RBAC stops working and you need something more sophisticated. In this article, we'll explore the 5 most common authorization problems Laravel developers hit, why traditional solutions fail, and how modern patterns (and modern packages) solve them cleanly. 🔴 Problem #1: The Role Explosion Trap The Symptom Your application has roles: admin , editor , viewer . Life is good. Then the product team asks: "Can we have an admin who can't delete users?" "Can we have an editor who can publish but not delete?" "Can we have a viewer who can export reports?" Before you know it, you have 47 roles in

2026-08-20 原文 →
AI 资讯

Você criou uma tabela de tokens pra proteger PDF. O Laravel já fazia isso.

O contrato do cliente tá numa URL que qualquer um adivinha A tarefa parecia simples: o cliente precisa baixar a nota fiscal dele. Você salvou em storage/app/public/notas/ , rodou php artisan storage:link , mandou o link e foi feliz. https://app.com/storage/notas/nota-1042.pdf . Semanas depois cai a ficha. Aquele arquivo está aberto na internet . Sem login, sem nada. E o nome é sequencial: quem baixou a nota-1042.pdf só precisa de curiosidade e cinco segundos pra tentar a 1041 . E a 1040 . Então você faz a coisa certa: tira do disco público e cria um sistema pra controlar acesso. Tabela download_tokens , model, geração de UUID, coluna expires_at , controller que valida, e um comando no scheduler pra limpar os vencidos. Sessenta linhas depois, funciona. E aí alguém comenta no PR: "por que você não usou uma URL assinada?" O sistema que você não precisava construir // ❌ migration + model + controller + command. tudo isso pra um PDF. Schema :: create ( 'download_tokens' , function ( Blueprint $table ) { $table -> id (); $table -> uuid ( 'token' ) -> unique (); $table -> string ( 'path' ); $table -> foreignId ( 'user_id' ); $table -> timestamp ( 'expires_at' ); $table -> timestamps (); }); public function gerarLink ( NotaFiscal $nota ): string { $token = DownloadToken :: create ([ 'token' => Str :: uuid (), 'path' => $nota -> arquivo_path , 'user_id' => auth () -> id (), 'expires_at' => now () -> addMinutes ( 10 ), ]); return route ( 'download' , $token -> token ); } Não tem nada de errado tecnicamente. O problema é o custo: mais uma tabela crescendo pra sempre, mais um comando no scheduler, mais um caminho pra testar. E você vai manter isso enquanto o projeto existir. O Laravel resolve o mesmo problema com uma assinatura criptográfica na própria URL. Sem estado, sem tabela, sem limpeza. Como uma URL assinada funciona A ideia é bonita de simples: o Laravel monta a URL com os parâmetros que você quer, calcula um hash disso tudo usando a APP_KEY e cola o hash no final. /not

2026-08-18 原文 →
AI 资讯

Seu log tem 40 mil linhas e nenhuma resposta

"Deu erro ao salvar, umas duas da tarde" É a única informação que você tem. O cliente não lembra o que clicou, não tirou print e já fechou a aba. Você abre o laravel.log . Quarenta mil linhas no dia. Faz um grep por "erro". Aparecem 1.200 ocorrências, e a maioria é isso: [2026-08-14 14:03:11] production.INFO: entrou [2026-08-14 14:03:11] production.INFO: erro aqui [2026-08-14 14:03:12] production.INFO: passou [2026-08-14 14:03:12] production.ERROR: Erro ao salvar Erro ao salvar o quê ? De qual usuário? Qual pedido? Qual valor? Aquele entrou da linha de cima é do mesmo request ou de outro cliente que estava usando o sistema no mesmo segundo? Você tem log. Você não tem informação. São coisas diferentes. O problema não é a falta de log. É o excesso de log inútil. public function emitir ( Pedido $pedido ) { Log :: info ( 'entrou no emitir' ); try { $nota = $this -> sefaz -> emitir ( $pedido ); Log :: info ( 'emitiu' ); } catch ( Throwable $e ) { // parabéns, você registrou que algo deu errado em algum lugar 🎉 Log :: error ( 'Erro ao emitir nota' ); return back () -> withErrors ( 'Falha na emissão' ); } } Repara no que esse catch jogou no lixo: a mensagem da exceção, o stack trace, o ID do pedido, o CNPJ, o retorno da SEFAZ. Tudo estava ali, na mão, e foi substituído por uma frase genérica. E os Log::info('entrou') espalhados? Aquilo foi debug que virou permanente. Hoje eles só servem pra empurrar as linhas úteis pra fora da tela. Duas perguntas que todo log precisa responder Um log serve pra duas plateias: você, com sono, às 3h da manhã — e uma máquina , filtrando milhões de linhas. As duas querem a mesma coisa: O que aconteceu , numa mensagem que não muda nunca. Com quem aconteceu , em dados separados da mensagem. Essa separação é o pulo do gato. Repare na diferença: // ❌ mensagem única pra cada pedido. impossível agrupar ou contar. Log :: error ( "Falha ao emitir nota do pedido { $pedido -> id } do cliente { $cliente -> nome } " ); // ✅ mensagem estável + contexto est

2026-08-18 原文 →
AI 资讯

Middleware é porteiro, não gerente

Ele começou com um if . Hoje tem 80 linhas. Sabe como é: precisava barrar quem não tem assinatura ativa. Um middleware, três linhas, resolvido. Depois entrou o período de teste. Depois o plano legado que tem regra diferente. Depois "aproveita que já buscou a assinatura e desconta um crédito". Depois o e-mail de aviso quando faltam 3 dias pro vencimento. Hoje esse arquivo tem 80 linhas, faz quatro queries, altera dado no banco e dispara e-mail. Ele não é mais um middleware. É um Service que mora na pasta errada e roda em todo request. E o pior: essa regra não existe pro resto do seu sistema. O middleware que virou gerente class VerificarAssinatura { public function handle ( Request $request , Closure $next ): Response { $assinatura = $request -> user () -> assinatura ; if ( ! $assinatura || $assinatura -> venceu ()) { return redirect () -> route ( 'planos' ); } // "aproveita que já tá aqui" 🙃 if ( $assinatura -> creditos < 1 ) { return redirect () -> route ( 'planos' ) -> withErrors ( 'Sem créditos' ); } $assinatura -> decrement ( 'creditos' ); $assinatura -> update ([ 'ultimo_acesso' => now ()]); if ( $assinatura -> vence_em -> diffInDays ( now ()) <= 3 ) { Mail :: to ( $request -> user ()) -> send ( new AssinaturaVencendo ( $assinatura )); } return $next ( $request ); } } Funciona. Passa nos testes de feature. E tem quatro problemas escondidos que só aparecem meses depois. Problema 1: middleware só existe no HTTP Esse é o grande. Middleware é uma camada de request HTTP . Ela não roda em outro lugar nenhum. Então: O comando php artisan relatorio:gerar não desconta crédito. O job na fila não desconta crédito. Sua rota de API que você esqueceu de agrupar não desconta crédito. O tinker passa por cima de tudo. Você não criou uma regra de negócio. Criou uma regra da porta da frente . Qualquer outra entrada no sistema ignora ela. E, sério, isso não é hipótese: um dia alguém vai criar um endpoint novo, esquecer o middleware, e a assinatura vira um detalhe decorativo. Probl

2026-08-18 原文 →
AI 资讯

Building Vendzoo: How I Built a Full Business OS for SMEs — Fraud Detection, 4 Couriers, RFM Engine & More

From COD fraud nightmares to automated intelligence: the story of building a business platform for Bangladesh's e-commerce market. 🎯 The Problem That Started Everything Picture this. A small shop owner is managing their online business. They've got WooCommerce for the website, Excel sheets for stock tracking, Pathao open on one phone, Steadfast on another, and Facebook Page orders coming in through DMs. They have a physical notebook for customer history, and absolutely no way to know if a new customer is a fraudster who'll refuse the delivery. Every morning starts with copy-pasting order details from three different places. Every afternoon is spent manually messaging courier agents. Every evening is reconciling which orders got delivered, which got returned, and how much money actually came in. This isn't a unique story. This is the daily reality of thousands of SME owners, retailers, and e-commerce merchants. I built Vendzoo to end this chaos. Vendzoo is an all-in-one SaaS Business OS: POS, Inventory, Courier, Fraud Detection, Customer Intelligence, Marketing, and Analytics, all in one dashboard. 🌐 vendzoo.com This is the story of how it was built, the real problems we solved, and the decisions that shaped the product. 🏗️ The System at a Glance Vendzoo is built on Laravel 13 with PHP 8.3 , backed by MySQL, with a Tailwind CSS v4 and Vite 8 frontend. Nothing exotic, just a solid, modern stack chosen for reliability and developer ergonomics. What makes it interesting isn't the stack. It's the three layers sitting on top of it. The core layer handles POS, orders, inventory, invoicing, and multi-user access with role-based permissions. The integration layer connects to everything a merchant already uses: WooCommerce, Shopify, Facebook Commerce, Pathao, Steadfast, RedX, Carrybee, Firebase, Telegram, SMS, WhatsApp, and Email. The intelligence layer is where Vendzoo earns its "Business OS" label: a fraud risk engine, customer segmentation, churn prediction, courier perfor

2026-08-15 原文 →
AI 资讯

Laravel Development Process: From Idea to Production

Building a Laravel application involves much more than writing PHP code. A production application needs to solve a real business problem, handle users and data reliably, survive deployments, remain secure, and continue to be maintainable as requirements change. Laravel provides an excellent foundation for building modern web applications, but the framework is only one part of the development process. A successful Laravel project typically moves through several stages, from understanding the original business idea to deploying, monitoring, and improving the application in production. Here is what that process looks like. 1. Start With the Business Problem Before thinking about controllers, models, databases, or cloud infrastructure, the first step is understanding what the application actually needs to accomplish. A project might begin with a simple request: "We need a customer portal." That's a starting point, but it isn't a specification. What should customers be able to do? Create and manage accounts? Upload documents? Manage subscriptions? Make payments? View reports? Communicate with employees? Receive notifications? Manage multiple users within an organization? These questions start turning an idea into actual application requirements. One of the easiest ways for a software project to become unnecessarily expensive is to begin development before the problem has been clearly defined. Laravel can make development faster, but building the wrong application faster doesn't solve the underlying problem. 2. Define the MVP Once the requirements become clearer, the next step is determining what belongs in the first release. I generally separate features into two categories: What does the application need in order to provide value? and What can be added later? The first category becomes the Minimum Viable Product, or MVP. For example, a new SaaS application might initially require: User registration Authentication Account management Subscription billing The application's

2026-08-12 原文 →
AI 资讯

The Laravel 13 Features That Matter in Real Projects

The Laravel 13 Features That Matter in Real Projects Laravel 13 shipped on March 17, 2026, and the upgrade story is unusually simple: zero application-level breaking changes from Laravel 12, one hard requirement (PHP 8.3), and several features that are genuinely useful in production rather than just impressive in release notes. This post focuses on the features you will actually reach for on real client projects — not an exhaustive tour. For the full release overview, upgrade checklist, and breaking changes reference, see Laravel 13: Features, Upgrade Guide, and Breaking Changes . Prerequisites: PHP 8.3+, Laravel 13.x (latest stable: 13.14.0 as of June 2026), Composer 2.x. 1. PHP Attributes on Models and Controllers Laravel 13 adds PHP 8-style #[Attribute] support across 15+ framework locations. The old property-based syntax still works — this is purely additive. On Eloquent Models: use Illuminate\Database\Eloquent\Attributes\Table ; use Illuminate\Database\Eloquent\Attributes\Fillable ; use Illuminate\Database\Eloquent\Attributes\Hidden ; #[Table('posts', primaryKey: 'id', incrementing: true, timestamps: true)] #[Fillable('title', 'body', 'user_id')] #[Hidden('deleted_at')] class Post extends Model {} On Controllers: use Illuminate\Routing\Attributes\Controllers\Authorize ; use Illuminate\Routing\Attributes\Controllers\Middleware ; #[Middleware('auth')] class CommentController extends Controller { #[Middleware('subscribed')] #[Authorize('create', [Comment::class, 'post'])] public function store ( Post $post ) { } } When to actually use this: Attributes shine on large domain models where $fillable , $hidden , $casts , and relationship declarations are scattered across the class. Collocating table definition and mass assignment rules at the top of the file improves readability at a glance. On small CRUD models, the tradeoff is extra import lines for minimal gain. Common mistake: Mass-converting every existing model to attribute syntax in a single PR. It creates a lar

2026-08-10 原文 →
AI 资讯

Building a Multi-Vendor Home Services Marketplace with Laravel: Architecture, Workflows and Key Decisions

Building a Multi-Vendor Home Services Marketplace with Laravel: Architecture, Workflows and Key Decisions Building a home services marketplace looks straightforward until you start mapping the actual workflows. A customer searches for a service, chooses a provider, selects a time slot, enters an address, pays, and receives confirmation. Simple enough. But behind that booking are several systems working together: customers, providers, services, locations, schedules, bookings, payments, invoices, notifications, and administration. For Laravel developers, the real challenge isn't creating another CRUD application. It's designing these components so the marketplace remains maintainable as providers, locations, services, and bookings grow. This article explores some of the most important architecture and development decisions to consider when building a multi-vendor home services marketplace with Laravel. 1. Think of It as Three Connected Applications A useful starting point is to stop thinking about the marketplace as one application. In practice, you're creating experiences for three different types of users: Customers Service Providers Marketplace Administrators Each has different responsibilities and permissions. Customer Experience Customers typically need to: Register and manage their account Select their location Discover services Find available providers View service details Choose an appointment date and time Save service addresses Create bookings Make payments View booking history Access invoices The customer interface should remain simple even if the system behind it is complex. A typical booking flow may look like: Location → Service → Provider → Date & Time → Address → Payment → Confirmation Every unnecessary step increases friction. 2. The Provider Side Is a Different Product The provider dashboard deserves just as much attention as the customer interface. A service professional or company may need to manage: Business profile Services Pricing Service areas

2026-08-09 原文 →
AI 资讯

Building Robust Crypto Data Pipelines in PHP: Introducing the Token Terminal SDK

The cryptocurrency and decentralized finance ecosystems generate an overwhelming amount of data every single day. For developers building financial dashboards, algorithmic trading tools, or market research platforms, accessing clean, standardized, and reliable data is absolutely critical. Token Terminal has established itself as a premier provider of fundamental financial data for the crypto space, offering institutional-grade metrics across various blockchains and decentralized applications 1 . However, integrating complex third-party APIs into enterprise PHP applications often requires writing significant amounts of boilerplate code to handle edge cases, rate limits, and unexpected response structures. To solve this problem and streamline the developer experience, the PHP community now has access to a dedicated solution: the tokenterminal-php SDK. This new open-source package provides a robust, fully-typed, and developer-friendly PHP 8.1+ client for the Token Terminal API v2 2 . Designed with modern PHP standards and framework integration in mind, it abstracts away the complexities of the underlying HTTP transport, allowing developers to focus entirely on building their applications rather than wrestling with API mechanics. The Challenge of Integrating Financial APIs When working with comprehensive financial data APIs like Token Terminal, developers frequently encounter several architectural challenges. First, there is the issue of rate limiting. Token Terminal enforces a strict limit of 1,000 requests per minute 3 . When building data pipelines that ingest historical metrics across hundreds of assets, hitting this limit is practically guaranteed. A naive implementation will simply crash or drop data, requiring manual intervention. Second, the cryptocurrency space moves rapidly. Projects frequently rebrand, merge, or migrate to new smart contracts. The Token Terminal API handles this gracefully by issuing HTTP 308 Permanent Redirects when a requested project ID ha

2026-08-09 原文 →
AI 资讯

I stopped hardcoding locales, and adding a language became a one-line change

Most i18n tutorials stop at "put your strings in a JSON file". That covers labels. It does not cover the thing that actually breaks: URLs. I run a personality test site in five locales (French, English, Brazilian Portuguese, European Portuguese, Spanish). Same site, five language trees, roughly 96 articles each. The first version had the shape every project seems to grow by accident: $prefix = $locale === 'en' ? '/en' : '' ; That line, or a cousin of it, spread across controllers, views and helpers. Every one of them was correct when written and wrong the moment a third locale showed up. The bug it produces is the worst kind: nothing throws, the page renders, and the Spanish version quietly links to French URLs. The rule that fixed it One rule, enforced by a test: no locale literal anywhere outside the config file. Not in controllers, not in views, not in helpers. If code needs to know something about a locale, it asks the config. Adding a locale then becomes: content files, plus one entry in config/locales.php . Nothing structural. 'default' => 'fr' , 'available' => [ 'fr' , 'en' , 'pt-br' , 'pt-pt' , 'es' ], Three helpers cover essentially every call site: locale_prefix () // '' for the default locale, '/es' otherwise locale_url ( '/disc' ) // prefixed, canonical, ready to print locale_slug ( 'groupe' ) // the localized route segment The part nobody warns you about: slugs are data Labels translate. Slugs are a different problem, because a slug is simultaneously a URL, a cache key, an SEO asset and a foreign key into your own content. The decision that saved me: one locale is canonical, always. French, in my case. Every slug in every other language resolves back to a French slug before anything else happens. $slugs = app ( SlugService :: class ); $slugs -> toLocale ( 'quatre-tendances' , 'es' ); // 'cuatro-tendencias' $slugs -> resolveToCanonical ( 'cuatro-tendencias' ); // 'quatre-tendances' Without that pivot you get N-to-N translation tables and, eventually, two

2026-08-08 原文 →
AI 资讯

Add toast messages in Laravel with Wiretoast

Fire toast notifications in Laravel from PHP, Alpine and plain JavaScript with one notify call, plus positioning, auto-dismiss and grouping, and no CSS framework in your bundle Here is a problem I hit on every project. A Livewire action finishes and I need to tell the user it worked, but the toast library I grabbed assumes Tailwind, or ships its own huge runtime, or only works from JavaScript when half my triggers actually live in PHP. Wiretoast is my answer to that, and this post is the fast path to using it. The problem You want to fire a toast from PHP, from Alpine, and from plain JavaScript with the same call, and you do not want to drag a CSS framework into your bundle to get it. How to install Start with Composer, then wire up the assets. I bundle with Vite, so I import the package CSS and JS into my entry files. // resources/js/app.js import ' @wiretoast/js/wiretoast.js ' ; import ' @wiretoast/css/wiretoast.css ' ; That @wiretoast alias is optional, and you set it up by pointing Vite at the vendor resources folder so the imports stay short. // vite.config.js resolve : { alias : { ' @wiretoast ' : path . resolve ( __dirname , ' vendor/edulazaro/wiretoast/resources ' ), }, }, Then the component goes once into your layout, and on the Vite path it injects no tags of its own. <x-wiretoast /> How to use it The fastest possible win is a one-liner in a Livewire component right after something succeeds. The helper is a component macro named notify , registered for you when Livewire is present. $this -> notify ( 'Profile updated' , 'success' ); Under the hood that dispatches a notify browser event, which is exactly what Alpine fires too. So the same toast from a purely front-end button looks like this. <button @ click= "$dispatch('notify', { message: 'Copied', type: 'info' })" > Copy link </button> The five types you can pass are success , error , warning , info and neutral , and a message can be a plain string or an object with a title and a message when you want a he

2026-08-06 原文 →
AI 资讯

Generate your entire Laravel CRUD stack with one Artisan command

TL;DR — composer require bouda/laravel-make-pattern → php artisan make:pattern Post → 9 consistent files in seconds. DDD-ready, rollback included, every stub is yours to override. The problem I kept running into Every new Laravel project starts the same way. You know the architecture you want: Repository, Service, Controller, some Form Requests, a Resource, a Policy, a test. You've written this stack dozens of times. And every time, you either: Copy-paste from a previous project — and immediately introduce inconsistency between how PostRepository is structured vs CategoryRepository . Write everything from scratch — which is slow and error-prone. Use make:model -a — which gives you the Model, Migration, Factory, Controller, but nothing about repositories, services, or policies wired together. None of these feel like the right answer when you want a clean, layered architecture. So I built laravel-make-pattern . What it does One command: php artisan make:pattern Post Generates 9 files : app/Models/Post.php app/Repositories/Contracts/PostRepositoryInterface.php app/Repositories/PostRepository.php app/Services/PostService.php app/Http/Controllers/PostController.php app/Http/Requests/PostStoreRequest.php app/Http/Requests/PostUpdateRequest.php app/Http/Resources/PostResource.php app/Policies/PostPolicy.php tests/Feature/PostTest.php All consistently named, all using the same conventions, all generated from stubs you own and can override . The generated code Here's what the repository looks like out of the box: <?php namespace App\Repositories ; use App\Models\Post ; use App\Repositories\Contracts\PostRepositoryInterface ; class PostRepository implements PostRepositoryInterface { public function all () { return Post :: all (); } public function find ( string $id ) { return Post :: findOrFail ( $id ); } public function create ( array $data ) { return Post :: create ( $data ); } public function update ( string $id , array $data ) { $model = $this -> find ( $id ); $model -> u

2026-08-06 原文 →
AI 资讯

Turn Claude Code into a Laravel expert with LaraClaude

Claude Code writes PHP in Laravel quite well, but it starts every session as a generalist. It does not know your project has three hundred migrations that should be thirty, that a @foreach two files over is firing an N+1, or that your modals follow one specific pattern. You end up re-explaining the same context constantly. LaraClaude packages that context as slash commands. It is a Claude Code plugin with over thirty Laravel skills, each a /lc: command. Install it once and you have audits, scaffolders and cleanup tools that already know Laravel. Here are the ones I run most. How to install LaraClaude installs through Claude Code's plugin system. Add the marketplace once, then install, so you get updates later: /plugin marketplace add edulazaro/laraclaude /plugin install laraclaude@edulazaro Or grab it directly from GitHub: /plugin install github:edulazaro/laraclaude You need Claude Code and a Laravel project. That is it for most skills; a couple that hit a live database also want Docker. Audit before you change anything Most skills default to a read-only report and only touch files when you add fix , so start by looking. /lc:find-n-plus-one scans your Blade views, Livewire components and controllers for a relationship accessed inside a loop, traces it back to the query that built the collection, and tells you the exact with() to add. /lc:find-n-plus-one /lc:security-audit is the other one I run on any project I inherit. It looks for SQL injection, XSS, mass-assignment and secrets committed to the repo, and like most fixable skills it takes a preview flag before it changes anything. /lc:security-audit # report /lc:security-audit fix --dry-run # preview the fixes /lc:security-audit fix # apply, with confirmation Clean up what has piled up Every long-lived Laravel app accumulates migration cruft: a create followed by twenty add_column and change_column files. /lc:consolidate-migrations groups them by table, classifies each table as safe to merge or not, and folds the A

2026-08-06 原文 →
AI 资讯

Add tags and categories to any model with Laraterms

Sometimes you need tags on a model. The usual answer is a tags table, a pivot, a slug and a belongsToMany , and you write it again in the next project with slightly different columns. Laraterms replaces that with a config entry and a trait, and it comes with the parts you normally bolt on later: hierarchy, per-tenant isolation and translations. This is the simple path first, then the two features you reach for next. How to install One package, its config and two migrations. composer require edulazaro/laraterms php artisan vendor:publish --tag = laraterms-config php artisan vendor:publish --tag = laraterms-migrations php artisan migrate Step 1: define a taxonomy A taxonomy is a kind of label, declared in config/laraterms.php . Start with a flat tags taxonomy; the file already ships one you can keep. 'taxonomies' => [ 'tags' => [ 'hierarchical' => false , 'max_terms_per_model' => null , 'scope' => 'tenant' , ], ], Step 2: tag a model Add the HasTerms trait and the model can hold terms. Attaching is find-or-create: pass a label, and the term is created the first time and reused afterwards. use EduLazaro\Laraterms\Concerns\HasTerms ; class Post extends Model { use HasTerms ; } $post -> attachTerm ( 'Laravel' , 'tags' ); $post -> attachTerms ([ 'Laravel' , 'PHP' ], 'tags' ); $post -> syncTerms ([ 'Laravel' , 'Vue' ], 'tags' ); // replace the tag set $post -> termsIn ( 'tags' ); // read them back Filtering by tag is a query scope, so it composes with the rest of your query. Post :: whereHasTerm ( 'laravel' , 'tags' ) -> get (); Post :: whereHasAllTerms ([ 'laravel' , 'tutorial' ], 'tags' ) -> get (); Hierarchical categories Set hierarchical => true on a taxonomy and its terms form a tree. Read the whole tree in one query, and walk a term's ancestry. 'categories' => [ 'hierarchical' => true , 'max_terms_per_model' => 1 , 'scope' => 'tenant' , ], use EduLazaro\Laraterms\Support\TermTree ; $tree = TermTree :: for ( 'categories' ); // roots with children, one query $term -> b

2026-08-06 原文 →