ZF2 和 Doctrine 2:翻译实体形式
ZF2 and Doctrine 2: Translation entity form
我需要为 Doctrine 可翻译实体创建 ZF2 表单(我使用 https://github.com/Atlantic18/DoctrineExtensions 可翻译扩展),它应该为每种可用语言的实体的所有可翻译属性(列)提供字段。
到目前为止,我有以下内容:
1) 文章实体
namespace TestModule\Entity;
use Doctrine\Common\Collections\ArrayCollection;
/**
* @Doctrine\ORM\Mapping\Entity(repositoryClass="TestModule\Entity\ArticleRepository")
* @Doctrine\ORM\Mapping\Table(name="test_module_articles")
* @Gedmo\Mapping\Annotation\TranslationEntity(class="TestModule\Entity\ArticleTranslation")
*/
class Article
{
/**
* @var int Auto-Incremented Primary Key
*
* @Doctrine\ORM\Mapping\Id
* @Doctrine\ORM\Mapping\Column(type="integer")
* @Doctrine\ORM\Mapping\GeneratedValue
*/
protected $id;
/**
* @Doctrine\ORM\Mapping\Column(type="string")
* @Gedmo\Mapping\Annotation\Translatable
*/
protected $name;
/**
* @Doctrine\ORM\Mapping\Column(type="text", length=65535)
* @Gedmo\Mapping\Annotation\Translatable
*/
protected $description;
/**
* @Gedmo\Mapping\Annotation\Locale
* Used locale to override Translation listener`s locale
* this is not a mapped field of entity metadata, just a simple property
* and it is not necessary because globally locale can be set in listener
*/
private $locale;
/**
* @Doctrine\ORM\Mapping\OneToMany(
* targetEntity="TestModule\Entity\ArticleTranslation",
* mappedBy="object",
* cascade={"persist", "remove"}
* )
*/
private $translations;
public function __construct()
{
$this->translations = new ArrayCollection();
}
public function getTranslations()
{
return $this->translations;
}
public function addTranslation(\TestModule\Entity\ArticleTranslation $t)
{
if (!$this->translations->contains($t)) {
$this->translations[] = $t;
$t->setObject($this);
}
}
public function addTranslations($translations)
{
foreach ($translations as $translation) {
$this->addTranslation($translation);
}
}
public function removeTranslations($translations)
{
foreach ($translations as $translation) {
$this->translations->removeElement($translation);
$translation->setObject(null);
}
}
public function setTranslatableLocale($locale)
{
$this->locale = $locale;
}
}
2) 文章翻译实体
namespace TestModule\Entity;
use Gedmo\Translatable\Entity\MappedSuperclass\AbstractPersonalTranslation;
/**
* @Doctrine\ORM\Mapping\Entity
* @Doctrine\ORM\Mapping\Table(name="test_module_articles_translations",
* uniqueConstraints={@Doctrine\ORM\Mapping\UniqueConstraint(name="lookup_unique_idx", columns={
* "locale", "object_id", "field"
* })}
* )
*/
class ArticleTranslation extends AbstractPersonalTranslation
{
/**
* Convinient constructor
*
* @param string $locale
* @param string $field
* @param string $value
*/
public function __construct($locale, $field, $value)
{
$this->setLocale($locale);
$this->setField($field);
$this->setContent($value);
}
/**
* @Doctrine\ORM\Mapping\ManyToOne(targetEntity="TestModule\Entity\Article", inversedBy="translations")
* @Doctrine\ORM\Mapping\JoinColumn(name="object_id", referencedColumnName="id", onDelete="CASCADE")
*/
protected $object;
}
3) 形式
namespace TestModule\Form;
use Zend\Form\Form;
use Doctrine\ORM\EntityManager;
use DoctrineModule\Stdlib\Hydrator\DoctrineObject as DoctrineHydrator;
use TestModule\Form\ArticleTranslationsFieldset;
use TestModule\Entity\ArticleTranslation;
class ArticleForm extends Form
{
protected $entityManager;
public function __construct(EntityManager $entityManager,$name = null)
{
parent::__construct($name);
$this->entityManager = $entityManager;
$hydrator = new DoctrineHydrator($this->entityManager, 'TestModule\Entity\Article');
$this->setAttribute('method', 'post')
->setHydrator($hydrator)
//->setInputFilter($inputFilter)
;
$this->add(array(
'name' => 'id',
'type' => 'Hidden',
));
$articleFieldset = new ArticleTranslationsFieldset($entityManager);
$fieldsetHydrator = new DoctrineHydrator($entityManager, 'TestModule\Entity\ArticleTranslation');
$articleFieldset->setHydrator($fieldsetHydrator)->setObject(new ArticleTranslation('en','name',''));
$this->add(array(
'type' => 'Zend\Form\Element\Collection',
'name' => 'translations',
'allow_empty' => true,
'options' => array(
'label' => '',
'count' => 0,
'allow_add' => true,
'allow_remove' => true,
'target_element' => $articleFieldset,
),
));
$this->add(array(
'name' => 'submit',
'attributes' => array(
'type' => 'submit',
'value' => 'Submit'
),
));
}
}
4) 翻译字段集:
namespace TestModule\Form;
use Zend\Form\Fieldset;
class ArticleTranslationsFieldset extends Fieldset
{
public function __construct()
{
parent::__construct('translations');
$this->add(array(
'name' => 'locale',
'type' => 'Hidden',
));
$this->add(array(
'name' => 'field',
'type' => 'Hidden',
));
$this->add(array(
'name' => 'content',
'type' => 'Zend\Form\Element\Text',
'options' => array(
'label' => _(''),
),
'attributes' => array(
'type' => 'text',
),
));
}
}
使用此设置,我可以保存每种语言的名称和描述属性,但我无法管理内容字段类型 - 名称和描述都是文本元素,无法设置正确的字段标签。我也无法按语言对元素进行分组,以便呈现给用户的表单井井有条。
对于如何解决这个问题,您还有其他建议吗?
我想要实现的是这样的:
我找不到问题中使用的可翻译原则扩展的解决方案。所以我搜索了另一个,最后我最终使用了 Prezent 扩展(https://github.com/Prezent/doctrine-translatable)。
有了这个扩展,翻译实体包含可翻译的字段,这使得翻译实体与翻译字段集的映射变得容易。每个翻译实体都有一个语言环境 属性,我将其映射到字段集中的一个隐藏字段,并使用它以所需方式呈现表单。
我需要为 Doctrine 可翻译实体创建 ZF2 表单(我使用 https://github.com/Atlantic18/DoctrineExtensions 可翻译扩展),它应该为每种可用语言的实体的所有可翻译属性(列)提供字段。 到目前为止,我有以下内容:
1) 文章实体
namespace TestModule\Entity;
use Doctrine\Common\Collections\ArrayCollection;
/**
* @Doctrine\ORM\Mapping\Entity(repositoryClass="TestModule\Entity\ArticleRepository")
* @Doctrine\ORM\Mapping\Table(name="test_module_articles")
* @Gedmo\Mapping\Annotation\TranslationEntity(class="TestModule\Entity\ArticleTranslation")
*/
class Article
{
/**
* @var int Auto-Incremented Primary Key
*
* @Doctrine\ORM\Mapping\Id
* @Doctrine\ORM\Mapping\Column(type="integer")
* @Doctrine\ORM\Mapping\GeneratedValue
*/
protected $id;
/**
* @Doctrine\ORM\Mapping\Column(type="string")
* @Gedmo\Mapping\Annotation\Translatable
*/
protected $name;
/**
* @Doctrine\ORM\Mapping\Column(type="text", length=65535)
* @Gedmo\Mapping\Annotation\Translatable
*/
protected $description;
/**
* @Gedmo\Mapping\Annotation\Locale
* Used locale to override Translation listener`s locale
* this is not a mapped field of entity metadata, just a simple property
* and it is not necessary because globally locale can be set in listener
*/
private $locale;
/**
* @Doctrine\ORM\Mapping\OneToMany(
* targetEntity="TestModule\Entity\ArticleTranslation",
* mappedBy="object",
* cascade={"persist", "remove"}
* )
*/
private $translations;
public function __construct()
{
$this->translations = new ArrayCollection();
}
public function getTranslations()
{
return $this->translations;
}
public function addTranslation(\TestModule\Entity\ArticleTranslation $t)
{
if (!$this->translations->contains($t)) {
$this->translations[] = $t;
$t->setObject($this);
}
}
public function addTranslations($translations)
{
foreach ($translations as $translation) {
$this->addTranslation($translation);
}
}
public function removeTranslations($translations)
{
foreach ($translations as $translation) {
$this->translations->removeElement($translation);
$translation->setObject(null);
}
}
public function setTranslatableLocale($locale)
{
$this->locale = $locale;
}
}
2) 文章翻译实体
namespace TestModule\Entity;
use Gedmo\Translatable\Entity\MappedSuperclass\AbstractPersonalTranslation;
/**
* @Doctrine\ORM\Mapping\Entity
* @Doctrine\ORM\Mapping\Table(name="test_module_articles_translations",
* uniqueConstraints={@Doctrine\ORM\Mapping\UniqueConstraint(name="lookup_unique_idx", columns={
* "locale", "object_id", "field"
* })}
* )
*/
class ArticleTranslation extends AbstractPersonalTranslation
{
/**
* Convinient constructor
*
* @param string $locale
* @param string $field
* @param string $value
*/
public function __construct($locale, $field, $value)
{
$this->setLocale($locale);
$this->setField($field);
$this->setContent($value);
}
/**
* @Doctrine\ORM\Mapping\ManyToOne(targetEntity="TestModule\Entity\Article", inversedBy="translations")
* @Doctrine\ORM\Mapping\JoinColumn(name="object_id", referencedColumnName="id", onDelete="CASCADE")
*/
protected $object;
}
3) 形式
namespace TestModule\Form;
use Zend\Form\Form;
use Doctrine\ORM\EntityManager;
use DoctrineModule\Stdlib\Hydrator\DoctrineObject as DoctrineHydrator;
use TestModule\Form\ArticleTranslationsFieldset;
use TestModule\Entity\ArticleTranslation;
class ArticleForm extends Form
{
protected $entityManager;
public function __construct(EntityManager $entityManager,$name = null)
{
parent::__construct($name);
$this->entityManager = $entityManager;
$hydrator = new DoctrineHydrator($this->entityManager, 'TestModule\Entity\Article');
$this->setAttribute('method', 'post')
->setHydrator($hydrator)
//->setInputFilter($inputFilter)
;
$this->add(array(
'name' => 'id',
'type' => 'Hidden',
));
$articleFieldset = new ArticleTranslationsFieldset($entityManager);
$fieldsetHydrator = new DoctrineHydrator($entityManager, 'TestModule\Entity\ArticleTranslation');
$articleFieldset->setHydrator($fieldsetHydrator)->setObject(new ArticleTranslation('en','name',''));
$this->add(array(
'type' => 'Zend\Form\Element\Collection',
'name' => 'translations',
'allow_empty' => true,
'options' => array(
'label' => '',
'count' => 0,
'allow_add' => true,
'allow_remove' => true,
'target_element' => $articleFieldset,
),
));
$this->add(array(
'name' => 'submit',
'attributes' => array(
'type' => 'submit',
'value' => 'Submit'
),
));
}
}
4) 翻译字段集:
namespace TestModule\Form;
use Zend\Form\Fieldset;
class ArticleTranslationsFieldset extends Fieldset
{
public function __construct()
{
parent::__construct('translations');
$this->add(array(
'name' => 'locale',
'type' => 'Hidden',
));
$this->add(array(
'name' => 'field',
'type' => 'Hidden',
));
$this->add(array(
'name' => 'content',
'type' => 'Zend\Form\Element\Text',
'options' => array(
'label' => _(''),
),
'attributes' => array(
'type' => 'text',
),
));
}
}
使用此设置,我可以保存每种语言的名称和描述属性,但我无法管理内容字段类型 - 名称和描述都是文本元素,无法设置正确的字段标签。我也无法按语言对元素进行分组,以便呈现给用户的表单井井有条。
对于如何解决这个问题,您还有其他建议吗?
我想要实现的是这样的:
我找不到问题中使用的可翻译原则扩展的解决方案。所以我搜索了另一个,最后我最终使用了 Prezent 扩展(https://github.com/Prezent/doctrine-translatable)。
有了这个扩展,翻译实体包含可翻译的字段,这使得翻译实体与翻译字段集的映射变得容易。每个翻译实体都有一个语言环境 属性,我将其映射到字段集中的一个隐藏字段,并使用它以所需方式呈现表单。