Symfony forms for Translatable Doctrine entities - php

I have a Doctrine entity that has been translated using the Translatable Doctrine extension:
<?php
namespace Myapp\ProductBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Gedmo\Mapping\Annotation as Gedmo;
use Gedmo\Translatable\Translatable;
/**
* #ORM\Table(name="product_property")
* #ORM\Entity()
* #Gedmo\TranslationEntity()
*/
class Property implements Translatable
{
/**
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #Gedmo\Translatable
* #ORM\Column(name="name", type="string", length=255)
*/
private $name;
/**
* #ORM\OneToMany(
* targetEntity="PropertyTranslation",
* mappedBy="object",
* cascade={"persist", "remove"}
* )
*/
private $translations;
/**
* #Gedmo\Locale
* Used locale to override Translation listener`s locale
* this is not a mapped field of entity metadata, just a simple property
*/
private $locale;
public function setTranslatableLocale($locale)
{
$this->locale = $locale;
}
public function getTranslations()
{
return $this->translations;
}
public function addTranslation(PropertyTranslation $t)
{
if (!$this->translations->contains($t)) {
$this->translations[] = $t;
$t->setObject($this);
}
}
}
Now, I'd like to render a form with an input field for the "name" property in each of the languages available in my translation.
How is that best done?

It seems that the following bundle is able to do exactly what I was looking for: https://github.com/a2lix/TranslationFormBundle

Related

Symfony - how to make Doctrine search in abstract mapped superclass?

I am building an online shop for plastic model makers (hence the 'model').
I have a Product mapped superclass because I want all products (models, tools, paints etc. to have name, price and description):
<?php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\ORM\Mapping\MappedSuperclass;
use Gedmo\Mapping\Annotation as Gedmo; // gedmo annotations
/** #MappedSuperclass */
abstract class Product
{
/**
* #ORM\Column(type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
* #ORM\Column(type="string", length=100, nullable=false)
*/
protected $name;
/**
* #var int
* #ORM\Column(type="decimal", scale=2, nullable=false)
*/
protected $price;
/**
* #var string
* #ORM\Column(type="text", nullable=true)
*/
protected $description;
/**
* #Gedmo\Timestampable(on="create")
* #ORM\Column(type="datetime")
*/
private $createdAt;
/**
* #ORM\Column(type="datetime")
* #Gedmo\Timestampable(on="update")
*/
private $updatedAt;
//getters and setters...
}
Then, there's a Model class, for plastic models, this extends the Product class but also has a Category for being able to search from cars, aircraft, ships etc:
<?php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity
* #ORM\Table(name="model")
*/
class Model extends Product
{
/**
* #var Category
* #ORM\ManyToOne(targetEntity="AppBundle\Entity\Category", inversedBy="models")
* #ORM\JoinColumn(name="category_id", referencedColumnName="id", nullable=true)
*/
private $category;
/**
* #return Category
*/
public function getCategory()
{
return $this->category;
}
/**
* #param Category $category
*/
public function setCategory($category)
{
$this->category = $category;
}
}
There will of course be more classes extending Product mapped superclass. Now I want to select the 10 most recently added products, regardless of their kind (models, tools, paints).
How can I tell Doctrine to give me the last 10 added products? Of course I tried something like:
$this->getDoctrine()->getManager()->getRepository("AppBundle:Product");
but of course it throws an exception saying that
SQLSTATE[42S02]: Base table or view not found: 1146 Table
'modeller_app.product' doesn't exist
which obviously is true, because Product is an abstract class and not actually an entity. How can I solve this problem?
You need to use class table inheritance.
Here is a example:
/**
* #ORM\Entity
* #ORM\Table(name="product")
* #InheritanceType("JOINED")
* #DiscriminatorColumn(name="discr", type="string")
* #DiscriminatorMap({"product" = "Product", "model" = "Model"})
*/
class Product
{
/**
* #ORM\Column(type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #var string
* #ORM\Column(type="string", length=100, nullable=false)
*/
protected $name;
...
}
/**
* #ORM\Entity
* #ORM\Table(name="product")
*/
class Model extends Product
{
// Custom properties
...
}
Now you can query the Product entity and it will return the result from all entities that inherits it.

StofDoctrineExtensionsBundle checking the uniqueness of slug by the two fields

I use Knp\DoctrineBehaviors for Translation and StofDoctrineExtensionsBundle for Sluggable. How to make checking the uniqueness of slug by the sluggable and locale? I want to get the slug look like this:
for EN: /contacts
for PT: /pt/contacts
for PT (if duplicate): /pt/contacts-1
for ES: /es/contacts
But now, i have this database filter_node_translation
Entity\FilterNode.php:
<?php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Knp\DoctrineBehaviors\Model as ORMBehaviors;
/**
* #ORM\Table(name="filter_node")
* #ORM\Entity()
*/
class FilterNode
{
use ORMBehaviors\Translatable\Translatable;
/**
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
* #ORM\Column(name="id", type="integer")
*/
protected $id;
/**
* #return mixed
*/
public function getId()
{
return $this->id;
}
}
FilterNodeTranslation:
<?php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Knp\DoctrineBehaviors\Model as ORMBehaviors;
use Gedmo\Mapping\Annotation as Gedmo;
/**
* #ORM\Table(name="filter_node_translation")
* #ORM\Entity()
*/
class FilterNodeTranslation
{
use ORMBehaviors\Translatable\Translation;
/**
* #var string
*
* #ORM\Column(type="string", nullable=true)
*/
protected $sluggable;
/**
* #var string
*
* #Gedmo\Slug(fields={"sluggable"})
* #ORM\Column(type="string", nullable=true)
*/
protected $slug;
/**
* #return string
*/
public function getSluggable()
{
return $this->sluggable;
}
/**
* #param string $sluggable
*/
public function setSluggable($sluggable)
{
$this->sluggable = $sluggable;
}
}
I found solution. Gedmo sluggable have other configuration option "unique_base".
It looks like this:
class FilterNodeTranslation
{
/**
* #var string
*
* #Gedmo\Slug(updatable=true, unique=true, unique_base="locale", fields={"sluggable"})
* #ORM\Column(type="string")
*/
protected $slug;
}

Symfony2 validation - first value is less than second

I've got entity type of:
/**
* #ORM\Table(name="entity")
*/
class Entity
{
/**
* #var integer
*
* #ORM\Column(type="integer", nullable=true)
*/
private $value1;
/**
* #var integer
*
* #ORM\Column(type="integer", nullable=true)
*/
private $value2;
}
How to check with validation that $value1 is less than $value2?
You can use Expression constraint in your entity
use Symfony\Component\Validator\Constraints as Assert;
/**
* #ORM\Table(name="entity")
*/
class Entity
{
/**
* #var integer
* #Assert\Expression(
* "this.getValue2() < this.getValue1()",
* message="Value 1 should be less than value 2"
* )
* #ORM\Column(type="integer", nullable=true)
*/
private $value2;
}
Basically, as the cookbook explains extensively, you'll probably want to add the following to your entity:
use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Component\Validator\Context\ExecutionContextInterface;
class Entity
{
//the values stay the same
/**
* #Assert\Callback
*/
public function validate(ExecutionContextInterface $context)
{
if ($this->value1 >= $this->value2)
{
$context->buildViolation('Value1 should be less than value2')
->atPath('value1')
->addViolation();
}
}
}

Class Doctrine\Common\Collections\ArrayCollection is not a valid entity or mapped super class

I have Three entities:
FeatureValue.php
<?php
namespace Webmuch\ProductBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity
*/
class FeatureValue
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #ORM\Column(type="string", length="100")
*/
protected $name;
/**
* #ORM\OneToMany(targetEntity="FeatureType", mappedBy="name")
*/
private $featuretype;
public function __construct()
{
$this->featuretype = new \Doctrine\Common\Collections\ArrayCollection();
}
FeatureType.php
<?php
namespace Webmuch\ProductBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Webmuch\ProductBundle\Entity\FeatureValue;
/**
* #ORM\Entity
*/
class FeatureType
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #ORM\Column(type="string", length=255, nullable=true)
*/
protected $title;
/**
* #ORM\ManyToOne(targetEntity="FeatureValue", inversedBy="featuretype",cascade={"persist"})
* #ORM\JoinColumn(name="feature_value_id", referencedColumnName="id")
*/
protected $name;
public function __construct()
{
$this->name = new \Doctrine\Common\Collections\ArrayCollection();
}
Product.php
<?php
namespace Webmuch\ProductBundle\Entity;
use Gedmo\Mapping\Annotation as Gedmo;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection as ArrayCollection;
/**
* #ORM\Entity
* #ORM\Table()
* #ORM\HasLifecycleCallbacks
*/
class Product
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #ORM\ManyToMany(targetEntity="Store")
*/
protected $store;
/**
* #ORM\ManyToMany(targetEntity="Webmuch\CategoryBundle\Entity\Category")
*/
protected $category;
/**
* #Gedmo\Sluggable
* #ORM\Column(type="string", length=255)
*/
protected $title;
/**
* #Gedmo\Slug(updatable=false, unique=true)
* #ORM\Column(type="string", length=255)
*/
protected $slug;
/**
* #ORM\Column(type="integer")
*/
protected $quantity;
/**
* #ORM\Column(type="boolean")
*/
protected $active;
/**
* #ORM\Column(type="text", length="4000", nullable="true")
*/
protected $preview;
/**
* #ORM\ManyToMany(targetEntity="FeatureType")
* #ORM\JoinColumn(name="feature_type_id", referencedColumnName="id")
*/
protected $features;
public function __toString()
{
return $this->getTitle();
}
}
My problem is that when i add FeatureValue in FeatureType then show me error Class "Doctrine\Common\Collections\ArrayCollection is not a valid entity or mapped super class."
In my project i want FeatureType along with FeatureValue in my Product entity.
suppose in FeatureType two property Size and Colour.Now in FeatureType Size- Three FeatueValue Small,Medium,Large have been given and also suppose in FeatureType Colour- Three FeatureValue Red,Green,Yello have been given.
Now i want to show both the FeatureType along with their FeatureValue in my Product Entity.
So any one tell me how it can be done.I have tried a lot of but not succeed.
In Webmuch\ProductBundle\Entity\FeatureType::__construct you assign an ArrayCollection to $this->name, this is wrong, as this is a ToOne and not a ToMany.
Just remove this line.

Symfony2 : Entities not created in database

I'm making entities with Symfony2 and Doctrine2. I made some entities that represent a many-to-many relation between two of my entities.
An example of one of these entities :
/**
* #ORM\Entity
*/
class Contact_Conference_Invitation
{
/**
* #ORM\Id
* #ORM\ManyToOne(targetEntity="Aurae\UserBundle\Entity\Contact")
*/
private $contact;
/**
* #ORM\Id
* #ORM\ManyToOne(targetEntity="Aurae\ConferenceBundle\Entity\Conference")
*/
private $conference;
/**
* #var datetime dateInvitation
*
* #ORM\Column(name="dateInvitation", type="datetime")
*/
private $dateInvitation;
//Getters and setters
}
I have tried updating my sql schema, but the tables corresponding to these entities do not appear. Is there somewhere I have to declare them (config or such)? If not, what's wrong?
Thanks a lot
Edit : I had forgotten the namespace for these class, and that's why they were omitted by Doctrine. Another case closed :) thanks for the answers!
Assumptions ...
No, you don't need to declare them anywhere else than in your Entity directory.
What's the error message you got?
I guess you added
use Doctrine\ORM\Mapping as ORM;
on the top of your classes to let them be mapped.
I tried ...
I tried to generate your entities by adding a simple Contact & Conference entities and it's working fine.
Here are the code snippets:
Contact_Conference_Invitation.php
namespace Ahsio\StackBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity
*/
class Contact_Conference_Invitation
{
/**
* #ORM\Id
* #ORM\ManyToOne(targetEntity="Ahsio\StackBundle\Entity\Contact")
*/
private $contact;
/**
* #ORM\Id
* #ORM\ManyToOne(targetEntity="Ahsio\StackBundle\Entity\Conference")
*/
private $conference;
/**
* #var datetime dateInvitation
*
* #ORM\Column(name="dateInvitation", type="datetime")
*/
private $dateInvitation;
//Getters and setters
}
Contact.php
namespace Ahsio\StackBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity
*/
class Contact
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #param $id
*/
public function setId($id)
{
$this->id = $id;
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
}
Conference.php
namespace Ahsio\StackBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity
*/
class Conference
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #param $id
*/
public function setId($id)
{
$this->id = $id;
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
}
Here are the generated tables:
NB: I used a specific namespace for the entities generation to work fine, you need to change them.
Also don't forget to check that you have automapping enabled.
In your config.yml you should have
doctrine:
orm:
auto_mapping: true
Came across this question because my entities weren't generated as well, this was my issue, it could save some time to people struggling with the same issue.
I don't see the definition of your ManyToMany relation in the sample of code you provided.
As an example, here's a ManyToMany relationship I implemented for a project
Entity Project.php
/**
* #var Provider[]
*
* #ORM\ManyToMany(targetEntity="Provider", mappedBy="projects")
*/
protected $providers = null;
Entity Provider.php
/**
* #var Project[]
*
* #ORM\ManyToMany(targetEntity="Project", inversedBy="providers")
* #ORM\JoinTable(name="PROVIDER_PROJECT")
*/
protected $projects = null;
As you can see, here you define the join table for your ManyToMany relationship.
Of course those entities are specific for my particular project but you get the idea and you can adapt it easily for your needs.

Categories