【问题标题】:Symfony2 data transformer string to entity (reverseTransform)Symfony2 数据转换器字符串到实体(reverseTransform)
【发布时间】:2018-01-13 07:10:33
【问题描述】:

我对 Symfony 很陌生,希望有人可以帮助我。我有一个名为 Material 的实体和一个名为 MaterialKeyword 的关联实体,它们基本上是标签。我在表单的文本字段中将关键字逗号分隔为字符串。我创建了一个数据转换器来做到这一点。从数据库中拉取关键字并显示它们是没有问题的,但是当我想向数据库提交现有的或新的关键字时,reversTransform 函数会出现问题。

材质类(MaterialKeyword):

/**
 * @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 代码。我认为您不需要所有 Material 类?

标签: symfony symfony-2.8


【解决方案1】:

TL;DR; 您的 reverseTransform 函数应返回一个包含零或 n 的数组 MaterialKeyword

它不应该返回单个MaterialKeyword 对象,因为MaterialKeyord[] --> string 的反向转换不是string --> MaterialKeyword,而是string --> MaterialKeyword[]

考虑到这一点,您认为 ArrayCollection 异常是有道理的,因为它正在尝试执行 new ArrayCollection(/** Single MaterialKeyword object */) 而不是 new ArrayCollection(/** Array of MaterialKeyword objects */)

【讨论】:

  • 正在添加 $result = new ArrayCollection();并返回带有 MaterialKeyword 对象数组的 $result 是否正确?因为它失败并出现错误““AppBundle\Entity\MaterialKeyword”类型的预期参数,给定“数组””
  • @Gildas.我该怎么做,你有例子吗?
【解决方案2】:

根据您所说的,我假设 MaterialMaterialKeyword 通过多对多关联连接,在这种情况下,每个 Material 都有一个 arrayMaterialKeyword 对象关联到它。

这意味着您的数据转换器也应该使用数组,但您只使用单个对象。

具体来说,reverseTransform 应该返回一组 MaterialKeyword 对象,而您只返回一个(循环中处理的最后一个)。

另一个问题是您的方法每次都会创建新对象,即使 $repository->findBy(...) 已经返回了 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;
}

【讨论】:

  • !$keywords === true 应该返回一个空数组而不是空 IMO 的情况。 Doctrine ArrayCollection 不喜欢将 null 作为 ctor 参数进行实例化:github.com/doctrine/collections/blob/master/lib/Doctrine/Common/…
  • 我试过你的代码,但没有运气。出现错误:给定“AppBundle\Entity\MaterialKeyword”、“array”类型的预期参数
【解决方案3】:

@Hanzi 让我走上了正确的道路。它必须是 MaterialKeywords 对象的数组。

这是我在 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;

    }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-04-03
    • 2013-06-23
    • 1970-01-01
    • 2023-02-07
    • 2014-07-20
    • 1970-01-01
    • 1970-01-01
    • 2012-09-24
    相关资源
    最近更新 更多