2

Symfony/Doctrine: PostgreSQL Migration Issue – Undefined column error only in HTTP Kernel (CLI works)

I'm working on a Symfony 7.3 project running on PHP 8.2. I recently migrated the database from MySQL to PostgreSQL, and since then, I've encountered a highly specific issue with Doctrine's ORM that only manifests in the HTTP context.

The Problem

When I try to fetch data from the user table via an HTTP request, I receive the following SQL error:

SQLSTATE[42703]: Undefined column: 7
ERROR:  column t0.id does not exist
LINE 1: SELECT t0.id AS id_1, t0.email AS email_2, t0.password AS pa...

This error is exclusive to any code executed within the HTTP Kernel (e.g., Controllers, Listeners).

Factual Observations (Crucial)

1. Command Line Interface (CLI) Works Fine ✔️

When executing queries directly via the Symfony console (which uses the exact same Doctrine configuration and database connection), everything works perfectly. This confirms the table public.user and the column id exist.

2. Isolated Debug Controller Fails ❌

A minimal debug controller fetching the User entity triggers the error.

3. Working Counter-Example (The Clue) 💡

A structurally identical controller for the Customer entity (table name customer, which is not a reserved PostgreSQL keyword) works without error. This strongly points to a conflict with the reserved keyword user.

Entity and Database Details

User Entity (Abridged)

The entity uses standard Doctrine annotations:

// src/Entity/User.php
#[ORM\Entity(repositoryClass: 'App\Repository\UserRepository')]
#[ORM\Table(name: 'user')] // Problematic line
class User {
    // ... ORM\Id and ORM\Column definitions
}

Database Structure

  • DBMS: PostgreSQL
  • Table Name in DB: user (lowercase, public schema)
  • PostgreSQL Fact: The word user is a reserved SQL keyword.

The Temporary Fix & The Core Question ⚠️

I discovered that the error is resolved by manually forcing Doctrine to quote the table name using backticks in the Entity mapping:

// Temporary Fix
#[ORM\Table(name: '`user`')]

While this solution works, I reject it as a permanent fix. It introduces an unsightly exception into my clean entity code, only addresses this single reserved word, and does not provide a future-proof, global guarantee that Doctrine will correctly handle other reserved PostgreSQL keywords (e.g., group, order, etc.) without manual intervention.


The Question

Based on the confirmed root cause (PostgreSQL reserved keyword user not being reliably quoted in the HTTP context) and the desire for a clean, global solution:

What is the underlying Doctrine DBAL or Symfony configuration setting (e.g., in doctrine.yaml) that must be applied to the PostgreSQL connection to globally enforce the correct quoting behavior for all reserved SQL keywords, thereby allowing the Entity mapping to remain clean (#[ORM\Table(name: 'user')]) and guaranteeing future compatibility with PostgreSQL?

2
  • Seems the only automatic choice is: doctrine-project.org/projects/doctrine-orm/en/3.5/reference/…: Quoting Reserved Words [...] For more control over column quoting the Doctrine\ORM\Mapping\QuoteStrategy interface was introduced in ORM. It is invoked for every column, table, alias and other SQL names. You can implement the QuoteStrategy and set it by calling Doctrine\ORM\Configuration#setQuoteStrategy(). Though this gets into casing issues if the ORM identifiers are different case then the database ones. Commented 2 days ago
  • The ORM may only know that there are keywords and how quoting can be done for them for a specific database configuration. However it can never know all keywords (as they can change) nor if the quoting does apply to all use-cases (as also the quoting may change or be context sensitive and also may change). So while you want to benefit from nice abstractions, the temporary fix, IIUC, even if different from your current encoding, will remain a temporary fix. So get your wanted, more generalized change towards upstream if you want to see this on the level of the ORM. Commented 2 days ago

1 Answer 1

0

What you call out as a

// Temporary Fix
#[ORM\Table(name: '`user`')]

actually is making use of the correct form to tell the Object Relational Mapper (ORM) what the actual name is. As user is a reserved word in your Relational Data Base Management System (RDBMS) you need to properly tell the ORM what you mean.

As has been commented, the ORM you make use of offers exactly this mechanism to communicate the mapping between names in PHP you have reserved for your objects (user) with the database (not the keyword users). A 1:1 mapping is not possible because your database would identify it not as a table name otherwise.

Another way to "undefine" this problem globally is not to use keywords of your database for ORM table names.

A common way - but not always fool-proof - is to use the plural form for table names, e.g. users; or compound names, like a prefix for the domain, e.g. app_user or in your case perhaps kernel_user now after you've learned which domain is effectively parenting and controlling the use of it.

This will also encode your so far temporary learning about the design decisions you've made so far and may help you to correct on the level of your very own abstractions you prefer to be leading overall.

Therefore, if you prefer to not have mapping at all (or to have it more invisible or discreet), understand the mapping capabilities the Object Relational Mapper (ORM) offers to you and the details of the Relational Data Base Management System (RDBMS) you make use of, to come as close as possible to the "non-temporary" form you have in mind.

Just™ understand the dynamics the mappings fall into to make the best decision. You will notice that this may change the next time you learn more about it (again so to say).

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.