Symfony2 数据转换器字符串到实体(reverseTransform)
Symfony2 data transformer string to entity (reverseTransform)
我是 Symfony 的新手,希望有人能帮助我。我有一个名为 Material 的实体和一个名为 MaterialKeyword 的关联实体,它们基本上是标签。我在表单的文本字段中显示以逗号分隔的字符串形式的关键字。我创建了一个数据转换器来做到这一点。从数据库中提取关键字并显示它们是没有问题的,但是当我想将现有或新的关键字提交到数据库时,我的 reversTransform 函数出现问题。
Material class(Material关键词):
/**
* @Assert\Type(type="AppBundle\Entity\MaterialKeyword")
* @Assert\Valid()
* @ORM\ManyToMany(targetEntity="MaterialKeyword", inversedBy="material")
* @ORM\JoinTable(name="materials_keyword_map",
* joinColumns={@ORM\JoinColumn(name="materialID", referencedColumnName="materialID", nullable=false)},
* inverseJoinColumns={@ORM\JoinColumn(name="keywordID", referencedColumnName="id", nullable=false)})
*/
public $materialkeyword;
/**
* Constructor
*/
public function __construct()
{
$this->MaterialKeyword = new ArrayCollection();
}
/**
* Set materialkeyword
*
* @param array $materialkeyword
*
*/
public function setMaterialkeyword(MaterialKeyword $materialkeyword=null)
{
$this->materialkeyword = $materialkeyword;
}
/**
* Get materialkeyword
*
* @Assert\Type("\array")
* @return array
*/
public function getMaterialkeyword()
{
return $this->materialkeyword;
}
这是我的数据转换器代码:
这部分正在运行:
class MaterialKeywordTransformer implements DataTransformerInterface
{
/**
* @var EntityManagerInterface
*/
private $manager;
public function __construct(ObjectManager $manager)
{
$this->manager = $manager;
}
/**
* Transforms an object (materialkeyword) to a string.
*
* @param MaterialKeyword|null $materialkeyword
* @return string
*/
public function transform($material)
{
$result = array();
if (null === $material) {
return '';
}
foreach ($material as $materialkeyword) {
$result[] = $materialkeyword->getKeyword();
}
return implode(", ", $result);
}
这部分不工作:
/**
* Transforms a string (keyword) to an object (materialkeyword).
*
* @param string $materialkeyword
* @return MaterialKeyword|null
* @throws TransformationFailedException if object (materialkeyword) is not found.
*/
public function reverseTransform($keywords)
{
// no keyword? It's optional, so that's ok
if (!$keywords) {
return;
}
$repository = $this->manager
->getRepository('AppBundle:MaterialKeyword');
$keyword_array = explode(", ", $keywords);
foreach($keyword_array as $keyword){
$materialkeyword = new MaterialKeyword();
$keyword_entry = $repository->findBy(array('keyword' => $keyword));
if(array_key_exists(0, $keyword_entry)){
$keyword_entry_first = $keyword_entry[0];
}else{
$keyword_entry_first = $keyword_entry;
}
if (null === $keyword_entry_first) {
throw new TransformationFailedException(sprintf('There is no "%s" exists',
$keywords
));
}
$materialkeyword->setKeyword($keyword_entry_first);
}
return $materialkeyword;
}
会有几个关键词,请问如何存储。我尝试了 Arrays 和 ArrayCollections (new ArrayCollection()) 但没有成功。
我目前在上面的代码中遇到的错误:
Catchable Fatal Error: Argument 1 passed to Doctrine\Common\Collections\ArrayCollection::__construct() must be of the type array, object given, called in /.../vendor/doctrine/orm/lib/Doctrine/ORM/UnitOfWork.php on line 605 and defined
根据你所说的,我假设 Material
和 MaterialKeyword
由 ManyToMany 关联连接,在这种情况下每个 Material
都有一个 array 个与之关联的 MaterialKeyword
个对象。
这意味着,您的数据转换器也应该使用数组,但您只使用单个对象。
具体来说,reverseTransform
应该 return 一个 MaterialKeyword
对象数组,而你只是 returning 一个(循环中处理的最后一个。)
另一个问题是您的方法每次都创建新对象,即使 $repository->findBy(...)
已经 return 一个 MaterialKeyword
实例。创建一个新对象会导致该条目被复制而不是简单地使用。
所以正确的方法可能是这样的:
public function reverseTransform($keywords)
{
// no keyword? It's optional, so that's ok
if (!$keywords) {
return array();
}
$repository = $this->manager
->getRepository('AppBundle:MaterialKeyword');
$keyword_array = explode(", ", $keywords);
$result_list = array(); // This will contain the MaterialKeyword objects
foreach($keyword_array as $keyword){
$keyword_entry = $repository->findOneBy(array('keyword' => $keyword));
if (null === $keyword_entry) {
throw new TransformationFailedException(sprintf('There is no "%s" exists',
$keyword
));
}
$result_list[] = $keyword_entry;
}
return $result_list;
}
TL;DR;
您的 reverseTransform
函数应该 return 一个包含零或 n MaterialKeyword
.
的数组
不应该return单个MaterialKeyword
对象因为MaterialKeyord[] --> string
的逆向变换不是string --> MaterialKeyword
,而是string --> MaterialKeyword[]
.
考虑到这一点,您的 ArrayCollection 异常学说很有意义,因为它正在尝试 new ArrayCollection(/** Single MaterialKeyword object */)
而不是 new ArrayCollection(/** Array of MaterialKeyword objects */)
。
@Hanzi 让我走上了正确的轨道。它必须是 MaterialKeywords
个对象的数组。
这是我在 class MaterialKeywordTransformer 中的最终工作代码:
/**
* Transforms a string (keyword) to an object (materialkeyword).
*
* @param string $materialkeyword
* @return MaterialKeyword|null
* @throws TransformationFailedException if object (materialkeyword) is not found.
*/
public function reverseTransform($keywords)
{
// keyword are optional, so that's ok
if (!$keywords) {
return;
}
$repository = $this->manager
->getRepository('AppBundle:MaterialKeyword');
$repository_m = $this->manager
->getRepository('AppBundle:Material');
$keyword_array = explode(", ", $keywords);
foreach($keyword_array as $keyword){
$materialkeyword = new MaterialKeyword();
$materialkeyword->setKeyword($keyword);
if($this->opt["data"]->getMaterialID() !== null) {
$materialkeyword->setMaterialID($this->opt["data"]->getMaterialID());
} else {
$material = $repository_m->findOne();
$materialID = $material[0]->getMaterialID();
$materialkeyword->setMaterialID($materialID);
}
$materialkeywords[] = $materialkeyword;
if (null === $keywords) {
throw new TransformationFailedException(sprintf('There is no "%s" exists',
$keywords
));
}
}
return $materialkeywords;
}
我是 Symfony 的新手,希望有人能帮助我。我有一个名为 Material 的实体和一个名为 MaterialKeyword 的关联实体,它们基本上是标签。我在表单的文本字段中显示以逗号分隔的字符串形式的关键字。我创建了一个数据转换器来做到这一点。从数据库中提取关键字并显示它们是没有问题的,但是当我想将现有或新的关键字提交到数据库时,我的 reversTransform 函数出现问题。
Material class(Material关键词):
/**
* @Assert\Type(type="AppBundle\Entity\MaterialKeyword")
* @Assert\Valid()
* @ORM\ManyToMany(targetEntity="MaterialKeyword", inversedBy="material")
* @ORM\JoinTable(name="materials_keyword_map",
* joinColumns={@ORM\JoinColumn(name="materialID", referencedColumnName="materialID", nullable=false)},
* inverseJoinColumns={@ORM\JoinColumn(name="keywordID", referencedColumnName="id", nullable=false)})
*/
public $materialkeyword;
/**
* Constructor
*/
public function __construct()
{
$this->MaterialKeyword = new ArrayCollection();
}
/**
* Set materialkeyword
*
* @param array $materialkeyword
*
*/
public function setMaterialkeyword(MaterialKeyword $materialkeyword=null)
{
$this->materialkeyword = $materialkeyword;
}
/**
* Get materialkeyword
*
* @Assert\Type("\array")
* @return array
*/
public function getMaterialkeyword()
{
return $this->materialkeyword;
}
这是我的数据转换器代码:
这部分正在运行:
class MaterialKeywordTransformer implements DataTransformerInterface
{
/**
* @var EntityManagerInterface
*/
private $manager;
public function __construct(ObjectManager $manager)
{
$this->manager = $manager;
}
/**
* Transforms an object (materialkeyword) to a string.
*
* @param MaterialKeyword|null $materialkeyword
* @return string
*/
public function transform($material)
{
$result = array();
if (null === $material) {
return '';
}
foreach ($material as $materialkeyword) {
$result[] = $materialkeyword->getKeyword();
}
return implode(", ", $result);
}
这部分不工作:
/**
* Transforms a string (keyword) to an object (materialkeyword).
*
* @param string $materialkeyword
* @return MaterialKeyword|null
* @throws TransformationFailedException if object (materialkeyword) is not found.
*/
public function reverseTransform($keywords)
{
// no keyword? It's optional, so that's ok
if (!$keywords) {
return;
}
$repository = $this->manager
->getRepository('AppBundle:MaterialKeyword');
$keyword_array = explode(", ", $keywords);
foreach($keyword_array as $keyword){
$materialkeyword = new MaterialKeyword();
$keyword_entry = $repository->findBy(array('keyword' => $keyword));
if(array_key_exists(0, $keyword_entry)){
$keyword_entry_first = $keyword_entry[0];
}else{
$keyword_entry_first = $keyword_entry;
}
if (null === $keyword_entry_first) {
throw new TransformationFailedException(sprintf('There is no "%s" exists',
$keywords
));
}
$materialkeyword->setKeyword($keyword_entry_first);
}
return $materialkeyword;
}
会有几个关键词,请问如何存储。我尝试了 Arrays 和 ArrayCollections (new ArrayCollection()) 但没有成功。
我目前在上面的代码中遇到的错误:
Catchable Fatal Error: Argument 1 passed to Doctrine\Common\Collections\ArrayCollection::__construct() must be of the type array, object given, called in /.../vendor/doctrine/orm/lib/Doctrine/ORM/UnitOfWork.php on line 605 and defined
根据你所说的,我假设 Material
和 MaterialKeyword
由 ManyToMany 关联连接,在这种情况下每个 Material
都有一个 array 个与之关联的 MaterialKeyword
个对象。
这意味着,您的数据转换器也应该使用数组,但您只使用单个对象。
具体来说,reverseTransform
应该 return 一个 MaterialKeyword
对象数组,而你只是 returning 一个(循环中处理的最后一个。)
另一个问题是您的方法每次都创建新对象,即使 $repository->findBy(...)
已经 return 一个 MaterialKeyword
实例。创建一个新对象会导致该条目被复制而不是简单地使用。
所以正确的方法可能是这样的:
public function reverseTransform($keywords)
{
// no keyword? It's optional, so that's ok
if (!$keywords) {
return array();
}
$repository = $this->manager
->getRepository('AppBundle:MaterialKeyword');
$keyword_array = explode(", ", $keywords);
$result_list = array(); // This will contain the MaterialKeyword objects
foreach($keyword_array as $keyword){
$keyword_entry = $repository->findOneBy(array('keyword' => $keyword));
if (null === $keyword_entry) {
throw new TransformationFailedException(sprintf('There is no "%s" exists',
$keyword
));
}
$result_list[] = $keyword_entry;
}
return $result_list;
}
TL;DR;
您的 reverseTransform
函数应该 return 一个包含零或 n MaterialKeyword
.
不应该return单个MaterialKeyword
对象因为MaterialKeyord[] --> string
的逆向变换不是string --> MaterialKeyword
,而是string --> MaterialKeyword[]
.
考虑到这一点,您的 ArrayCollection 异常学说很有意义,因为它正在尝试 new ArrayCollection(/** Single MaterialKeyword object */)
而不是 new ArrayCollection(/** Array of MaterialKeyword objects */)
。
@Hanzi 让我走上了正确的轨道。它必须是 MaterialKeywords
个对象的数组。
这是我在 class MaterialKeywordTransformer 中的最终工作代码:
/**
* Transforms a string (keyword) to an object (materialkeyword).
*
* @param string $materialkeyword
* @return MaterialKeyword|null
* @throws TransformationFailedException if object (materialkeyword) is not found.
*/
public function reverseTransform($keywords)
{
// keyword are optional, so that's ok
if (!$keywords) {
return;
}
$repository = $this->manager
->getRepository('AppBundle:MaterialKeyword');
$repository_m = $this->manager
->getRepository('AppBundle:Material');
$keyword_array = explode(", ", $keywords);
foreach($keyword_array as $keyword){
$materialkeyword = new MaterialKeyword();
$materialkeyword->setKeyword($keyword);
if($this->opt["data"]->getMaterialID() !== null) {
$materialkeyword->setMaterialID($this->opt["data"]->getMaterialID());
} else {
$material = $repository_m->findOne();
$materialID = $material[0]->getMaterialID();
$materialkeyword->setMaterialID($materialID);
}
$materialkeywords[] = $materialkeyword;
if (null === $keywords) {
throw new TransformationFailedException(sprintf('There is no "%s" exists',
$keywords
));
}
}
return $materialkeywords;
}