我有这个实体
<?php
namespace App\Entity;
use ApiPlatform\Metadata\ApiResource;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Criteria;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Serializer\Annotation\Groups;
#[ApiResource(
normalizationContext: ["groups" => ["contact", "contact_read"]],
denormalizationContext: ["groups" => ["contact", "contact_write"]]
)]
#[ORM\Entity]
class Contact
{
// ...
#[ORM\OneToMany(targetEntity: Email::class, mappedBy: "contact")]
#[Groups(["contact"])]
private $emails;
// ...
public function __construct()
{
$this->emails = new ArrayCollection();
}
// ...
public function getEmails()
{
return $this->emails;
}
// ...
}
我想添加虚拟财产
#[Groups(["contact"])]
public function getPrimaryEmail()
{
$criteria = Criteria::create()->where(Criteria::expr()->eq("is_primary", true));
$matches = $this->emails->matching($criteria);
return ($matches->count()) ? $matches->first()->getAccount() : null;
}
并且它有效......但如果方法的名称是
getEmail()
,则无效
#[Groups(["contact"])]
public function getEmail()
{
$criteria = Criteria::create()->where(Criteria::expr()->eq("is_primary", true));
$matches = $this->emails->matching($criteria);
return ($matches->count()) ? $matches->first()->getAccount() : null;
}
在这种情况下我会收到此错误
多对关系的意外不可迭代值
这是为什么呢?有没有办法让方法保持
getEmail()
?
我正在使用 API Platform 3.2.10 和 symfony 6.4.1
完全错误:
{
"@id": "/errors/400",
"@type": "hydra:Error",
"title": "An error occurred",
"detail": "Unexpected non-iterable value for to-many relation.",
"status": 400,
"type": "/errors/400",
"trace": [
{
"file": "vendor/symfony/serializer/Normalizer/AbstractObjectNormalizer.php",
"line": 192,
"function": "getAttributeValue",
"class": "ApiPlatform\\Serializer\\AbstractItemNormalizer",
"type": "->"
},
{
"file": "vendor/api-platform/core/src/Serializer/AbstractItemNormalizer.php",
"line": 171,
"function": "normalize",
"class": "Symfony\\Component\\Serializer\\Normalizer\\AbstractObjectNormalizer",
"type": "->"
},
{
"file": "vendor/api-platform/core/src/JsonLd/Serializer/ItemNormalizer.php",
"line": 111,
"function": "normalize",
"class": "ApiPlatform\\Serializer\\AbstractItemNormalizer",
"type": "->"
},
{
"file": "vendor/symfony/serializer/Debug/TraceableNormalizer.php",
"line": 58,
"function": "normalize",
"class": "ApiPlatform\\JsonLd\\Serializer\\ItemNormalizer",
"type": "->"
},
{
"file": "vendor/symfony/serializer/Serializer.php",
"line": 159,
"function": "normalize",
"class": "Symfony\\Component\\Serializer\\Debug\\TraceableNormalizer",
"type": "->"
},
{
"file": "vendor/api-platform/core/src/Hydra/Serializer/CollectionNormalizer.php",
"line": 91,
"function": "normalize",
"class": "Symfony\\Component\\Serializer\\Serializer",
"type": "->"
},
{
"file": "vendor/api-platform/core/src/Serializer/AbstractCollectionNormalizer.php",
"line": 106,
"function": "getItemsData",
"class": "ApiPlatform\\Hydra\\Serializer\\CollectionNormalizer",
"type": "->"
},
{
"file": "vendor/api-platform/core/src/Hydra/Serializer/PartialCollectionViewNormalizer.php",
"line": 50,
"function": "normalize",
"class": "ApiPlatform\\Serializer\\AbstractCollectionNormalizer",
"type": "->"
},
{
"file": "vendor/api-platform/core/src/Hydra/Serializer/CollectionFiltersNormalizer.php",
"line": 91,
"function": "normalize",
"class": "ApiPlatform\\Hydra\\Serializer\\PartialCollectionViewNormalizer",
"type": "->"
},
{
"file": "vendor/symfony/serializer/Debug/TraceableNormalizer.php",
"line": 58,
"function": "normalize",
"class": "ApiPlatform\\Hydra\\Serializer\\CollectionFiltersNormalizer",
"type": "->"
},
{
"file": "vendor/symfony/serializer/Serializer.php",
"line": 159,
"function": "normalize",
"class": "Symfony\\Component\\Serializer\\Debug\\TraceableNormalizer",
"type": "->"
},
{
"file": "vendor/symfony/serializer/Serializer.php",
"line": 138,
"function": "normalize",
"class": "Symfony\\Component\\Serializer\\Serializer",
"type": "->"
},
{
"file": "vendor/symfony/serializer/Debug/TraceableSerializer.php",
"line": 47,
"function": "serialize",
"class": "Symfony\\Component\\Serializer\\Serializer",
"type": "->"
},
{
"file": "vendor/api-platform/core/src/State/Processor/SerializeProcessor.php",
"line": 65,
"function": "serialize",
"class": "Symfony\\Component\\Serializer\\Debug\\TraceableSerializer",
"type": "->"
},
{
"file": "vendor/api-platform/core/src/State/Processor/WriteProcessor.php",
"line": 42,
"function": "process",
"class": "ApiPlatform\\State\\Processor\\SerializeProcessor",
"type": "->"
},
{
"file": "vendor/api-platform/core/src/Symfony/Controller/MainController.php",
"line": 111,
"function": "process",
"class": "ApiPlatform\\State\\Processor\\WriteProcessor",
"type": "->"
},
{
"file": "vendor/symfony/http-kernel/HttpKernel.php",
"line": 181,
"function": "__invoke",
"class": "ApiPlatform\\Symfony\\Controller\\MainController",
"type": "->"
},
{
"file": "vendor/symfony/http-kernel/HttpKernel.php",
"line": 76,
"function": "handleRaw",
"class": "Symfony\\Component\\HttpKernel\\HttpKernel",
"type": "->"
},
{
"file": "vendor/symfony/http-kernel/Kernel.php",
"line": 197,
"function": "handle",
"class": "Symfony\\Component\\HttpKernel\\HttpKernel",
"type": "->"
},
{
"file": "vendor/symfony/runtime/Runner/Symfony/HttpKernelRunner.php",
"line": 35,
"function": "handle",
"class": "Symfony\\Component\\HttpKernel\\Kernel",
"type": "->"
},
{
"file": "vendor/autoload_runtime.php",
"line": 29,
"function": "run",
"class": "Symfony\\Component\\Runtime\\Runner\\Symfony\\HttpKernelRunner",
"type": "->"
},
{
"file": "public/index.php",
"line": 5,
"function": "require_once"
}
],
"hydra:title": "An error occurred",
"hydra:description": "Unexpected non-iterable value for to-many relation."
}
可能是因为 symfony 序列化器在规范化过程中将 getEmail 确定为 emails 属性的访问器,从而导致类型不匹配,因为 getEmail 返回单个对象,而 emails 是一个集合。
为了避免这些“晚期”错误,您可以通过向每个属性、方法参数和返回添加严格类型来改进代码。
它仍然会失败,但会给你更容易理解的错误消息。
<?php
namespace App\Entity;
use ApiPlatform\Metadata\ApiResource;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\Common\Collections\Criteria;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Serializer\Annotation\Groups;
#[ApiResource(
normalizationContext: ["groups" => ["contact", "contact_read"]],
denormalizationContext: ["groups" => ["contact", "contact_write"]]
)]
#[ORM\Entity]
class Contact
{
// ...
/**
* @var Collection|Email[]
*/
#[ORM\OneToMany(targetEntity: Email::class, mappedBy: "contact")]
#[Groups(["contact"])]
private Collection $emails;
// ...
public function __construct()
{
$this->emails = new ArrayCollection();
}
// ...
/**
* @return Collection|Email[]
*/
public function getEmails(): Collection
{
return $this->emails;
}
// ...
#[Groups(["contact"])]
public function getEmail(): ?Email
{
$criteria = Criteria::create()->where(Criteria::expr()->eq("is_primary", true));
$matches = $this->emails->matching($criteria);
return ($matches->count()) ? $matches->first() : null;
}
}