这将是一个很长的帖子,我遇到了一个奇怪的行为,我在profiler中看到一个实体管理器被说成是在映射它没有映射的实体。它看起来像这样。这里是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
这里是framework.yaml,有缓存池的配置。
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
如果我删除 metadata_cache_driver
日志配置 entity_manager
配置,或者将其改为使用不同于默认实体管理器的缓存池(apcu.logs.cache.pool),那么profiler就会报告正确的映射(例如在默认em和logs em中的实体是空的)。
这个问题只发生在实体是feed trough形式和 $form->handleRequest()
处理,创建或修改没有表单的实体不会引起这样的问题。这是我的控制器。
<?php
namespace 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和example2路由 不 导致问题的原因,只有example3是这样的,而且只有在提交表单的时候,所以只有当我输入example3的url,然后点击提交表单的时候,只有当进入这个请求的profiler的时候,我才能看到这个问题。
我的最小重现例子是创建新的symfony LTS项目。symfony new example-site --version=lts --full
那么这些都是我后来改过的文件。
数据库是由 symfony console doctrine:database:create --connection=default
和 symfony console doctrine:database:create --connection=logs
然后通过以下方式创建表格 symfony console doctrine:migrations:diff --em=default
和 symfony console doctrine:migrations:migrate --em=default
这里是其他文件的代码,我还没有把它放在帖子里。
<?php
//src/Entity/Main/Example.php
namespace 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.php
namespace 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>
最后我想补充的是,在其他项目中,这个问题更加明显,因为当实体对其他实体有引用时,就会报告错误(在非拥有方的一对多自引用关联中)。在这种情况下,Item 实体是一个feed trough form.对于那些好奇的人来说,这里是Item.php:但我不知道这有什么关系,因为它不是由日志实体管理器管理的,不应该出现在默认实体管理器下。
<?php
namespace 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版本是7.3.12,托管的是 symfony serve
我回到github上,在 问题线索 从 花式网络 谁说的
状态:已审查
这个错误与WebProfilerBundle无关。原因是你对2个实体管理器使用了相同的缓存盐。在某些地方,我们盲目地依次在两个EM上调用getClassMetadata()(即:DoctrineLoader,DoctrineExtractor)。第一次对该EM的调用会填充缓存。第二次调用在不应该知道该类的EM上打入缓存,从而认为该类已被加载。
使用相同的缓存是可以的,只是需要使用不同的盐。
当我问到在配置中是否有为实体管理器设置盐的选项时,我得到的回答是 凳子:
简单的实现方式是使用2个独立的缓存池,因为FrameworkBundle在共享同一存储时,会将池名考虑到种子中,以隔离每个池中的密钥。