Search code examples
phpsymfonydoctrine-ormentitylocale

Two records in database on 1 form


I have an entity Page with fields:

pageID (PK) and tag.

I have an entity PageLocale with fields:

pagelocaleid (PK), description, content, locale, translated and pageID (FK).

My Database Structure:

enter image description here

My entity PageLocale:

<?php

namespace DX\MyBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\HttpFoundation\File\UploadedFile;

/**
 * Pagelocale
 *
 * @ORM\Table(name="pageLocale", indexes={@ORM\Index(name="fk_pageLocale_page1_idx", columns={"pageID"})})
 * @ORM\Entity(repositoryClass="DX\MyBundle\Repository\PagelocaleRepository")
 * @ORM\HasLifecycleCallbacks
 */
class Pagelocale
{
    /**
     * @var string
     *
     * @ORM\Column(name="description", type="text", length=65535, nullable=true)
     */
    private $description;

    /**
     * @var string
     */
    private $descriptionEN;

    /**
     * @var string
     *
     * @ORM\Column(name="content", type="text", length=65535, nullable=true)
     */
    private $content;

    /**
     * @var string
     */
    private $contentEN;

    /**
     * @var string
     *
     * @ORM\Column(name="locale", type="string", length=5, nullable=true)
     */
    private $locale;

    /**
     * @var boolean
     *
     * @ORM\Column(name="translated", type="boolean", nullable=true)
     */
    private $translated;

    /**
     * @var integer
     *
     * @ORM\Column(name="pageLocaleID", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="IDENTITY")
     */
    private $pagelocaleid;

    /**
     * @var \DX\MyBundle\Entity\Page
     *
     * @ORM\ManyToOne(targetEntity="DX\MyBundle\Entity\Page")
     * @ORM\JoinColumns({
     *   @ORM\JoinColumn(name="pageID", referencedColumnName="pageID")
     * })
     */
    private $pageid;

    /**
     * @var string
     */
    private $tag;

    /**
     * Set tag
     *
     * @param string $tag
     * @return Articlelocale
     */
    public function setTag($tag)
    {
        if($this->pageid)
        {
            $this->pageid->setTag($tag);
        }
        else
        {
            $this->tag = $tag;
        }

        return $this;
    }

    /**
     * Get tag
     *
     * @return string
     */
    public function getTag()
    {
        if($this->pageid)
        {
            return $this->pageid->getTag();
        }
        else
        {
            return $this->tag;
        }
    }

    /**
     * Set description
     *
     * @param string $description
     * @return Pagelocale
     */
    public function setDescription($description)
    {
        $this->description = $description;

        return $this;
    }

    /**
     * Get description
     *
     * @return string 
     */
    public function getDescription()
    {
        return $this->description;
    }

    /**
     * Set descriptionEN
     *
     * @param string $descriptionEN
     * @return Pagelocale
     */
    public function setDescriptionEN($descriptionEN)
    {
        $this->descriptionEN = $descriptionEN;

        return $this;
    }

    /**
     * Get descriptionEN
     *
     * @return string
     */
    public function getDescriptionEN()
    {
        return $this->descriptionEN;
    }

    /**
     * Set content
     *
     * @param string $content
     * @return Pagelocale
     */
    public function setContent($content)
    {
        $this->content = $content;

        return $this;
    }

    /**
     * Get content
     *
     * @return string 
     */
    public function getContent()
    {
        return $this->content;
    }


    /**
     * Set contentEN
     *
     * @param string $contentEN
     * @return Pagelocale
     */
    public function setContentEN($contentEN)
    {
        $this->contentEN = $contentEN;

        return $this;
    }

    /**
     * Get contentEN
     *
     * @return string
     */
    public function getContentEN()
    {
        return $this->contentEN;
    }

    /**
     * Set locale
     *
     * @param string $locale
     * @return Pagelocale
     */
    public function setLocale($locale)
    {
        $this->locale = $locale;

        return $this;
    }

    /**
     * Get locale
     *
     * @return string 
     */
    public function getLocale()
    {
        return $this->locale;
    }

    /**
     * Set translated
     *
     * @param boolean $translated
     * @return Pagelocale
     */
    public function setTranslated($translated)
    {
        $this->translated = $translated;

        return $this;
    }

    /**
     * Get translated
     *
     * @return boolean 
     */
    public function getTranslated()
    {
        return $this->translated;
    }

    /**
     * Get pagelocaleid
     *
     * @return integer 
     */
    public function getPagelocaleid()
    {
        return $this->pagelocaleid;
    }

    /**
     * Set pageid
     *
     * @param \DX\MyBundle\Entity\Page $pageid
     * @return Pagelocale
     */
    public function setPageid(\DX\MyBundle\Entity\Page $pageid = null)
    {
        $this->pageid = $pageid;

        return $this;
    }
}

I'm using the Sonata Admin Bundle but that doesn't really matter in this case.

As you can see in my entity I've manually added contentEN and descriptionEN because I want the content & description in 2 languages.

And I want to be able to do this in one form and not in 2 steps (create for each language content).

Now I have in my form:

$formMapper
    ->add('tag', 'text', array('label' => 'Tag'))
    ->add('description', 'text', array('label' => 'Beschrijving'))
    ->add('descriptionEN', 'text', array('label' => 'Beschrijving Engels'))
    ->add('content', 'textarea', array('label' => 'Tekst', 'attr' => array('class' => 'ckeditor'), 'help' =>
        'My help text.'))
    ->add('contentEN', 'textarea', array('label' => 'Tekst Engels', 'attr' => array('class' => 'ckeditor'), 'help' =>
        'My help text.'))
;

I can create 2 different entities and set the locale, that's no problem. But when I want to edit them the contentEN & descriptionEN are logically not filled in. How can I make sure I get the description and content where locale = .. ?

I know the contentEN & descriptionEN are not the way to do this. But I just wanted to clarify the problem.


Solution

  • If you want to retrieve some specific content based on the locale, you need to create an array where you set your fields ordered by locale and create a query that uses this array.

    You could do it this way :

    class PageLocaleManager 
    {
        public function getParametersLocale()
        {
            // retrieve the current locale.
            $locale = $this->get('request')->getLocale();
            // set the fields you want retrieve based on the locale, you have to set an alias before the name for the query.
            $parameters = array(
                'fr' => array('pl.description', 'pl.content'),
                'en' => array('pl.descriptionEN', 'pl.contentEN')
            );
            // if the locale is set return the parameters related to it, else return the default parameters (in this case default = fr)
            return (isset($parameters[$locale]) ? $parameters[$locale] : $parameters['fr'];
        }
    }
    
    class PageLocaleRepository
    {
        public function findLocalePageById($parameters, $pageId)
        {
            return $this->createQueryBuilder('pl')
                ->select($parameters)
                ->where('pl.page = :pageId')
                ->setParameter('pageId', $id)
                ->getQuery()
                ->getResult();
        }
    }
    

    Then when you want to retrieve the page content for a specific locale you have to do :

    $pageId = 1;
    $parameters = $this->get('page_locale.manager')->getParametersLocale();
    $pageLocaleEntity = $this->getDoctrine()->getRepository('TestBundle:PageLocale')->findLocalePageById($parameters, $pageId);
    

    Also you shouldn't use this schema in your project in my opinion, if you want to add more languages, you will have to duplicate fields.

    Update

    You have to use events prePersist / preUpdate if you want to create / update 2 entity from the data of the same form.

    You can add in your Sonata Admin a prePersist method (http://sonata-project.org/bundles/admin/master/doc/reference/saving_hooks.html) and create a new Entity based on the data of your form.

    class PageLocaleAdmin extends Admin
    {
        public function prePersist($object)
        {
            $pageLocaleEnEntity = new PageLocale();
            $pageLocaleEnEntity->setDescriptionEN($object->getDescriptionEN());
            $pageLocaleEnEntity->setContentEN($object->getContentEN());
            $this->getConfigurationPool()->getContainer()->get('doctrine')->persist($pageLocaleEnEntity);
        }
    }
    

    Update 2

    Ok, i didn't see that the field descriptionEN and contentEN are not in your model. To fill the descriptionEN and contentEN on Edit you have to retrieve the related PageLocale and set the locale value, you could do :

    class PageLocaleAdmin extends Admin
    {
         public function configureFormFields(FormMapper $formMapper)
         {
             $locale = 'en';
             if ($this->subject->getId() !== null) {
                 $pageLocaleEntity = $this->getConfigurationPool()->getContainer()->get('doctrine')->getRepository('DXMyBundle:PageLocale')->findOneby($this->subject->getId(), $locale);
                 $descriptionEN = $pageLocaleEntity->getDescriptionEN();
                 $contentEN = $pageLocaleEntity->getContentEN();
             } else {
                 $pageLocaleEntity = null;
                 $descriptionEN = null;
                 $contentEN = null;
             }
    
             $formMapper
                 ->add('description', 'text', array('label' => 'Beschrijving'))
                 ->add('descriptionEN', 'text', array('label' => 'Beschrijving Engels', 'data' => $descriptionEN))
                 ->add('content', 'textarea', array('label' => 'Tekst', 'attr' => array('class' => 'ckeditor'), 'help' => 'My help text.'))
                 ->add('contentEN', 'textarea', array('label' => 'Tekst Engels', 'attr' => array('class' => 'ckeditor'), 'help' => 'My help text.', 'data' => $contentEN));
    
         }
    }