最近,我开始在导入脚本中使用Symfony Validator组件来验证实体是否设置了所有必填字段,并且没有“唯一约束违例”。无效的条目将被跳过并记录。
我不确定,但是这个github问题可能描述了相同的问题: https://github.com/doctrine/orm/issues/7277
验证器组件的版本为v4.2.5
并且该理论库的版本为v2.6.3
以前有人遇到这样的问题吗?我该如何解决?
error: {
message: "Argument 2 passed to Doctrine\ORM\Cache\EntityCacheKey::__construct() must be of the type array, null given, called in /var/www/myproject/vendor/doctrine/orm/lib/Doctrine/ORM/Cache/DefaultQueryCache.php on line 353",
trace: [
"/var/www/myproject/vendor/doctrine/orm/lib/Doctrine/ORM/Cache/EntityCacheKey.php:49",
"/var/www/myproject/vendor/doctrine/orm/lib/Doctrine/ORM/Cache/DefaultQueryCache.php:353",
"/var/www/myproject/vendor/doctrine/orm/lib/Doctrine/ORM/Cache/DefaultQueryCache.php:305",
"/var/www/myproject/vendor/doctrine/orm/lib/Doctrine/ORM/Cache/Persister/Entity/AbstractEntityPersister.php:426",
"/var/www/myproject/vendor/doctrine/orm/lib/Doctrine/ORM/EntityRepository.php:181",
"/var/www/myproject/vendor/symfony/doctrine-bridge/Validator/Constraints/UniqueEntityValidator.php:139",
"/var/www/myproject/vendor/symfony/validator/Validator/RecursiveContextualValidator.php:809",
"/var/www/myproject/vendor/symfony/validator/Validator/RecursiveContextualValidator.php:525",
"/var/www/myproject/vendor/symfony/validator/Validator/RecursiveContextualValidator.php:330",
"/var/www/myproject/vendor/symfony/validator/Validator/RecursiveContextualValidator.php:141",
"/var/www/myproject/vendor/symfony/validator/Validator/RecursiveValidator.php:100",
"/var/www/myproject/src/Service/Api/Import/StoreImporter.php:251",
"/var/www/myproject/src/Command/Api/Import/StoreImporterCommand.php:92",
"/var/www/myproject/vendor/symfony/console/Command/Command.php:255",
"/var/www/myproject/vendor/symfony/console/Application.php:926",
"/var/www/myproject/vendor/symfony/framework-bundle/Console/Application.php:89",
"/var/www/myproject/vendor/symfony/console/Application.php:269",
"/var/www/myproject/vendor/symfony/framework-bundle/Console/Application.php:75",
"/var/www/myproject/vendor/symfony/console/Application.php:145",
"/var/www/myproject/bin/console:39"
]
},
在另一个进口商中,出现了一个问题,该问题也与二级缓存有关。 堆栈跟踪显示了一个区别,它使用了liip / functional-test-bundle DataCollectingValidator,因为这是我在“开发”环境中运行命令的时候。
error: {
message: "Notice: Undefined index: 0000000051f7928f000000005709f6ca",
trace: [
"/var/www/myproject/vendor/doctrine/orm/lib/Doctrine/ORM/UnitOfWork.php:2995",
"/var/www/myproject/vendor/doctrine/orm/lib/Doctrine/ORM/Cache/DefaultQueryCache.php:352",
"/var/www/myproject/vendor/doctrine/orm/lib/Doctrine/ORM/Cache/DefaultQueryCache.php:305",
"/var/www/myproject/vendor/doctrine/orm/lib/Doctrine/ORM/Cache/Persister/Entity/AbstractEntityPersister.php:426",
"/var/www/myproject/vendor/doctrine/orm/lib/Doctrine/ORM/EntityRepository.php:181",
"/var/www/myproject/vendor/symfony/doctrine-bridge/Validator/Constraints/UniqueEntityValidator.php:139",
"/var/www/myproject/vendor/symfony/validator/Validator/RecursiveContextualValidator.php:809",
"/var/www/myproject/vendor/symfony/validator/Validator/RecursiveContextualValidator.php:525",
"/var/www/myproject/vendor/symfony/validator/Validator/RecursiveContextualValidator.php:330",
"/var/www/myproject/vendor/symfony/validator/Validator/RecursiveContextualValidator.php:141",
"/var/www/myproject/vendor/symfony/validator/Validator/RecursiveValidator.php:100",
"/var/www/myproject/vendor/symfony/validator/Validator/TraceableValidator.php:66",
"/var/www/myproject/vendor/liip/functional-test-bundle/src/Validator/DataCollectingValidator.php:66",
"/var/www/myproject/src/Service/Api/Import/DeviceImporter.php:272",
"/var/www/myproject/src/Command/Api/Import/DeviceImporterCommand.php:92",
"/var/www/myproject/vendor/symfony/console/Command/Command.php:255",
"/var/www/myproject/vendor/symfony/console/Application.php:926",
"/var/www/myproject/vendor/symfony/framework-bundle/Console/Application.php:89",
"/var/www/myproject/vendor/symfony/console/Application.php:269",
"/var/www/myproject/vendor/symfony/framework-bundle/Console/Application.php:75",
"/var/www/myproject/vendor/symfony/console/Application.php:145",
"/var/www/myproject/bin/console:39"
]
}
编辑:添加了唯一实体约束的配置:
/**
* Device Entity
*
* @ORM\Cache(region = "rarely_changing", usage = "NONSTRICT_READ_WRITE")
* @ORM\Entity(repositoryClass = "App\Repository\DeviceRepository")
* @ORM\Table(name = "s4_device", indexes = {
* @ORM\Index(name = "device_model_search_index", columns = {"device_model"}),
* @ORM\Index(name = "device_slug_search_index", columns = {"device_slug"}),
* }, uniqueConstraints = {
* @ORM\UniqueConstraint(name = "UNIQUE_DEVICE_MODEL_AND_BRAND", columns = {"device_model", "brand_id"})
* })
* @UniqueEntity(fields = {"model", "brand"}, errorPath = "model", message = "device-model-is-not-unique")
*/
class Device extends AbstractEntity
{
/* ... */
/**
* @var DeviceReference
*
* @ORM\Cache(region = "rarely_changing", usage = "NONSTRICT_READ_WRITE")
* @ORM\OneToOne(targetEntity = "App\Entity\Model\Reference\DeviceReference", mappedBy = "device", cascade = {"persist", "remove"})
*/
protected $reference;
/* ... */
}
/**
* Store Entity
*
* @ORM\Cache(region = "rarely_changing", usage = "NONSTRICT_READ_WRITE")
* @ORM\Entity(repositoryClass = "App\Repository\StoreRepository")
* @ORM\Table(name = "s4_store", indexes = {
* @ORM\Index(name = "store_name_search_index", columns = {"store_name"}),
* @ORM\Index(name = "store_slug_search_index", columns = {"store_slug"})
* }, uniqueConstraints = {
* @ORM\UniqueConstraint(name = "UNIQUE_STORE_NAME", columns = {"store_name"})
* })
* @UniqueEntity(fields = {"name"}, message = "store-name-is-not-unique")
* @UniqueEntity(fields = {"uri"}, message = "store-uri-is-not-unique")
*/
class Store extends AbstractEntity
{
/* ... */
/**
* @var StoreReference|null
*
* @ORM\Cache(region = "rarely_changing", usage = "NONSTRICT_READ_WRITE")
* @ORM\OneToOne(targetEntity = "App\Entity\Model\Reference\StoreReference", mappedBy = "store", cascade = {"persist", "remove"})
*/
protected $reference;
/* ... */
}
Store Importer(示例,其中省略了不相关的代码)
namespace App\Service\Api\Import;
/* ... */
use Symfony\Component\Validator\Validator\ValidatorInterface;
class StoreImporter
{
/**
* @var StoreManagerInterface
*/
private $_storeManager;
/**
* @var ValidatorInterface
*/
private $_validator;
/**
* @param StoreManagerInterface $storeManager
* @param ValidatorInterface $validator
*/
public function __construct(StoreManagerInterface $storeManager, ValidatorInterface $validator)
{
$this->_storeManager = $storeManager;
$this->_validator = $validator;
}
public function import()
{
/* ... */
foreach ($storeHashes as $md5hash => $storeDetails) {
/* @var Store $store */
$store = $this->_storeManager->findOrCreateByReference(
$storeDetails["company_id"], // cs-cart ID
$storeDetails["company"] // store name
);
/* ... */
$validationErrors = $this->_validator->validate($store);
if (count($validationErrors) > 0) {
$validationContext = [
"errors" => (string) $validationErrors,
"details" => $storeDetails,
];
$this->logError("Skipping " . (string) $store . " - Store has validation errors", $validationContext);
continue; // skip saving store details when there are validation errors
}
/* ... */
$this->_storeManager->saveOne($store, false);
}
/* ... */
$this->_storeManager->flush();
$this->_storeManager->clear();
/* ... */
}
/* ... */
}
编辑2:这是在唯一实体验证器的第139行发生的情况。
138
139 $result = $repository->{$constraint->repositoryMethod}($criteria);
140
转储的变量($ constraint和$ criteria)
"constraint" => Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity {#2 462
+message: "device-model-is-not-unique"
+service: "doctrine.orm.validator.unique"
+em: null
+entityClass: null
+repositoryMethod: "findBy"
+fields: array:2 [
0 => "model"
1 => "brand"
]
+errorPath: "model"
+ignoreNull: true
+payload: null
+"groups": array:2 [
0 => "Default"
1 => "Device"
]
}
"criteria" => array:2 [
"model" => "Xperia XZ"
"brand" => App\Entity\Model\DeviceBrand {#2183
#type: "device_brand"
#devices: Doctrine\ORM\PersistentCollection {#2184
-snapshot: []
-owner: App\Entity\Model\DeviceBrand {#2183}
-association: array:16 [ …16]
-em: Doctrine\ORM\EntityManager {#561 …11}
-backRefFieldName: "brand"
-typeClass: Doctrine\ORM\Mapping\ClassMetadata {#128 …}
-isDirty: false
#collection: Doctrine\Common\Collections\ArrayCollection {#2185
-elements: []
}
#initialized: false
}
#id: 14
#name: "Sony"
#slug: "sony"
#createdAt: DateTime @1560754604 {#2182
date: 2019-06-17 08:56:44.0 Europe/Berlin (+02:00)
}
#createdBy: null
#deleted: false
#deletedAt: null
#deletedBy: null
#updatedAt: null
#updatedBy: null
}
]
编辑#3:
我通过尝试调试一些奇怪的行为 教义ORM库中的UnitOfWork类。 显然,在objectIdentifiers数组中找不到对象哈希。 找不到的实体类型是与我要更新的实体的OneToOne关系。
UnitOfWork(经过修改)
/**
* Gets the identifier of an entity.
* The returned value is always an array of identifier values. If the entity
* has a composite identifier then the identifier values are in the same
* order as the identifier field names as returned by ClassMetadata#getIdentifierFieldNames().
*
* @param object $entity
*
* @return array The identifier values.
*/
public function getEntityIdentifier($entity)
{
if (!array_key_exists(spl_object_hash($entity), $this->entityIdentifiers)) {
dump([
"entity-class" => get_class($entity),
"object-hash" => spl_object_hash($entity),
"identifiers" => $this->entityIdentifiers,
]);
exit();
}
return $this->entityIdentifiers[spl_object_hash($entity)];
}
转储结果:
array:3 [
"entity-class" => "App\Entity\Model\Reference\StoreReference"
"object-hash" => "000000002f4c81ef00000000678832e6"
"identifiers" => array:6 [
"000000002f4c805b00000000678832e6" => array:1 [
"id" => 1
]
"000000002f4c805700000000678832e6" => array:1 [
"id" => 2
]
"000000002f4c813600000000678832e6" => array:1 [
"id" => 6
]
"000000002f4c816100000000678832e6" => array:1 [
"id" => 2
]
"000000002f4c819f00000000678832e6" => array:1 [
"id" => 1
]
"000000002f4c81e200000000678832e6" => array:1 [
"id" => 1
]
]
]
商店参考实体
namespace App\Entity\Model\Reference;
use App\Entity\Model\Store;
use Doctrine\ORM\Mapping as ORM;
use App\Entity\Model\Reference\AbstractReferenceEntity;
/**
* @ORM\Cache(region = "rarely_changing", usage = "NONSTRICT_READ_WRITE")
* @ORM\Entity()
* @ORM\Table(name = "s4_store_reference", indexes = {
* @ORM\Index(name = "reference_external_id_search_index", columns = {"external_id"})
* })
*/
class StoreReference extends AbstractReferenceEntity
{
/**
* @return string
*/
public function __toString()
{
return "[" . $this->id . "] StoreReference";
}
/**
* ID
*
* @var integer
*
* @ORM\Id
* @ORM\Column(name = "store_reference_id", type = "integer", unique = true)
* @ORM\GeneratedValue(strategy = "AUTO")
*/
protected $id;
/**
* @var Store
*
* @ORM\Cache(region = "rarely_changing", usage = "NONSTRICT_READ_WRITE")
* @ORM\OneToOne(targetEntity = "App\Entity\Model\Store", inversedBy = "reference", cascade = { "persist", "remove" })
* @ORM\JoinColumn(name = "store_id", referencedColumnName = "store_id", nullable = false)
*/
protected $store;
/* ... additional methods ... */
}
我也在尝试在this github repository
中重现此问题。答案 0 :(得分:0)
因此,我找到了解决该问题的方法,这是一个Doctrine错误。这不是很常规,但在此之前一直有效,直到Doctrine ORM 2.6.4发行版可用为止。
我对所有错误的OneToOne关联进行了不同的配置。通过将关系更改为ManyToOne关系,并以编程方式坚持并仅选择一个实体,我仍然具有“一对一”关系,并且我的应用程序将继续正常运行。代码:
设备实体:
/**
* Device References
*
* One Device has one Reference
*
* note: this relation is configured as a One to Many association to work around a bug in Doctrine
*
* @var ArrayCollection|DeviceReference[]
*
* @ORM\Cache(region = "rarely_changing", usage = "NONSTRICT_READ_WRITE")
* @ORM\OneToMany(targetEntity = "App\Entity\Model\Reference\DeviceReference", mappedBy = "device", cascade = {"persist", "remove"})
*/
protected $references;
/**
* Add reference
*
* @param DeviceReference $reference
*
* @return self
*/
public function addReference(DeviceReference $reference)
{
$reference->setDevice($this);
$this->references = new ArrayCollection([$reference]);
return $this;
}
/**
* Remove reference
*
* @param DeviceReference $reference
*/
public function removeReference(DeviceReference $reference)
{
$this->references->removeElement($reference);
}
/**
* Get references
*
* @return Collection|DeviceReference[]
*/
public function getReferences()
{
return $this->references;
}
/**
* Set reference
*
* @param DeviceReference $reference
*
* @return self
*/
public function setReference(DeviceReference $reference)
{
$this->addReference($reference);
return $this;
}
/**
* Get reference
*
* @return DeviceReference
*/
public function getReference()
{
if (0 === $this->references->count()) {
return null;
}
return $this->references->first();
}
DeviceReference实体:
/**
* Device
*
* One Reference has one Device
*
* note: this relation is configured as a Many to One association to work around a bug in Doctrine
*
* @var Device
*
* @ORM\Cache(region = "commonly_changing", usage = "NONSTRICT_READ_WRITE")
* @ORM\ManyToOne(targetEntity = "App\Entity\Model\Device", inversedBy = "references")
* @ORM\JoinColumn(name = "device_id", referencedColumnName = "device_id", nullable = false, unique = true)
*/
private $device;
/* ... getter and setter remain the same ... */
别忘了更新存储库中的任何自定义查询!