Doctrine ORM是一个PHP ORM。虽然Doctrine 1.2使用Active Record模式,但Doctrine ORM 2及更高版本使用Data Mapper模式。 Doctrine项目是一个开源库和工具的集合,用于处理用PHP编写的数据库抽象和对象关系映射。
Symfony 6.4 - Doctrine - Xml - 没有可用的匹配全局属性声明,但严格通配符要求
composer.json "学说/学说捆绑": "^2.11.1", "学说/学说-迁移-bundle": "^3.3.0", “教义/规则”:“...
Zend Framework 2 Doctrine 2 多对多实体关系问题
我有以下表格:电影、类别、电影_类别和实体: 电影.php 我有以下表格:电影、类别、电影_类别和实体: 电影.php <?php namespace Admin\Entity; use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\Collection; use Doctrine\ORM\Mapping as ORM; /** * @ORM\Table(name="films") */ class Film{ /** * @ORM\Id * @ORM\GeneratedValue(strategy="AUTO") * @ORM\Column(type="integer") * @ORM\Column(length=11) */ private $id; /** * @ORM\Column(type="string") */ private $name; /* .... */ /** * @ORM\ManyToMany(targetEntity="Category") * @ORM\JoinTable(name="films_categories", * joinColumns={@ORM\JoinColumn(name="film_id", referencedColumnName = "id")}, * inverseJoinColumns={@ORM\JoinColumn(name="category_id", referencedColumnName="id")}) */ private $categories; public function __construct(){ $this->categories = new ArrayCollection(); } public function getCategoriesNames(){ $names = array(); foreach($this->categories as $category){ $names[] = $category->getName(); } return $names; } public function getId(){ return $this->id; } public function setId($id){ $this->id = $id; } /* ... */ /** * @return Collection */ public function getCategories(){ return $this->categories; } public function addCategories(Collection $categories){ foreach($categories as $category){ $this->categories->add($category); } } public function removeCategories(Collection $categories){ foreach($categories as $category){ $this->categories->removeElement($category); } } } 类别.php <?php namespace Admin\Entity; use Doctrine\ORM\Mapping as ORM; /** * @ORM\Table(name="categories") */ class Category { /** * @ORM\Id * @ORM\GeneratedValue(strategy="AUTO") * @ORM\Column(type="integer") */ private $id; /* ... */ public function getId(){ return $this->id; } public function setId($id){ $this->id = $id; } /* ... */ } 我想要做的是创建一个表单和添加新电影并为其分配类别的操作。这是我使用的表格: FilmFieldset.php <?php namespace Admin\Form; use Zend\Form\Fieldset; use Zend\InputFilter\InputFilterProviderInterface; use DoctrineORMModule\Stdlib\Hydrator\DoctrineEntity; use Admin\Entity\Film; class FilmFieldset extends Fieldset implements InputFilterProviderInterface{ protected $entityManager; public function __construct($em){ parent::__construct('film'); $this->entityManager= $em; $this->setHydrator(new DoctrineEntity($em,'Admin\Entity\Film')) ->setObject(new Film()); #$this->setAttribute('method','post'); #$this->setAttribute('class','standardForm'); $this->add(array( 'name' => 'id', 'type' => 'hidden' )); /* ... */ $this->add( array( 'type' => 'DoctrineModule\Form\Element\ObjectSelect', 'name' => 'categories', 'attributes' => array( 'multiple' => 'multiple', ), 'options' => array( 'object_manager' => $em, 'target_class' => 'Admin\Entity\Category', 'property' => 'name', 'label' => 'Categories: ', 'disable_inarray_validator' => true ), ) ); } public function getInputFilterSpecification(){ return array( /* .... */ 'categories' => array( 'required' => true, ), ); } } FilmForm.php <?php namespace Admin\Form; use Zend\Form\Form; use Zend\Stdlib\Hydrator\ClassMethods; use Admin\Entity\Film; use Zend\InputFilter\InputFilter; use DoctrineModule\Stdlib\Hydrator\DoctrineObject as DoctrineHydrator; class FilmForm extends Form{ public function __construct($em){ parent::__construct('filmForm'); $this->setAttribute('method','post') ->setAttribute('class','standardForm') ->setHydrator(new DoctrineHydrator($em,'\Admin\Entity\Film')) ->setInputFilter(new InputFilter()); /* I register the fieldset through a service and not directly here */ // $this->add(array( // 'type' => new FilmFieldset($em), // 'options' => array( // 'user_as_base_fieldset' => true // ) // )); $this->add(array( 'name' => 'security', 'type' => 'Zend\Form\Element\Csrf' )); $this->add(array( 'name' => 'submit', 'type' => 'submit', )); $this->setValidationGroup(array( 'security', 'film' => array( 'categories', ) )); } } 添加操作: public function addAction() { $em = $this->getEntityManager(); $form = $this->getForm(); $film = new Film(); $form->bind($film); if($request->isPost()){ $post = array_merge_recursive( $request->getPost()->toArray(), $request->getFiles()->toArray() ); $form->setData($post); if($form->isValid()){ $categories = array(); foreach($post['film']['categories'] as $categoryId){ $categories[] = $em->getRepository('Admin\Entity\Category')->find($categoryId); } $film->addCategories($categories); $em->persist($film); $em->flush(); }else{ // the form is not valid } } 结果是各种错误和 ORMExcption,并显示消息“在关联 Admin\Entity\Film#categories 上找到类型实体,但期望 Admin\Entity\Category” 请帮帮我,我真的被这个吓坏了!谢谢你:) 据我所知,您的实体正在接收类似的东西Admin\Entity\Film#categories,在这一部分中,类别具有一定的价值。您的实体需要一个类型为 Admin\Entity\Film#categories 的对象。 要克服这个问题,你必须创建一个 public function SetCategory(Admin\Entity\Category Category) { $this->categories(or category or w/e your variable name is)= Category; } public function getCategory() { return $this->categories(or category or w/e your variable name is); } 然后在你的操作中,你必须将Category的对象传递给Film实体,就像这样 $Film->SetCategory($categoryObj); 当然你必须根据你的部分设置你的业务逻辑,但是这个错误应该被这个方法删除。 您需要为目标实体定义 FQCN。 改变: * @ORM\ManyToMany(targetEntity="Category") 至: * @ORM\ManyToMany(targetEntity="Admin\Entity\Category") 这与水合作用和延迟加载有关。 我不是这方面的专家,但是 #categories 是一个代理对象,当您要保存它时,它会抱怨,因为它需要是一个实际的集合,而不是集合的代理对象。 如果您采用了 noobie-php 的方法,您将在主对象上重新附加新的类别对象,因此它们不再是代理。 这令人沮丧,因为 Doctrine 本来应该避免很多麻烦,但在很多情况下它实际上并没有达到您自然期望的效果。 我前段时间发现了一个关于此问题的错误票,但现在找不到它 - 如果我能找到它,我会将其添加到此。
这是我的symfony项目,我正在其中练习功能测试,当我测试我的功能时出现这样的错误。 在这里,发生我的错误的代码部分:\ 这是我的 symfony 项目,我正在其中练习功能测试,当我测试我的功能时出现这样的错误。 这里,发生我的错误的代码部分:\ <?php namespace App\Tests; use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; use App\Entity\Category; class AdminControllerCategoriesTest extends WebTestCase { public function setUp():void { parent::setUp(); $this->client = static::createClient(); $this->entityManager = $this->client->getContainer()->get('doctrine.orm.entity_manager'); $this->entityManager->beginTransaction(); $this->entityManager->getConnection()->setAutoCommit(false); } public function tearDown():void { parent::tearDown(); $this->entityManager->rollback(); $this->entityManager->close(); $this->entityManager = null; //avoid memory leaks } public function testTextOnPage() { $crawler = $this->client->request('GET', '/admin/categories'); $this->assertSame('Categories list', $crawler->filter('h2')->text()); $this->assertContains('Electronics', $this->client->getResponse()->getContent()); } public function testNumberOfItems() { $crawler = $this->client->request('GET', '/admin/categories'); $this->assertCount(21, $crawler->filter('option')); } } 这里是我的.env,我有数据库连接: # In all environments, the following files are loaded if they exist, # the latter taking precedence over the former: # # * .env contains default values for the environment variables needed by the app # * .env.local uncommitted file with local overrides # * .env.$APP_ENV committed environment-specific defaults # * .env.$APP_ENV.local uncommitted environment-specific overrides # # Real environment variables win over .env files. # # DO NOT DEFINE PRODUCTION SECRETS IN THIS FILE NOR IN ANY OTHER COMMITTED FILES. # # Run "composer dump-env prod" to compile .env files for production use (requires symfony/flex >=1.2). # https://symfony.com/doc/current/best_practices.html#use-environment-variables-for-infrastructure-configuration ###> symfony/framework-bundle ### APP_ENV=dev APP_SECRET=018d7408d23791c60854cbb4fc65b667 ###< symfony/framework-bundle ### ###> doctrine/doctrine-bundle ### # Format described at https://www.doctrine-project.org/projects/doctrine-dbal/en/latest/reference/configuration.html#connecting-using-a-url # IMPORTANT: You MUST configure your server version, either here or in config/packages/doctrine.yaml # # DATABASE_URL="sqlite:///%kernel.project_dir%/var/data.db" DATABASE_URL="mysql://root:@127.0.0.1:3306/symf5?serverVersion=mariadb-10.4.11" # DATABASE_URL="postgresql://symfony:[email protected]:5432/app?serverVersion=13&charset=utf8" ###< doctrine/doctrine-bundle ### 在这里,我的 .env.test 文件中有以下代码: # define your env variables for the test env here KERNEL_CLASS='App\Kernel' APP_SECRET='$ecretf0rt3st' SYMFONY_DEPRECATIONS_HELPER=999999 PANTHER_APP_ENV=panther PANTHER_ERROR_SCREENSHOT_DIR=./var/error-screenshots 我不知道出了什么问题,我尝试了不同的方法,但都不起作用,我也不知道这出了什么问题,该怎么办。希望你们能帮我解决我的问题。 谢谢! 您有两个选择: 为您的测试创建新数据库 删除数据库测试中的dbname_suffix,它负责为新数据库测试提供后缀名称 -at config/packages/test/doctrine.yaml - when@test: doctrine: dbal: # "TEST_TOKEN" is typically set by ParaTest dbname_suffix: '_test%env(default::TEST_TOKEN)%' 我想你可能忘记创建 .env.test 文件。 在文档中,您可以阅读需要此文件: https://symfony.com/doc/current/testing.html#customizing-environment-variables 在此文件中,您将使用正确的数据库进行测试。 告诉我它是否有效! 你的 phpunit.xml 看起来怎么样,或者你有吗? 我们在项目目录中添加了一个 phpunit.xml 并在 phpunit.xml 文件中声明了必要的环境变量,例如: <?xml version="1.0" encoding="UTF-8"?> <phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="vendor/phpunit/phpunit/phpunit.xsd" colors="true" bootstrap="vendor/autoload.php" cacheResultFile=".phpunit.cache/test-results" executionOrder="depends,defects" forceCoversAnnotation="true" beStrictAboutCoversAnnotation="true" beStrictAboutOutputDuringTests="true" beStrictAboutTodoAnnotatedTests="true" convertDeprecationsToExceptions="true" failOnRisky="true" failOnWarning="true" verbose="true" > <php> <ini name="display_errors" value="1" /> <ini name="error_reporting" value="1" /> <env name="APP_ENV" value="test" force="true" /> <env name="KERNEL_CLASS" value="App\Kernel" /> <env name="APP_DEBUG" value="false" /> <env name="DATABASE_URL" value="sqlite:///:memory:" force="true" /> <var name="DB_DBNAME" value="app" /> </php> <testsuites> <testsuite name="Test Suite"> <directory>tests</directory> </testsuite> </testsuites> <coverage cacheDirectory=".phpunit.cache/code-coverage" processUncoveredFiles="true"> <include> <directory suffix=".php">src</directory> </include> <exclude> <directory>src/Entity</directory> <directory>src/Repository</directory> <file>src/Kernel.php</file> </exclude> </coverage> <listeners> <listener class="Symfony\Bridge\Phpunit\SymfonyTestsListener" /> </listeners> <extensions> <extension class="Symfony\Component\Panther\ServerExtension" /> </extensions> </phpunit> 为了设置所有功能测试,我们在tests/Framework/FunctionalTestCase.php 上初始化数据库模式 <?php namespace App\Tests\Framework; use App\Tests\Framework\DatabaseUtil\InitDatabase; use Doctrine\ORM\EntityManagerInterface; use Symfony\Bundle\FrameworkBundle\KernelBrowser; use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; class FunctionalTestCase extends WebTestCase { protected EntityManagerInterface|null $entityManager = null; private KernelBrowser|null $client = null; protected function setUp(): void { parent::setUp(); self::ensureKernelShutdown(); $this->client = static::createClient(); InitDatabase::updateSchema($this->client); $this->entityManager = $this->client->getContainer() ->get('doctrine') ->getManager(); } protected function getClientFromParent(): KernelBrowser { return $this->client; } } 以及测试/Framework/DatabaseUtil/InitDataBase.php: <?php namespace App\Tests\Framework\DatabaseUtil; use Doctrine\ORM\Tools\SchemaTool; class InitDatabase { public static function updateSchema(object $kernel): void { $entityManager = $kernel->getContainer()->get('doctrine.orm.entity_manager'); $metaData = $entityManager->getMetadataFactory()->getAllMetadata(); $schemaTool = new SchemaTool($entityManager); $schemaTool->updateSchema($metaData); } } 使用 我们在 ControllerTests 中使用这个FunctionalTestCase,例如: <?php namespace App\Tests\Controller\AnyController; use App\Tests\Framework\FunctionalTestCase; use App\Entity\User; use App\TestsDataFixture\UserFixture; use Doctrine\Common\Collections\Collection; use Doctrine\DBAL\Exception\TableNotFoundException; use Doctrine\Persistence\ObjectManager; class AnyControllerTest extends FunctionalTestCase { private User $user; private User $entityUser; private KernelBrowser $client; public function setUp(): void { parent::setUp(); $userFixture = new UserFixture(); $this->user = $userFixture->load($this->entityManager); $this->entityUser = $this->entityManager->getRepository(User::class)->findAll()[0]; $this->client = $this->getClientFromParent(); } public function tearDown(): void { parent::tearDown(); $this->delete([$this->entityUser], $this->entityManager); } public function testLoginSuccessful(): void { $payload = [ 'username' => $this->user->getEmail(), 'password' => $this->user->getPassword() ]; $this->client->loginUser($this->user); $this->client->request( 'POST', '/auth/login', [], [], [ 'Content-Type' => 'application/json' ], json_encode($payload) ); $response = $this->client->getResponse()->getContent(); $data = json_decode($response, true); $this->assertResponseIsSuccessful(); $this->assertIsString($data['token']); } private function deleteFromDatabase(array|Collection $entities, ObjectManager $manager): void { $connection = $manager->getConnection(); $databasePlatform = $connection->getDatabasePlatform(); if ($databasePlatform->supportsForeignKeyConstraints()) { $connection->query('SET FOREIGN_KEY_CHECKS=0'); } foreach($entities as $entity) { try { $query = $databasePlatform->getTruncateTableSQL( $manager->getClassMetadata(get_class($entity))->getTableName() ); $connection->executeUpdate($query); } catch(TableNotFoundException $exception) { // do nothing } } if ($databasePlatform->supportsForeignKeyConstraints()) { $connection->query('SET FOREIGN_KEY_CHECKS=1'); } } } UserFixture 是一个普通的 DataFixture,具有用于生成 FakeUser 的加载方法,如下例所示:https://symfony.com/bundles/DoctrineFixturesBundle/current/index.html 您可以将私有删除方法放入特征中,以便在多个控制器中使用。 在此示例中,我们使用内存中的 sqlite 数据库,但您也可以将 phpunit 中的 DATABASE_URL 更改为 MariaDB DSN。
监听器“SoftDeleteableListener”未添加到EventManager
我按照这个示例在运行 Symfony 2.1.0-DEV 的项目上测试 softdeletable 扩展。 我配置了 config.yml,如下所示: 奥姆: 自动生成代理类:%kernel.debug%
当我使用 find(id) 执行查询时,它工作正常。 但是当我使用 createQuery 方法时 select u from User u where u.id = 1 然后我得到错误,它是一个数组。 所以我想知道是否可以...
我了解如何为 Doctrine 3 实体添加验证,但据我所知,EasyAdmin 应该将该验证显示为其表单的一部分。目前它只是抛出异常......
我是 Symfony 的新手,我正在尝试创建一个绑定到实体用户的表单。 该实体的一个字段的类型为 ArrayCollection。它实际上是与另一个对象的 OneToMany 关系...
我正在为这个课程编写一个单元测试: 我正在为这门课编写单元测试: <?php namespace AppBundle\Managers\CRUD; use Doctrine\ORM\EntityManager; use CommonLibs\Interfaces\CrudManagerInterface; use AppBundle\Entity\Pet; use CommonLibs\Helpers\PaginatorHelper; use AppBundle\Entity\Person; use AppBundle\Managers\CRUD\PetManager; use AppBundle\AppBundle; class PersonManager extends CrudManagerInterface { /** * @var EntityManager */ private $em; /** * @var PetManager */ private $petManager; public function __construct(EntityManager $em,PetManager $petManager) { $this->em=$em; $this->petManager=$petManager; } /** * {@inheritDoc} * @see \CommonLibs\Interfaces\CrudManagerInterface::search() * @return AppBundle\Entity\Person[] */ public function search(array $searchParams, array $order, $page, $limit) { $queryBuilder=$this->em->createQueryBuilder(); $queryBuilder=$queryBuilder->select('p')->from('AppBundle:Person','p'); if(isset($searchParams[Person::NAME])) { $queryBuilder->andWhere('p.name LIKE :name')->setParameter('name','%'.$searchParams[Person::NAME].'%'); } $petNameSearch=isset($searchParams[Pet::NAME]); $petTypeSearch=isset($searchParams[Pet::TYPE]); if( $petNameSearch || $petTypeSearch ) { $queryBuilder->join('p.pets','pe'); if($petNameSearch) { $queryBuilder->andWhere('pe.name LIKE :pet_name')->setParameter('pet_name','%'.$searchParams[Pet::NAME].'$'); } if($petTypeSearch) { if(!is_array($searchParams[Pet::TYPE])) { $searchParams[Pet::TYPE]=array($searchParams[Pet::TYPE]); } $queryBuilder->andWhere('pe.type IN (:pet_types)')->setParameter('pet_types',$searchParams[Pet::TYPE]); } /** * @var Doctrine\ORM\Query */ $query=$queryBuilder->getQuery(); if((int)$limit>0) { $query->setFirstResult(PaginatorHelper::calculateFirstResult($page,$limit))->setMaxResults((int)$limit); } $results=$query->getResult(); return $results; } } /** * {@inheritDoc} * @see \CommonLibs\Interfaces\CrudManagerInterface::getById() * @return AppBundle\Entity\Person */ public function getById($id) { return $this->em->getManager('AppBundle:Person')->findById($id); } /** * {@inheritDoc} * @see \CommonLibs\Interfaces\CrudManagerInterface::add() * * @param array $dataToAdd * * $dataToAdd Must have one of the follofiwng formats: * * FORMAT 1: * [ * Person:NAME=>"value" * ] * * FORMAT 2: * * [ * [ * Person:NAME=>"value" * ], * [ * Person:NAME=>"value" * ], * [ * Person:NAME=>"value" * ] * ] * * @return AppBundle\Entiry\Person[] with the modified persons */ public function add(array $dataToAdd) { /** * @var AppBundle\Entiry\Person $insertedPersons */ $insertedPersons=[]; foreach($dataToAdd as $key=>$data) { $personToInsert=new Person(); if(is_array($data)) { $personToInsert=$this->add($data); if($personToInsert==false) { return false; } } elseif(!$this->setReference($personToInsert,$key,$data)) { $personToInsert->$$key=$data; } if(is_array($personToInsert)) { $insertedPersons=array_merge($insertedPersons,$personToInsert); } else { $this->em->flush($personToInsert); $insertedPersons[]=$personToInsert; } } if(!empty($insertedPersons)) { $this->em->flush(); } return $insertedPersons; } /** * {@inheritDoc} * @see \CommonLibs\Interfaces\CrudManagerInterface::edit() */ public function edit(array $changedData) { $em=$this->em->getManager('AppBundle:Person'); foreach($changedData as $id => $fieldsToChange) { $item=$this->getById($id); foreach($fieldsToChange as $fieldName=>$fieldValue){ if(!$this->setReference($item,$fieldName,$fieldValue)){ $item->$$fieldName=$fieldValue; } } $em->merge($item); } $em->flush(); } /** * {@inheritDoc} * @see \CommonLibs\Interfaces\CrudManagerInterface::delete() * * @param array changedData * Should contain data in the following formats: * FORMAT 1: * * [ * Person::ID=>^an_id^ * Person::NAME=>^a name of a person^ * ] * * FORMAT2: * [ * Person::ID=>[^an_id1^,^an_id2^,^an_id3^...,^an_idn^] * Person::NAME=>^a name of a person^ * ] * * The $changedData MUST contain at least one of Person::ID or Person::NAME. * Therefore you can ommit one of Person::ID or Person::NAME but NOT both. */ public function delete(array $changedData) { $queryBuilder=$this->em->createQueryBuilder(); $queryBuilder->delete()->from('AppBundle:Person','p'); $canDelete=false; if(isset($changedData[Person::ID])) { if(!is_array($changedData[Person::ID])) { $changedData[Person::ID]=[$changedData[Person::ID]]; } $queryBuilder->where('person.id IN (:id)')->bindParam('id',$changedData[Person::ID]); $canDelete=true; } if(isset($changedData[Person::NAME])) { $queryBuilder->orWhere('person.name is :name')->bindParam('name',$changedData[Person::NAME]); $canDelete=true; } if($canDelete) { $query=$queryBuilder->getQuery(); $query->execute(); } return $canDelete; } /** * Set referencing fields to person. * * @param AppBundle\Entiry\Person $item The item to set the reference * @param string $referencingKey A string that Indicates the input field. * The strings for the param above are defined as constants at AppBundle\Entiry\Person. * @param mixed $referencingValue The value of referencing key * * @return boolean */ private function setReference($item,$referencingKey,$referencingValue) { /** * @var AppBundle\Entity\Pet $pet */ $pet=null; if($referencingKey===Person::PET) { if(is_numeric($referencingValue)) {//Given pet id $pet=$this->petManager->getById($referencingValue);//Searching pet by id } elseif (is_object($referencingValue) && $referencingValue instanceof AppBundle\Entity\Pet ){//Given directly a pet Object $pet=$referencingValue; } $item->$$referencingKey=$referencingValue; return true; } return false; } } 我想模拟 Doctrine 的实体管理器。但我不知道要返回什么才能成功使用 Doctrine 的查询生成器,但没有实际的数据库连接。 好吧,如果你想真正遵循最佳实践,你不应该嘲笑实体管理器,因为你不拥有它;您可以在以下链接阅读更多内容 https://github.com/mockito/mockito/wiki/How-to-write-good-tests https://adamwathan.me/2017/01/02/dont-mock-what-you-dont-own/ https://8thlight.com/blog/eric-smith/2011/10/27/thats-not-yours.html 好吧,现在,如果你想走那条路,你可以像嘲笑 EntityManager 中的所有其他对象一样嘲笑 PHPUnit 如果您使用 PHPUnit >= 5.7 且 PHP > 5.5 $mockedEm = $this->createMock(EntityManager::class) 或 PHP <= 5.5 $mockedEm = $this->createMock('Doctrine\\ORM\\EntityManager'); 一旦你模拟了它,你就必须声明所有预设的响应和期望:预设的响应是为了让你的代码工作,而期望是为了让它成为一个模拟 举个例子,这应该是罐头的 return $this->em->getManager('AppBundle:Person')->findById($id); 正如您将看到的,为每个方法调用声明一个固定方法可能非常困难且过度;例如,在这里,你应该这样做 $mockedEm = $this->createMock(EntityManager::class) $mockedPersonManager = $this->createMock(...); $mockedEm->method('getManager')->willReturn(mockedPersonManager); $mockedPersonManager->findOneBy(...)->willReturn(...); (当然你必须用实际值替换...) 最后,记住模拟不是存根
在 Doctrine2 中为元表结构创建映射以在 FormBuilder 中使用
我有两张桌子: 分支机构: +-------------+--------------+------+-----+-------- --+----------------+ |领域 |类型 |空 |关键|默认 |额外 | +-------------+---------...
通常,当您使用 Doctrine 实现实体时,您会将其显式映射到表: 通常,当您使用 Doctrine 实现实体时,您会将其显式映射到表: <?php /** * @Entity * @Table(name="message") */ class Message { //... } 或者您回复原则以隐式将您的类名映射到表...我有几个在架构上相同的表,但我不希望每次都重新创建该类...因此在运行时(动态地) )我想相应地更改表名称。 我从哪里开始或者我会考虑什么来实现这个奇怪的要求??? 令我惊讶的是,解决方案非常简单。您所要做的就是获取实体的 ClassMetadata 并更改它映射到的表的名称: /** @var EntityManager $em */ $class = $em->getClassMetadata('Message'); $class->setPrimaryTable(['name' => 'message_23']); 您需要小心,在加载了一些Message类型的实体并更改它们后,不要更改表名称。如果幸运的话,它很可能会在保存时产生 SQL 错误(例如,由于表约束),否则它会修改错误的行(来自新表)。 我建议以下工作流程: 设置所需的表名; 加载一些实体; 随意修改; 拯救他们; 将它们与实体管理器分离(方法 EntityManager::clear() 是重新开始的快速方法); 返回步骤 1(即使用另一个表重复)。 即使您不更改或不保存实体,步骤#5(从实体管理器中分离实体)也很有用。它允许实体管理器使用更少的内存并更快地工作。 这只是可用于动态设置/更改映射的众多方法之一。其余部分请查看 ClassMetadata 类的文档。您可以在PHP映射的文档页面中找到更多灵感。
Symfony/FosUserBundle - 在数据库中存储角色
如何在数据库中存储角色? 我尝试了这种方法http://blog.jmoz.co.uk/symfony2-fosuserbundle-role-entities/ 用户.php /** * @ORM\实体 * @ORM\Table(名称=“`用户`”) */ User 类扩展了 BaseU...
如何阻止 symfony 尝试为我在学说迁移中创建的视图创建表? 实体映射视图 /** * 类 TenancyPendingInspection * @ORM\Entity(repositoryClass="
编写功能测试时将会话中的用户附加到当前EntityManager
我正在为与用户实体有关系的操作实体编写功能测试: 我正在为与 Action 实体有关系的 User 实体编写功能测试: <?php namespace Acme\AppBundle\Entity; /** * Class Action * * @ORM\Table() * @ORM\Entity(repositoryClass="Acme\AppBundle\Repository\ActionRepository") */ class Action { /** * @var int * * @ORM\Column(type="integer") * @ORM\Id * @ORM\GeneratedValue(strategy="AUTO") */ private $id; /** * @var \Acme\AppBundle\Entity\User * * @ORM\ManyToOne(targetEntity="\Acme\AppBundle\Entity\User", inversedBy="actions") * @ORM\JoinColumn(name="user_id", referencedColumnName="id") */ private $createdBy; } 用户: namespace Acme\AppBundle\Entity; /** * @ORM\Entity * @ORM\Table(name="`user`") */ class User extends BaseUser { /** * @ORM\Id * @ORM\Column(type="integer") * @ORM\GeneratedValue(strategy="AUTO") */ protected $id; /** * @var ArrayCollection * * @ORM\OneToMany(targetEntity="Action", mappedBy="createdBy") */ private $actions; } 用户使用以下代码片段在控制器中设置: <?php namespace Acme\ApiBundle\Controller; /** * * @Route("/actions") */ class ActionController extends FOSRestController { public function postAction(Request $request) { $action = new Action(); $action->setCreatedBy($this->getUser()); return $this->processForm($action, $request->request->all(), Request::METHOD_POST); } } 例如,当使用 REST 客户端调用操作时,一切正常,Action 和 User 之间的关系正确保留。 现在,当使用功能测试来测试操作时,由于以下错误,该关系不起作用: 通过关系“Acme\AppBundle\Entity\Action#createdBy”找到了一个新实体,该实体未配置为实体的级联持久操作:测试。要解决此问题:对此未知实体显式调用 EntityManager#persist() 或配置级联在映射中保留此关联,例如 @ManyToOne(..,cascade={"persist"})。 对于我的功能测试,我需要注入 JWT 和会话令牌,因为我的路由由 JWT 保护,并且我需要在会话中拥有用户。 这是我注入的方法: <?php namespace Acme\ApiBundle\Tests; class ApiWebTestCase extends WebTestCase { /** * @var ReferenceRepository */ protected $fixturesRepo; /** * @var Client */ protected $authClient; /** * @var array */ private $fixtures = []; protected function setUp() { $fixtures = array_merge([ 'Acme\AppBundle\DataFixtures\ORM\LoadUserData' ], $this->fixtures); $this->fixturesRepo = $this->loadFixtures($fixtures)->getReferenceRepository(); $this->authClient = $this->createAuthenticatedClient(); } /** * Create a client with a default Authorization header. * * @return \Symfony\Bundle\FrameworkBundle\Client */ protected function createAuthenticatedClient() { /** @var User $user */ $user = $this->fixturesRepo->getReference('user-1'); $jwtManager = $this->getContainer()->get('lexik_jwt_authentication.jwt_manager'); $token = $jwtManager->create($user); $this->loginAs($user, 'api'); $client = static::makeClient([], [ 'AUTHENTICATION' => 'Bearer ' . $token, 'CONTENT_TYPE' => 'application/json' ]); $client->disableReboot(); return $client; } } 现在,问题是注入的 UsernamePasswordToken 包含一个与当前 User 分离的 EntityManager 实例,从而导致上面的 Doctrine 错误。 我可以将 $user 方法中的 postAction 对象合并到 EntityManager 中,但我不想这样做,因为这意味着我修改我的工作代码以使测试通过。 我还尝试将测试中的 $user 对象直接合并到 EntityManager 中,如下所示: $em = $client->getContainer()->get('doctrine')->getManager(); $em->merge($user); 但它也不起作用。 所以现在,我陷入了困境,我真的不知道该怎么办,除了我需要将会话中的用户附加回当前EntityManager。 您收到的错误消息表明测试客户端容器中包含的 EntityManager 不了解您的 User 实体。这让我相信您在 createAuthenticatedClient 方法中检索 User 的方式是使用不同的 EntityManager。 我建议您尝试使用测试内核的 EntityManager 来检索 User 实体。例如,您可以从测试客户端的容器中获取它。 感谢您的推文,我来完成给定的答案并(尝试)提出解决方案, 问题是您的用户不受 EntityManager 管理,更简单地说,因为它不是在数据库中注册的真实现有用户。 要解决此问题,您需要有一个真正的(托管)用户,该规则可以用于您的操作试图创建的关联。 因此,您可以在每次执行功能测试用例时创建此用户(并在完成后将其删除),或者仅在新环境中首次执行测试用例时创建一次。 这样的事情应该可以解决问题: /** @var EntityManager */ private $em; /** */ public function setUp() { $client = static::createClient(); $this->em = $client->getKernel() ->getContainer() ->get('doctrine'); $this->authClient = $this->createAuthenticatedClient(); } /** */ protected function createAuthenticatedClient() { /** @var User $user */ $user = $this->em ->getRepository('Acme\AppBundle\Entity\User') ->findOneBy([], ['id' => DESC]; // Fetch the last created // ... return $client; } 这对你的灯具来说是一个遗憾(它们太性感了),但我看不到任何方法可以将你的灯具作为真正的入口附加起来,因为你无法与测试的控制器进行更多交互。 另一种方法是向您的登录端点创建请求,但这会更难看。
带有“$fetchJoinCollection = true”的分页器不会遵守 DQL 中的“ORDER BY”?
有一个奇怪的问题。我们正在使用 MariaDB 5.5 和doctrine/orm 2.3.3,并尝试将 Doctrine Paginator 与 DQL 结合使用。 http://docs.doctrine-project.org/en/latest/tutorials/pagination.html 该...
当我们尝试 setFilters() / getFilters() 时,我们都遇到过这个问题:“实体必须被管理” 那么如何以通用的方式处理过滤器的会话存储,以便......
我有一个简单的问题, 如何创建表单列表元素,例如网格或以下内容: [x] 姓名 |图像| [按钮] [ ] 姓名 |图像| [按钮] [x] 姓名 |图像| [按钮] 我有一个简单的问题, 我如何创建表单列表元素,例如网格或这样: [x] name | image | [button] [ ] name | image | [button] [x] name | image | [button] <table> <tr><th>checkbox</th><th>name</th><th>action</th></tr> <tr><td><input type="checkbox"></td><td>name</td><td><button>OK</td></tr> <tr><td><input type="checkbox"></td><td>name</td><td><button>OK</td></tr> <tr><td><input type="checkbox"></td><td>name</td><td><button>OK</td></tr> </table> //列出数据库中的实体,数组(对象,对象,对象) //对象=应用程序\实体\区域 $areas = $this->getObjectManager()->getRepository('Application\Entity\Area')->findAll(); 我在表单 Zend\Form\Element\Collection 中使用,但我不知道如何从数据库填充集合日期,所以我有清晰的表单。 我应该正确做,用什么? 从 Doctrine 中你已经得到了一个可迭代的数据类型(数组)。所以你只需要在你的视图中迭代它: ... <?php foreach($this->data as $area): ?> //your table row markup for a single entity <?php endforeach; ?> ... 免责声明:我问过类似的问题,但没有答案。所以我也很想知道“Zend”方式,或者是否有人能够提出替代方案。 下面的方法似乎对我有用。 ListForm.php 将集合添加到您的“列表”表单中。 /** The collection that holds each element **/ $name = $this->getCollectionName(); $collectionElement = new \Zend\Form\Element\Collection($name); $collectionElement->setOptions(array( 'count' => 0, 'should_create_template' => false, 'allow_add' => true )); $this->add($collectionElement); 这个集合将容纳集合元素(Zend\Form\Element\Checkbox) /** The element that should be added for each item **/ $targetElement = new \Zend\Form\Element\Checkbox('id'); $targetElement->setOptions(array( 'use_hidden_element' => false, 'checked_value' => 1, )); $collectionElement->setTargetElement($targetElement); 然后我添加了一些方法来允许我将 ArrayCollecion 传递到表单。对于我的集合中的每个实体,我将创建一个新的 $targetElement;将其检查值设置为实体的 id。 /** * addItems * * Add multiple items to the collection * * @param Doctrine\Common\Collections\Collection $items Items to add to the * collection */ public function addItems(Collection $items) { foreach($items as $item) { $this->addItem($item); } return $this; } /** * addItem * * Add a sigle collection item * * @param EntityInterface $entity The entity to add to the * element collection */ public function addItem(EntityInterface $item) { $element = $this->createNewItem($item->getId()); $this->get($this->getCollectionName())->add($element); } /** * createNewItem * * Create a new collection item * * @param EntityInterface $entity The entity to create * @return \Zend\Form\ElementInterface */ protected function createNewItem($id, array $options = array()) { $element = clone $this->targetElement; $element->setOptions(array_merge($element->getOptions(), $options)); $element->setCheckedValue($id); return $element; } 然后需要的就是将集合从控制器操作内传递到表单。 一些控制器 public function listAction() { //.... $users = $objectManager->getRepository('user')->findBy(array('foo' => 'bar')); $form = $this->getServiceLocator()->get('my_list_form'); $form->addItems($users); //... } 您可以使用数据库中的学说填充多选复选框,使用 DoctrineModule\Form\Element\ObjectMultiCheckbox,如本页所示: https://github.com/doctrine/DoctrineModule/blob/master/docs/form-element.md 只需将实体管理器传递给表单,然后按照示例中的操作即可创建 ObjectMultiCheckbox 表单元素... 或其他更好的 -moro 自动化工作方法,如果您想使用集合,您需要对区域进行正确的映射(@orm\OneToMany 和 @orm\ManyToOne)...并在形式如下...: http://framework.zend.com/manual/2.2/en/modules/zend.form.collections.html 并向其他实体添加方法以添加和删除区域,如下所示: public function addArea(Collection $areas) { foreach ($areas as $area) { $area->setOtherEntity($this); $this->areas->add($area); } } public function removeAreas(Collection $areas) { foreach ($areas as $area) { $area->setOtherEntity(null); $this->areas->removeElement($area); } } 如果您使用水合作用,当您自动选择它们时,这些值将被添加和删除...
graphql 中的 Post 请求返回数据字段,但它们的值为空
我制作了一个 graphql 控制器,它可以从原则中解析有关类别的信息。当我在终端输入以下命令时,问题就开始了: 卷曲 -X POST http://localhost:8000/graphq...
Symfony ParamConverter 到 MapEntity
我正在尝试将我的symfony应用程序从版本5.4升级到6.4,因为Sensio Bundle已被放弃,我需要使用属性而不是注释,我如何将paramcoverter注释转换为
我在我制作的一个小框架中有一个用户实体。现在我想在几个项目中使用这个用户实体。 但在某些项目中我想向用户实体添加一些字段而不修改...
使用 DoctrineExtensios 更新 slug 创建的另一个字段
我在 Symfony 2 项目中使用 DoctrineExtensions,我有一个简单的实体类,其中我在属性上使用 Sluggable,然后我想根据 slug 将值设置为另一个属性,...