it is going to be lengthy post, I encountering weird behavior where I see in profiler that one entity managers is said to map entity that it does not map. It looks like this:
Here is doctrine.yaml:
doctrine: dbal: default_connection: default connections: default: driver: "pdo_mysql" host: "127.0.0.1" port: "3306" dbname: "example" user: "root" password: "" charset: utf8mb4 server_version: "mariadb-10.4.10" logs: driver: "pdo_mysql" host: "127.0.0.1" port: "3306" dbname: "example_logs" user: "root" password: "" charset: utf8mb4 server_version: "mariadb-10.4.10" orm: auto_generate_proxy_classes: true default_entity_manager: default entity_managers: default: query_cache_driver: type: pool pool: apcu.default.cache.pool metadata_cache_driver: type: pool pool: apcu.default.cache.pool result_cache_driver: type: pool pool: apcu.default.cache.pool connection: default naming_strategy: doctrine.orm.naming_strategy.underscore_number_aware mappings: App: is_bundle: false type: annotation dir: '%kernel.project_dir%/src/Entity/Main' prefix: 'App\Entity\Main' alias: App logs: query_cache_driver: type: pool pool: apcu.default.cache.pool metadata_cache_driver: type: pool pool: apcu.default.cache.pool result_cache_driver: type: pool pool: apcu.default.cache.pool connection: logs naming_strategy: doctrine.orm.naming_strategy.underscore_number_aware mappings: LogBundle: is_bundle: false type: annotation dir: '%kernel.project_dir%/src/Entity/Logs' prefix: 'App\Entity\Logs' alias: App
And here is framework.yaml with cache pool configuration:
framework: secret: '%env(APP_SECRET)%' session: handler_id: null cookie_secure: auto cookie_samesite: lax php_errors: log: true cache: pools: apcu.default.cache.pool: adapter: cache.adapter.apcu apcu.logs.cache.pool: adapter: cache.adapter.apcu
If I remove metadata_cache_driver
configuration from logs entity_manager
configuration, or change it to use different cache pool (apcu.logs.cache.pool) than default entity manager then profiler reports correct mappings (Example entity in default em and logs em is empty).
The issue occurs only when entity is feed trough form and $form->handleRequest()
handles it, creating or modifying entity without forms does not cause such issue. Here is my controller:
<?phpnamespace App\Controller;use App\Entity\Main\Example;use App\Form\Type\ExampleType;use Doctrine\ORM\EntityManagerInterface;use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;use Symfony\Component\HttpFoundation\Request;use Symfony\Component\HttpFoundation\Response;use Symfony\Component\Routing\Annotation\Route;class ExampleController extends AbstractController { /** * @Route("/example1") * @Template */ public function example1(EntityManagerInterface $em){ $example = new Example(); $example->setValue('example value'); try { $em->persist($example); $em->flush(); } catch(\Exception $e){ return new Response('An error has occurred. '.$e->getMessage()); } return []; } /** * @Route("/example2") * @Template */ public function example2(EntityManagerInterface $em){ $example = $em->getRepository(Example::class)->find(1); if(!$example){ return new Response('No example found.'); } $example->setValue(mt_rand(0, mt_getrandmax())); try { $em->flush(); } catch(\Exception $e){ return new Response('An error has occurred. '.$e->getMessage()); } return []; } /** * @Route("/example3") * @Template */ public function example3(Request $request, EntityManagerInterface $em){ $example = $em->getRepository(Example::class)->find(1); if(!$example){ return new Response('No example found.'); } $form = $this->createForm(ExampleType::class, $example); $form->handleRequest($request); if($form->isSubmitted() && $form->isValid()){ $em->flush(); } return ['form' => $form->createView()]; }}
example1 and example2 routes DOES NOT cause issue, only example3 does and only when the form is submitted, so only when I enter example3 url, then click submit form only then when enter profiler for this request I can see the issue.
My minimal reproduction example was to create new symfony LTS project symfony new example-site --version=lts --full
Then these are files that I have changed since:
![file changes]()
Databases are created by symfony console doctrine:database:create --connection=default
and symfony console doctrine:database:create --connection=logs
then tables are created by symfony console doctrine:migrations:diff --em=default
and symfony console doctrine:migrations:migrate --em=default
Here is code for other files I haven't yet included in post:
<?php//src/Entity/Main/Example.phpnamespace App\Entity\Main;use Doctrine\ORM\Mapping as ORM;/** * @ORM\Entity */class Example { /** * @ORM\Id() * @ORM\GeneratedValue() * @ORM\Column(type="integer") */ private $id; /** * @ORM\Column(type="string") */ private $value; public function getId(){ return $this->id; } public function getValue(){ return $this->value; } public function setValue(string $value){ $this->value = $value; }}
<?php//src/Form/Type/ExampleType.phpnamespace App\Form\Type;use App\Entity\Main\Example;use Symfony\Component\Form\AbstractType;use Symfony\Component\Form\Extension\Core\Type\SubmitType;use Symfony\Component\Form\Extension\Core\Type\TextType;use Symfony\Component\Form\FormBuilderInterface;use Symfony\Component\OptionsResolver\OptionsResolver;class ExampleType extends AbstractType { public function buildForm(FormBuilderInterface $builder, array $options){ $builder->add('value', TextType::class); $builder->add('submit', SubmitType::class); } public function configureOptions(OptionsResolver $resolver){ $resolver->setDefaults(['data_class' => Example::class, ]); }}
<!-- template/s/example/example1.html.twig --><!doctype html><html lang="en"><head><meta charset="utf-8"><title>Example</title></head><body> Example1</body></html>
<!-- template/s/example/example2.html.twig --><!doctype html><html lang="en"><head><meta charset="utf-8"><title>Example</title></head><body> Example2</body></html>
<!-- template/s/example/example3.html.twig --><!doctype html><html lang="en"><head><meta charset="utf-8"><title>Example</title></head><body>{{ form(form) }}</body></html>
Last thing I want to add is that in other project this issue is more visible, because when entity has reference to other entity an error is reported (on non-owning side in One-to-Many self-referencing association):
In this case Item entity is the one feed trough form.For those who are curious here is Item.php:But I don't know how would it matter as it is not managed by logs entity manager and should not appear under. default entity manager who is managing the entity is not reporting any issues with it.
<?phpnamespace App\Entity;use Doctrine\ORM\Mapping as ORM;use Symfony\Component\HttpFoundation\File\UploadedFile;use Symfony\Component\Validator\Constraints as Assert;/** * @ORM\Entity(repositoryClass="App\Repository\ItemRepository") * @ORM\Table(indexes={ * @ORM\Index(name="item_image", columns={"image"}) * }) */class Item { /** * @ORM\Id() * @ORM\GeneratedValue() * @ORM\Column(type="integer") */ private $id; /** * @ORM\Column(type="string", length=32) * @Assert\NotBlank() * @Assert\Length(min=3, max=32) */ private $name; /** * @ORM\Column(type="string") */ private $description = ''; /** * @ORM\Column(type="string", length=25, nullable=true) */ private $image; /** * @ORM\OneToMany(targetEntity="App\Entity\Item", mappedBy="container") */ private $items; /** * @ORM\ManyToOne(targetEntity="App\Entity\Item", inversedBy="items") * @ORM\JoinColumn(name="container", referencedColumnName="id") * @var $container Item */ private $container; /** * @ORM\OneToMany(targetEntity="App\Entity\TagItem", mappedBy="item") * @var $tags TagItem[] */ private $tags; /** * @Assert\Image(mimeTypes="image/jpeg") * @var $imageFile null|UploadedFile */ private $imageFile; public function __construct() { $this->items = new \Doctrine\Common\Collections\ArrayCollection(); $this->tags = new \Doctrine\Common\Collections\ArrayCollection(); } public function getId(){ return $this->id; } public function getName(){ return $this->name; } public function setName(string $name){ $this->name = $name; } public function getDescription(){ return $this->description; } public function setDescription($description){ $this->description = $description; } public function hasImage(){ return isset($this->image); } public function getImage(){ return $this->image; } public function setImage($image){ $this->image = $image; } public function hasImageFile(){ return isset($this->imageFile); } public function getImageFile(){ return $this->imageFile; } public function setImageFile($imageFile){ $this->imageFile = $imageFile; } public function getItems(){ return $this->items; } public function hasContainer(){ return isset($this->container); } public function getContainer(){ return $this->container; } public function setContainer(?Item $container){ return $this->container = $container; } public function getTags(){ return $this->tags; } public function setTags($tags){ $this->tags = $tags; }}
PHP version is 7.3.12 and hosted with symfony serve