如何在symfony2实体中动态添加字段


How can I add field on the fly in symfony2 entity

我想知道是否有一种方法可以向Symfony2上的任何实体动态添加字段。我在大互联网上搜索,什么也没找到。当我说"一种方式"时,我的意思是,如果存在具有该行为的条令扩展、实现它的捆绑包、设计模式等。

我的想法类似于教义扩展的可翻译行为。假设我有一个Address实体,所以我想动态添加一些属性,比如街道、数字、十字路口等,但一开始我不知道可能存在哪些字段。

我把一些东西看作两个实体:Address和AddressFieldValues。Address将具有特定的属性,如id、与其他classess关系的外键,并将用于注入动态属性(字段值的集合)。AddressFieldValue将具有Address的reals字段值,具有以下属性:id、Address_id、field_name、field_value。

因此,实体地址可能是这样的:

/**
 * Address
 *
 * @ORM'Entity(repositoryClass="AddressRepository")
 * @ORM'Table(name="address")
 */
class Address
{
    /**
    * @var integer
    *
    * @ORM'Column(name="id", type="integer")
    * @ORM'Id
    * @ORM'GeneratedValue(strategy="AUTO")
    */
    private $id;

    /**
     * @ORM'OneToMany(
     *   targetEntity="AddressFieldValues",
     *   mappedBy="object",
     *   cascade={"persist", "remove"}
     * )
     */
    private $field_value;
    public function __construct()
    {
        $this->field_value = new ArrayCollection();
    }
    public function getFieldValue()
    {
        return $this->field_value;
    }
    public function addFieldValue(AddressFieldValues $fv)
    {
        if (!$this->field_value->contains($fv)) {
            $this->field_value[] = $fv;
            $fv->setObject($this);
        }
    }
    public function getId()
    {
        return $this->id;
    }
}

和AddressFieldValues实体可以是这样的:

/**
 * @ORM'Entity
 * @ORM'Table(name="address_field_values",
 *     uniqueConstraints={@ORM'UniqueConstraint(name="lookup_unique_idx", columns={
 *         "object_id", "field"
 *     })}
 * )
 */
class AddressFieldValues
{
    /**
     * @var integer $id
     *
     * @ORM'Column(type="integer")
     * @ORM'Id
     * @ORM'GeneratedValue
     */
    protected $id;
    /**
     * @var string $field
     *
     * @ORM'Column(type="string", length=32)
     */
    protected $field;
    /**
     * @ORM'ManyToOne(targetEntity="Address", inversedBy="field_value")
     * @ORM'JoinColumn(name="object_id", referencedColumnName="id", onDelete="CASCADE")
     */
    protected $object;
    /**
     * @var string $content
     *
     * @ORM'Column(type="text", nullable=true)
     */
    protected $content;
    /**
     * Convenient constructor
     *
     * @param string $field
     * @param string $value
     */
    public function __construct($field, $value)
    {
        $this->setField($field);
        $this->setContent($value);
    }        
    /**
     * Get id
     *
     * @return integer $id
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     * Set field
     *
     * @param string $field
     */
    public function setField($field)
    {
        $this->field = $field;
        return $this;
    }
    /**
     * Get field
     *
     * @return string $field
     */
    public function getField()
    {
        return $this->field;
    }
    /**
     * Set object related
     *
     * @param string $object
     */
    public function setObject($object)
    {
        $this->object = $object;
        return $this;
    }
    /**
     * Get related object
     *
     * @return object $object
     */
    public function getObject()
    {
        return $this->object;
    }
    /**
     * Set content
     *
     * @param string $content
     */
    public function setContent($content)
    {
        $this->content = $content;
        return $this;
    }
    /**
     * Get content
     *
     * @return string $content
     */
    public function getContent()
    {
        return $this->content;
    }        
}

所以,如果表上有以下值:address_field_values

  id | object |      field      |    content
  1  |   1    |  street         | 1st Ave
  2  |   1    |  number         | 12345
  3  |   1    |  intersections  | 2sd Ave and 4th Ave
  4  |   2    |  street         | 1st Ave
  5  |   2    |  number         | 12347
  6  |   2    |  intersections  | 2sd Ave and 4th Ave
  7  |   3    |  street         | 1st Ave
  8  |   3    |  number         | 12349
  9  |   3    |  intersections  | 2sd Ave and 4th Ave

目前,地址表只有以下值:

|  id |
|  1  |
|  2  |
|  3  |

我可以将这些字段值动态地注入到Address对象中,这样做:

// if I need get de Address with id = 2
$addressRepository = $em->getRepository('Address');
$address = $addressRepository->find(2);
sprintf('The address is: "%s", #"%s" between "%s".', $address->getStreet(), $address->getNumber(), $address->getIntersections());
// then it should show: The address is 1st Ave, #12347 between 2sd Ave and 4th Ave.
//
// or if I need add a new Address, do something like this:
$address = new Address();
$address->setStreet('1st Ave');
$address->setNumber('12351');
$address->setIntersections('2sd Ave and 4th Ave');
$em->persist($address);
$em->flush();

然后它保存地址和address_field_value,这些表具有以下值:

// address
|  id |
|  1  |
|  2  |
|  3  | 
|  4  |  
// address_field_values
  id | object |      field      |    content
  1  |   1    |  street         | 1st Ave
  2  |   1    |  number         | 12345
  3  |   1    |  intersections  | 2sd Ave and 4th Ave
  4  |   2    |  street         | 1st Ave
  5  |   2    |  number         | 12347
  6  |   2    |  intersections  | 2sd Ave and 4th Ave
  7  |   3    |  street         | 1st Ave
  8  |   3    |  number         | 12349
  9  |   3    |  intersections  | 2sd Ave and 4th Ave
 10  |   4    |  street         | 1st Ave
 11  |   4    |  number         | 12351
 12  |   4    |  intersections  | 2sd Ave and 4th Ave

那么,有什么想法我该怎么做吗?

记住,在我的业务逻辑中,我有一个要求,那就是我一开始不知道哪些字段可以有地址,所以我需要动态注入字段。我使用Address作为示例,但这种行为可以用于任何实体。

提前感谢

我认为您的请求类似于表单中的集合(Doctrine2文档)。

在文档中,具有name属性的Tags实体的集合链接到Task实体。在您的情况下,实体AddressFieldValue将具有fieldcontent属性,并且AddressFieldValue实体的集合将添加到Address实体中。

因此,通过使用此文档并用Address替换Task,用AddressFieldValue替换Tag,它应该可以工作。