BNE
BNE

Reputation: 55

Sylius: adding resource with translateable content

I am building an app based on Sylius standard edition. With the ResourceBundle i handled to integrate my own entities and the corresponding relations. This new resources should be related later to the products entity, but first i want to get it working "standalone". The backend works for both, the added resource and for relations. These are editable via form-collections. Very fine! Now i want to get translated database-content for my new resource. I tried the way i did it in Symfony earlier, but it didn't work. The last vew days i tried every possible solution found, but none of this works, or i made mistakes... Neither the translation-tables where constructed when typing:

app/console doctrine:schema:update --force

nor translatable content is visible in the forms. When calling the edit action, i get following error:

error:
Neither the property "translations" nor one of the methods "getTranslations()", "translations()", "isTranslations()", "hasTranslations()", "__get()" exist and have public access in class "KontaktBundle\Entity\Kontakte".

Is somebody out there with an example implementation of a extended Sylius-resource with translateable database-content? I'm still learning symfony and sylius too, can you tell me what i'm missing or doing wrong?

Many Thanks to @gvf. Now i figured out that the config entry must be set. This gave me a functional example which i want to provide here:

Configs

# app/config/sylius_config.yml (must be imported in config)

# Adding Resource
sylius_resource:
    # Resource Settings
    settings:
        sortable: true
        paginate: 50
        allowed_paginate: [50, 100, 500]
        filterable: true

    resources:
        dbk.authors:
            driver: doctrine/orm
            templates: AuthorBundle:Backend
            object_manager: default
            classes:
                model: AuthorBundle\Entity\Kontakte
                #interface: // if you have an interface configured
                controller: Sylius\Bundle\ResourceBundle\Controller\ResourceController
                repository: Sylius\Bundle\ResourceBundle\Doctrine\ORM\EntityRepository
                translation:
                    model: AuthorBundle\Entity\AuthorsTranslation
                    mapping:
                        fields: ['anrede','biografie']

Services

# app/config/sylius_services.yml (must be imported in config)
parameters:
    # Parameter for our author entity
    app.form.type.authors.class: AuthorBundle\Form\AuthorsType
    app.form.type.authors_translation.class: AuthorBundle\Form\AuthorsTranslationType

services:
    # Adding Authors Backend menu Item
    dbk_backend_authors.menu_builder:
        class: AuthorBundle\EventListener\MenuBuilderListener
        tags:
            - { name: kernel.event_listener, event: sylius.menu_builder.backend.main, method: addBackendMenuItems }
            - { name: kernel.event_listener, event: sylius.menu_builder.backend.sidebar, method: addBackendMenuItems }

    # Adding Authors FormType
    app.form.type.authors:
        class: "%app.form.type.authors.class%"
        tags: 
            - {name: form.type, alias: dbk_authors }

    app.form.type.authors_translation:
        class: "%app.form.type.authors_translation.class%"
        tags: 
            - {name: form.type, alias: dbk_authors_translation }

EventListener (Adds Menu Entry in Sylius-Backend)

<?php

// AuthorBundle/EventListener/MenuBuilderListener/MenuBuilderListener.php

namespace AuthorBundle\EventListener;

use Sylius\Bundle\WebBundle\Event\MenuBuilderEvent;

class MenuBuilderListener
{
    public function addBackendMenuItems(MenuBuilderEvent $event)
    {
        $menu = $event->getMenu();

        $menu['assortment']->addChild('vendor', array(
            'route' => 'Authors',
            'labelAttributes' => array('icon' => 'glyphicon glyphicon-user'),
        ))->setLabel('Authors');
    }
}

Entities

Authors (The new resource hich we want to add and to translate)

<?php

// AuthorBundle/Entity/Authors.php

namespace AuthorBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use Sylius\Component\Translation\Model\AbstractTranslatable;
use Doctrine\Common\Collections\ArrayCollection;

/**
 * Authors
 *
 * @ORM\Entity
 * @ORM\Table(name="authors")
 */
class Authors extends AbstractTranslatable
{

    //
    // IDENTIFIER FIELDS
    //

    /**
     * @var integer
     *
     * @ORM\Column(name="id", type="bigint", length=20, nullable=false, options={"unsigned":"true"})
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;


    //
    // FIELDS
    //

    /**
     * @var string
     *
     * @ORM\Column(name="vorname", type="string", length=255)
     */
    private $vorname;

    /**
     * @var string
     *
     * @ORM\Column(name="nachname", type="string", length=255)
     */
    private $nachname;

    public function __construct() {
        parent::__construct();
    }

    //
    // TranslationFields - Getters and Setters
    //

    /**
     * Get Anrede
     * @return string
     */
    public function getAnrede()
    {
        return $this->translate()->getAnrede();
    }

    /**
     * Set Anrede
     *
     * @param string $anrede
     *
     * @return Authors
     */
    public function setAnrede($anrede)
    {
        $this->translate()->setAnrede($anrede);
        return $this;
    }

    /**
     * Get Biografie
     * @return string
     */
    public function getBiografie()
    {
        return $this->translate()->getBiografie();
    }

    /**
     * Set Biografie
     *
     * @param string $biografie
     *
     * @return Authors
     */
    public function setBiografie($biografie)
    {
        $this->translate()->setBiografie($biografie);
        return $this;
    }


    //
    // Getters and Setters
    //

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


    /**
     * Set vorname
     *
     * @param string $vorname
     *
     * @return Authors
     */
    public function setVorname($vorname)
    {
        $this->vorname = $vorname;

        return $this;
    }

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

    /**
     * Set nachname
     *
     * @param string $nachname
     *
     * @return Authors
     */
    public function setNachname($nachname)
    {
        $this->nachname = $nachname;

        return $this;
    }

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


    public function  __toString(){
        return $this->getFullName();
    }

}

AuthorsTranslation (This is the Entity for tanslation of Authors)

<?php

// AuthorBundle/Entity/AuthorsTranslation.php

namespace AuthorBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use Sylius\Component\Translation\Model\AbstractTranslation;

/**
 * AuthorsTranslation
 *
 * @ORM\Entity
 * @ORM\Table(name="authors_translation")
 */
class AuthorsTranslation extends AbstractTranslation
{
    /**
     * @var integer
     *
     * @ORM\Column(name="id", type="bigint", length=20, nullable=false, options={"unsigned":"true"})
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    protected $id;

    //
    // TRANSLATABLE - FIELDS
    //

    /**
     * @var string
     * @ORM\Column(name="anrede", type="string", length=255)
     */
    private $anrede;

    /**
     * @var string
     * @ORM\Column(name="biografie", type="text")
     */
    private $biografie;

    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return $this->id;
    }

    //
    // GETTERS AND SETTERS
    //

    /**
     * Set anrede
     *
     * @param string $anrede
     * @return Authors
     */
    public function setAnrede($anrede)
    {
        $this->anrede = $anrede;
        return $this;
    }

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


    /**
     * Set biografie
     *
     * @param string $biografie
     *
     * @return Authors
     */
    public function setBiografie($biografie)
    {
        $this->biografie = $biografie;
        return $this;
    }

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



}

FormTypes

AuthorsType

<?php

// AuthorBundle/Form/AuthorsType.php

namespace AuthorBundle\Form;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
use Doctrine\ORM\QueryBuilder;

class AuthorsType extends AbstractType
{

     /**
     * @param FormBuilderInterface $builder
     * @param array $options
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            // Add Translations to Form.
            ->add('translations', 'a2lix_translations', array(
                'required' => false,
                'fields' => array(
                    'anrede' => array(
                        'label' => 'Anrede',
                    ),
                    'biografie' => array(
                        'label' => 'Biografie',
                        'attr' => array('data-edit' => 'wysiwyg', 'rows' => '15'),
                        'required' => false,
                    )
                )
            ))

            ->add('vorname', null, array(
                'label' => 'Vorname',
                'required' => false,
            ))

            ->add('nachname', null, array(
                'label' => 'Nachname',
                'required' => false,
            ))
        ;
    }

    /**
     * @param OptionsResolverInterface $resolver
     */
    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
            $resolver->setDefaults(array(
                'csrf_protection'   => false,
                'data_class' => 'AuthorBundle\Entity\Authors'
            ));
    }

    /**
     * @return string
     */
    public function getName()
    {
        return 'dbk_authors';
    }
}

AuthorsTranslationType

<?php

// AuthorBundle/Form/AuthorsTranslationType.php

namespace AuthorBundle\Form;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;

class AuthorsTranslationType extends AbstractType
{
    /**
     * {@inheritdoc}
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('anrede', 'text', array(
                'label' => 'Anrede'
            ))
            ->add('biografie', 'textarea', array(
                'label' => 'Biografie'
            ))
        ;
    }

    /**
     * {@inheritdoc}
     */
    public function getName()
    {
        return 'dbk_authors_translation';
    }
}

Form Template

{# AuthorBundle/Resources/views/backend/edit||add.html.twig - as you like... the call of form.translation (line 5) is the point here #}
{% form_theme form 'SyliusWebBundle:Backend:forms.html.twig' %}
<div class="row">
    <div class="col-md-12">
        {{ form_row(form.translations, {'attr': {'class': 'input-lg'}}) }}
        {{ form_row(form.vorname) }}
        {{ form_row(form.nachname) }}
    </div>
</div>

Upvotes: 3

Views: 1352

Answers (1)

gvf
gvf

Reputation: 1039

Have a look at the Product and ProductTranslation under the models folder in Sylius Components to see an example of how Sylius implements it.

Kontakte needs to extend AbstractTranslatable, you also need to create a class KontakteTranslation that extends AbstractTranslation. Under sylius_resource you also need to configure the translations:

sylius_resource:
resources:
    dbk.contact:
        driver: doctrine/orm
        templates: KontaktBundle:Backend
        object_manager: default
        classes:
            model: KontaktBundle\Entity\Kontakte
            controller: Sylius\Bundle\ResourceBundle\Controller\ResourceController
            repository: Sylius\Bundle\ResourceBundle\Doctrine\ORM\EntityRepository
            translation:
                model: KontaktBundle\Entity\KontakteTranslation
                mapping:
                    fields: {...fields that will be translated...}

Get rid of gedmo translatable extension because Sylius doesn't use it.

Upvotes: 2

Related Questions