My Symfony project (sf v6) uses postgresql/postgis and 2 databases: the main one with specific business datas and the second one called web-services database with commons datas share beetwen multiple projects (with two schema, mainly gis which contain GIS datas)
So first, I refered to https://symfony.com/doc/current/doctrine/multiple_entity_managers.html
and set my config/package/doctrine.yaml :
doctrine:
dbal:
connections:
default:
url: '%env(resolve:DATABASE_URL)%'
server_version: '13.5'
web_services:
url: '%env(resolve:DATABASE_WS_URL)%'
server_version: '13.5'
default_connection: default
orm:
default_entity_manager: default
entity_managers:
default:
connection: default
#auto_generate_proxy_classes: true # thow exception Unrecognized options
#enable_lazy_ghost_objects: true # thow exception Unrecognized options
report_fields_where_declared: true
validate_xml_mapping: true
naming_strategy: doctrine.orm.naming_strategy.underscore_number_aware
auto_mapping: true
mappings:
App:
is_bundle: false
dir: '%kernel.project_dir%/src/Entity'
prefix: 'App\Entity'
alias: App
type: attribute
#profiling: "%kernel.debug%" # thow exception Unrecognized options
#profiling_collect_backtrace: '%kernel.debug%' # thow exception Unrecognized options
web_services:
connection: web_services
mappings:
Web_services:
is_bundle: false
dir: '%kernel.project_dir%/src/Entity/WebServices'
prefix: 'App\Entity\WebServices'
alias: Web_services
type: attribute
when@test:
doctrine:
dbal:
# "TEST_TOKEN" is typically set by ParaTest
dbname_suffix: '_test%env(default::TEST_TOKEN)%'
when@prod:
doctrine:
orm:
auto_generate_proxy_classes: false
proxy_dir: '%kernel.build_dir%/doctrine/orm/Proxies'
query_cache_driver:
type: pool
pool: doctrine.system_cache_pool
result_cache_driver:
type: pool
pool: doctrine.result_cache_pool
framework:
cache:
pools:
doctrine.result_cache_pool:
adapter: cache.app
doctrine.system_cache_pool:
adapter: cache.system
mainly, dbal url, and connection dir and prefix
I can access without any issue on default connection, entity, repository !
I defined two entities to access to web_services connection datas:
First one, Translate
// src/Entity/WebServices/Translate.php
namespace App\Entity\WebServices;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\ORM\Id;
#[ORM\Entity(repositoryClass: 'App\Repository\WebServices\TranslateRepository')]
#[ORM\Table(name: "gis.translate")]
class Translate
{
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column(type: 'integer')]
private $translateId;
#[ORM\Column(type: 'string', length: 255)]
private $frValue;
#[ORM\Column(type: 'string', length: 255)]
private $gbValue;
public function getTranslateId(): ?int
{
return $this->translateId;
}
// and others getters/setters
}
Second one, Country
// src/Entity/WebServices/Country.php
namespace App\Entity\WebServices;
use App\Repository\WebServices\CountryRepository;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\ORM\Id;
#[ORM\Entity(repositoryClass: 'App\Repository\WebServices\CountryRepository')]
#[ORM\Table(name: "gis.country")]
class Country
{
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column]
private ?int $countryId = null;
#[ORM\Column(length: 2, nullable: true)]
private ?string $isoCode = null;
#[ORM\ManyToOne]
#[ORM\JoinColumn(name: 'translate_id', referencedColumnName: 'translate_id', nullable: false)]
private ?Translate $translate = null;
public function getCountryId(): ?int
{
return $this->country_id;
}
// and others getters/setters
}
Note that web_services tables uses tablename_id, not simply id
At this point, if I run (in my sf docker container, postgresql in other one):
php bin/console dbal:run-sql 'SELECT * FROM translate'
for main database translate table, or
php bin/console dbal:run-sql --connection web_services 'SELECT * FROM gis.translate'
for web_services database translate table,
it runs correctly !
It runs correctly too in the LocationCountryController controller if I call getClassMetadata
method of EntityManager, in src/Controller/WebServices/CountryController:
[…]
use Doctrine\ORM\EntityManagerInterface;
[…]
#[Route(path: '/location/country')]
class LocationCountryController extends AbstractController
{
#[Route(path: '/', name: 'location_country_index', methods: ['GET'])]
public function index(EntityManagerInterface $web_servicesEntityManager): Response
{
$ctableName = $web_servicesEntityManager->getClassMetadata(Country::class);
$ttableName = $web_servicesEntityManager->getClassMetadata(Translate::class);
dd($ctableName, $ttableName);
}
//[…]
}
If I run, always in src/Controller/WebServices/CountryController:
class LocationCountryController extends AbstractController
{
#[Route(path: '/', name: 'location_country_index', methods: ['GET'])]
public function index(EntityManagerInterface $web_servicesEntityManager): Response
{
$connection = $doctrine->getConnection('web_services');
$countries = $connection->fetchAllAssociative('SELECT * FROM country c JOIN translate t ON c.translate_id=t.translate_id LIMIT 20');
dd($countries);
// […]
It returns too 20 countries with correct translate datas !
BUT as soon I want to use Country repository, for example, always in src/Controller/WebServices/CountryController:
namespace App\Controller;
use App\Entity\WebServices\Country;
use App\Entity\WebServices\Translate;
use App\Repository\WebServices\CountryRepository;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\Persistence\ManagerRegistry;
#[Route(path: '/location/country')]
class LocationCountryController extends AbstractController
{
#[Route(path: '/', name: 'location_country_index', methods: ['GET'])]
public function index(ManagerRegistry $doctrine, EntityManagerInterface $web_servicesEntityManager): Response
{
$repository = $web_servicesEntityManager->getRepository(Country::class);
$countries = $repository->findAll(); // ->find(1) returns same error
dd($countries);
// or
$countriesRepository = $doctrine->getRepository(Country::class, 'web_services');
dd($countriesRepository->findAll());
//[…]
I have the error:
An exception occurred while executing a query: SQLSTATE[42P01]: Undefined table: 7 ERROR: relation "gis.country" does not exist
Here are my src/Repository/WebServices/CountryRepository.php:
namespace App\Repository\WebServices;
use App\Entity\WebServices\Country;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
/**
* @extends ServiceEntityRepository<Country>
*
* @method Country|null find($id, $lockMode = null, $lockVersion = null)
* @method Country|null findOneBy(array $criteria, array $orderBy = null)
* @method Country[] findAll()
* @method Country[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
*/
class CountryRepository extends ServiceEntityRepository
{
public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, Country::class);
}
// […]
/**
* @return country[] Returns an array of Country objects
*/
public function findAll(): array
{
return $this->createQueryBuilder('c')
// ->innerJoin('c.translate', 't')
// ->addSelect('t')
// ->orderBy('t.frValue', 'ASC')
->setMaxResults(5)
->getQuery()
->getResult()
;
}
I updaded symfony to last 6.3 release, last 2.17 doctrine and still have the same error !
In my searches to solve, I found this post : https://dba.stackexchange.com/questions/101570/error-42p01-relation-does-not-exist … bad permissions… but I can access to table if I don't use repository ! and if I search with "postgresql Error 42P01", I founded this post :
PostgreSQL ERROR: 42P01: relation "[Table]" does not exist
and my translate
and country
table seems correctly named.
EDIT:
I tried in entity to separate schema and table:
#[ORM\Table(schema: "sig", name: "country")]
, it doesn't change !
The problem come from the configuration of the registry.
Symfony auto-wiring will search the first pattern which match the configuration.
In this case App\Entity
will always come first.
There are two solutions to this problem :
# config/package/doctrine.yaml
# […]
orm:
default_entity_manager: default
entity_managers:
web_services:
connection: web_services
mappings:
Web_services:
is_bundle: false
dir: '%kernel.project_dir%/src/Entity/WebServices'
prefix: 'App\Entity\WebServices'
alias: Web_services
type: attribute
default:
connection: default
report_fields_where_declared: true
validate_xml_mapping: true
naming_strategy: doctrine.orm.naming_strategy.underscore_number_aware
auto_mapping: true
mappings:
App:
is_bundle: false
dir: '%kernel.project_dir%/src/Entity'
prefix: 'App\Entity'
alias: App
type: attribute
# […]