2015-02-27 6 views
0

Мы сталкиваемся с небольшим запахом кода с symfony и нашими формами. Это не проблема сама по себе, но заставляет меня задаться вопросом, можем ли мы достичь наших целей любым другим способом.Symfony, формы и многие к одному

Для простоты позвольте мне вкратце объяснить установку: пусть «Продукт» представляет собой объект, который представляет продукт в базе данных, предназначенный для продажи в интернет-магазине. Поскольку в интернет-магазине предусмотрено несколько языков, каждый отдельный бит информации, который может быть связан с языком, находится в сущности «Product_descriptions», которая связана с многопользовательским способом с «Продуктом». Наконец, мы разработали «Язык» сущность, представляя каждый язык пользователь может увидеть магазин в

Как вы можете себе представить, код довольно стандартный материал:.

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. В той же форме мы хотели бы иметь возможность устанавливать всю информацию о продукте, а также информацию для всех возможных языков. Запах приходит, когда нам нужно передать все возможные «Язык» в тип формы, проверить, существует ли «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. 
} 

Это работает, но мне кажется, что это не «Symfony» путь делать вещи. Как вы это сделаете? Вы нашли более элегантный подход ?.

Большое спасибо.

ответ

1

Я думаю, вы должны пересмотреть то, как вы перевести сущности ...

Существующий способ заключается в использовании 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(); 

(теперь статья имеет немецкий перевод)

+0

я мог бы обсудить это с командой. Другой слой абстракции может помочь, особенно потому, что реальный проект имеет гораздо больше переводимых объектов. Как насчет графического интерфейса бэкэнда ?. Я полагаю, что связка поможет нам? –

+0

Да, комплект имеет хорошую документацию. Просто добавьте поле «locale» в вашей форме сущности, чтобы выбрать язык, после отправки этого значения в «$ article-> setTranslatableLocale ($ yourvalue). Работа выполнена. – pbenard

+0

Хорошо. Будет читать на нем и показывать его команде в понедельник, когда я снова в городе. –

Смежные вопросы