繁体   English   中英

Symfony,形式和多对一

[英]Symfony, forms and many to one

我们遇到了带有symfony和表单的小代码设计问题。 这本身不是问题,但是让我怀疑我们是否可以通过其他方式实现目标。

为了简单起见,让我简要地解释一下设置:让“产品”是代表数据库中产品的实体,该产品打算在在线商店中出售。 由于在线商店设计为具有多种语言,因此可能与该语言相关的每一点信息都在实体“ Product_descriptions”中,该实体以manyToOne方式与“ Product”相关。 最后,我们设计了一个“语言”实体,代表用户可以在其中看到商店的每种语言。

可以想象,代码是非常标准的东西:

class Language
{
    private $language_id;
    private $language_name;
    private $language_code;

    //Some other stuff.
};

class Product
{
    private $product_id;
    private $product_reference;
    private $product_weight;

    private $product_descriptions; //As an arrayCollection of "Product_description" objects.

    //Some other stuff.
};

class Product_description
{
    private $product_description_id;
    private $product_name;
    private $product_long_description;
    private $product_short_description;

    private $product;   //A reference to the Product itself.
    private $language;  //A reference to the language this is meant to be seen in.
};

好的,现在针对问题本身。 如预期的那样,该安装程序运行良好。 气味存在于后端。

为了创建新产品,我们设计了一个symfony表格Type。 我们希望以相同的形式设置所有产品信息以及每种可能的语言的信息。 当我们需要将所有可能的“ Language”输入表单类型时,会闻到气味,检查“ Language”和“ Product”是否存在“ Product_description”,并显示空白文本字段(如果不存在)或填充字段...我们的解决方案要求将所有语言的存储库注入表单。 让我向您展示它的运行方式(请考虑到这不是真正的代码...可能缺少某些东西):

class ProductType extends AbstractType
{
    private $language_repo;

    public function __construct($r)
    {
        $this->language_repo=$r;
    }

    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder->add('product_name', 'text')
            ->add('product_code', 'text');

        $product=$builder->getData();

        //We retrieve all languages here, to check if an entry for that 
        //language exists and show its data.

        $languages=$this->language_repo->findAll();
        foreach($languages as $key => &$lan)
        {
            //Here we look for existing data... This will return null if there's none.
            $product_description=$product->get_description_for_language($lan);

            $default_name=$product_description ? $product_description->getProductName() : '';
            $default_long=$product_description ? $product_description->getProductLongDescription() : '';
            $default_short=$product_description ? $product_description->getProductShortDescription() : '';

            //Here we manually create the name_#language_id# form data... That we will retrieve later.
            $builder->add('name_'.$lan->getLanguageId(), 'text', array(
                    'label' => 'Name for '.$lan->getName(), 
                    'mapped' => false, 
                    'data' => $default_name))
                ->add('long_'.$lan->getLanguageId(), 'text', array(
                    'label' => 'Name for '.$lan->getName(), 
                    'mapped' => false, 
                    'data' => $default_long))
                ->add('short_'.$lan->getLanguageId(), 'text', array(
                    'label' => 'Name for '.$lan->getName(), 
                    'mapped' => false, 
                    'data' => $default_short));
        }

        $builder->add('save', 'submit', array('label' => 'Save data'));
    }

    //And some other stuff here.
}

如您所见,我们正在手动设置一些稍后在控制器中需要检索的数据键。 设置当然可以。 任何新语言都会产生一个空的表单字段。 任何现有语言都会显示相关信息。

现在对于控制器而言,这甚至变得更加混乱...当我们提交表单时,我们将像这样进行:

private function process_form_data(Form &$f, Product &$item, Request &$request)
{
    //Find all languages...
    $em=$this->getDoctrine()->getManager();
    $languages=$em->getRepository("MyBundle:Language")->findAll();

    //Get submitted data for that language..
    foreach($languages as $key => &$lan)
    {
        $name_language=$f->get('name_'.$lan->getLanguageId())->getData();
        $long_language=$f->get('long_'.$lan->getLanguageId())->getData();
        $short_language=$f->get('short_'.$lan->getLanguageId())->getData();

        //Check if the language entry exists... Create it, if it doesn't. Feed the data.            
        $product_description=$product->get_description_for_language($lan);

        if(!$product_description)
        {
            $product_description=new Product_description();
            $product_description->setLanguage($lan);
            $product_description->setProduct($product);
        }

        $product_description->setName($name_language);
        $product_description->setLongDescription($long_language);
        $product_description->setShortDescription($short_language);

        $em->persist($product_description);
    }

    //Do the product stuff, persist, flush, generate a redirect...Not shown.
}

它有效,但是在我看来,这不是“交响乐”的做事方式。 你会怎么做? 您是否找到了更优雅的方法?

非常感谢。

我认为您应该重新审视翻译实体的方式...

现有的方法是使用DoctrineExtensionBundle ,可精确translatable为...

您可以在这里找到更多信息

https://github.com/Atlantic18/DoctrineExtensions/blob/master/doc/translatable.md

这是摘录,看它如何工作:

<?php
// first load the article
$article = $em->find('Entity\Article', 1 /*article id*/);
$article->setTitle('my title in de');
$article->setContent('my content in de');
$article->setTranslatableLocale('de_de'); // change locale
$em->persist($article);
$em->flush();

(现在这篇文章有德语翻译)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM