AI 资讯
Migrating Laravel to Symfony Without Rewriting Your Domain
Book: Decoupled PHP — Clean and Hexagonal Architecture for Applications That Outlive the Framework Also by me: Thinking in Go (2-book series) — Complete Guide to Go Programming + Hexagonal Architecture in Go My project: Hermes IDE | GitHub — an IDE for developers who ship with Claude Code and other AI coding tools Me: xgabriel.com | GitHub You've been handed the ticket everyone dreads: move the app off Laravel and onto Symfony. Maybe the team standardized on Symfony. Maybe a Messenger-and-Doctrine shop acquired you. Maybe someone decided Eloquent's global scopes had cost enough Friday nights. The estimate comes back in quarters. Someone quotes the phrase "big rewrite" and the room goes quiet, because everyone remembers the last big rewrite. Here is the question that decides whether this is a quarter or a year: how much of your business logic imports the framework? If your PlaceOrder logic reaches into request() , calls Order::create() on an Eloquent model, and opens a transaction with DB::transaction() , then the framework is the application and you are rewriting the application. If your business rules sit in plain PHP classes that never heard of Laravel, then the migration is an adapter swap, and adapter swaps ship one route at a time. What the framework actually owns Strip a typical Laravel app down and you find three categories of code. The first is your domain and use cases: the rules about what an order is, what placing one means, when it can be cancelled. This is the part the business pays for. It should not import a framework at all. The second is glue that translates the outside world into calls on that logic: controllers, form requests, Eloquent models, queue jobs, service providers. This is framework-specific by definition. The third is infrastructure your code talks to through interfaces: the database, the queue, the mailer, the payment gateway. A framework migration only touches the second category. The trouble is that most Laravel apps let the first and
AI 资讯
Keeping Doctrine Entities Honest with DTOs and ObjectMapper
Originally posted on https://symfonycasts.com/blog/honest-entities Your Doctrine entities are lying to you! For years, the standard way to build Doctrine entities in Symfony has looked something like this (and it's still what MakerBundle generates today): #[ORM\Entity] class ConferenceTalk { #[ORM\Id] #[ORM\GeneratedValue] #[ORM\Column] private ?int $id = null ; #[Assert\NotBlank] #[ORM\Column(length: 255)] private ?string $title = null ; #[ORM\Column(type: Types::TEXT, nullable: true)] private ?string $abstract = null ; public function getId (): ?int { return $this -> id ; } public function getTitle (): ?string { return $this -> title ; } public function setTitle ( ?string $title ): static { $this -> title = $title ; return $this ; } public function getAbstract (): ?string { return $this -> abstract ; } public function setAbstract ( ?string $abstract ): static { $this -> abstract = $abstract ; return $this ; } } At first glance, this looks perfectly reasonable. The title field is required. We know that because it has a NotBlank constraint and the database column is not nullable. But look closer. private ?string $title = null ; public function setTitle ( ?string $title ): static public function getTitle (): ?string According to the PHP type system, the title is optional. In fact, the public API of this class explicitly allows us to set it to null . That means this is perfectly valid: $talk = new ConferenceTalk (); And so is this: $talk = new ConferenceTalk (); $talk -> setTitle ( null ); Both objects represent a conference talk that can never be successfully persisted. Eventually, Doctrine catches the problem: $talk = new ConferenceTalk (); $entityManager -> persist ( $talk ); $entityManager -> flush (); // boom! SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'title' cannot be null The database knows that a conference talk must have a title. Our PHP code does not. So why do we build entities this way? Historically, this pattern was optimized for simpli
AI 资讯
Omnia Ipsum: Unified placeholder content for Symfony
Rethinking fake content in Symfony projects A prototype web page displaying pure placeholder content When building early UI prototypes or shaping design systems in Symfony, placeholder content becomes a constant companion. Lorem ipsum text. Dummy profile photos. Placeholder videos. Silent audio. Temporary avatars. Realistic fake user data. Every project needs them — and yet most setups rely on a patchwork of libraries, links and hardcoded values. Omnia Ipsum aims to fix that by giving Symfony developers a single, elegant toolkit for placeholder content of all kinds. In this article, I will walk you through the motivation behind the project, the conceptual patterns it follows, and its most advanced features — all designed to make your prototyping workflow faster, cleaner and more maintainable. Motivation: Why a placeholder library? Most Symfony projects start the same way: You add lorem ipsum text manually into Twig templates. You grab placeholder images from an external service. You generate avatars using yet another site. You paste in temporary YouTube or stock video URLs. You install Faker separately whenever realistic data is needed. The result is inconsistent, fragmented and difficult to maintain. And even worse: placeholder content often leaks into production unless guarded carefully. The idea behind Omnia Ipsum was simple: “If your UI needs placeholder content, it should come from one place — predictable, configurable, and accessible directly from Twig.” This cuts down on boilerplate, cognitive overhead, and the "temporary chaos" of early-stage templates. Quick Start Prerequisite Go to github.com/symfinity/recipes and follow the instructions to add the required recipe repository. Installation composer require --dev symfinity/omnia-ipsum Usage Use the Twig functions immediately: <img src= " {{ omnia_image ( 600 , 400 ) }} " alt= "Placeholder" > <img src= " {{ omnia_avatar ( 'John Doe' , 100 ) }} " alt= "Avatar" > <video src= " {{ omnia_video ( 1920 , 1080 ) }}
AI 资讯
Font Manager: Multi-format Font export for Symfony
The Problem Typography should be one of the simplest parts of a project. In reality, it often ends up scattered across multiple layers: Bootstrap: $font-family-base variables Tailwind: JavaScript configuration TypeScript: type definitions Design systems: W3C Design Tokens The same font information gets copied and maintained in several places. Every update means touching multiple files, hoping everything stays in sync. It's repetitive, error-prone, and easy to get wrong. So I built Font Manager. Define your fonts once and export them in whatever format your project needs — CSS, Bootstrap variables, Tailwind configuration, TypeScript definitions, design tokens, and more. The Solution A simple Twig function: {{ font_manager ( 'Ubuntu' , '400 700' ) }} Configuration: symfinity_font_manager : export : formats : - scss_bootstrap - tailwind_config - typescript_definitions One lock command: php bin/console fonts:lock Every format, automatically generated. Perfectly synced. Bootstrap Example Before: // Manually copy font name $font-family-base : 'Ubuntu' , sans-serif ; // ❌ Duplication @import 'bootstrap/scss/bootstrap' ; After: symfinity_font_manager : export : formats : [ scss_bootstrap ] php bin/console fonts:lock // app.scss @import './assets/styles/fonts-bootstrap' ; // ← Auto-generated @import 'bootstrap/scss/bootstrap' ; Bootstrap uses your fonts automatically. No manual mapping. No duplication. Tailwind Example symfinity_font_manager : export : formats : [ tailwind_config ] // tailwind.config.js const fonts = require ( ' ./assets/fonts-tailwind.config.js ' ); // ← Auto-generated module . exports = { theme : { extend : { fontFamily : fonts . fontFamily } } }; <p class= "font-sans" > Your custom font, via Tailwind. </p> TypeScript Example symfinity_font_manager : export : formats : [ typescript_definitions ] import { fonts , type FontFamily } from ' ./assets/fonts ' ; applyFont ( element , ' sans ' ); // ✓ Valid applyFont ( element , ' invalid ' ); // ✗ TypeScript erro
AI 资讯
Deploying Symfony 8 to cPanel Step by Step guide.
Table of Contents Introduction Double-check everything Configure your Environment Variables Install/Update your Vendors Clear your Symfony Cache Install symfony/apache-pack Update composer.json public directory Build the assets Update Kernel.php Upload the project to cPanel Final Thoughts Introduction I'm new to Symfony and recently, I deployed a Symfony app to a shared hosting environment running cPanel with no SSH access. I could not figure out the best way to do it, let alone find useful resources online as most of them are outdated and felt inefficient. I faced a lot of errors like: failing to load the app with a 500 Internal Server Error, some static assets not loading, etc. I figured it out in the end. This motivated me to write this post to reduce the headache for other Symfony newbies like me. Alright, let's get into it. Most deployment guides online assume you can run Composer, clear caches, execute migrations, and run Symfony commands directly on the server. In shared hosting environments, that is often not possible so, my examples will assume you don't have it installed on the server. 1. Double-check everything The first step to building for production is double-checking everything if it's in intact. Yes, this is very important. In my case, I was faced with some static image assets failing to load because of wrong reference which was ignored on dev mode. I had something like: asset('/images/<filename> ) which was working in dev mode but failed to load the image in prod. the paths had to be like: asset('images/'). This was after checking how I defined other assets. So avoid things like this before hand. 2. Configure your Environment Variables For this, we will use the dotenv:dump command which is not registered by default, so you must register first in your services: # config/services.yaml services : Symfony\Component\Dotenv\Command\DotenvDumpCommand : ~ Then, run the command below. After running this command, Symfony will create and load the .env.local.ph