I have the following data model
Product: id, description, price
ProductExtraField: id, name
ProductExtraFieldData: product_id, extra_field_id, value
I want to use this datamodel so users of my application can add extra properties to a product on the fly. Let's say the add the property 'Color'. When they do so a row will be created in the ProductExtraField table with a value like this: 6, 'Color'. Now the can add values for this property to there products. When the do so a new row will be created in the ProductExtraFieldData table with a value like this: 4, 6, 'Green'. Now I want to represent this model in a class called Product. I use the following code:
<?php
use Doctrine\Common\Collections\ArrayCollection;
/** #Entity #Table(name="product") **/
class Product
public function __construct() {
$this->extraFieldData = new ArrayCollection();
$this->extraField = new ArrayCollection();
}
/** #Id #Column(name="id", type="integer") #GeneratedValue **/
private $id;
/** #Column(name="description", type="string") **/
private $description;
/** #Column(name="price", type="float") **/
private $price;
/**
* #OneToMany(targetEntity="ProductExtraFieldData", mappedBy="product", cascade={"persist"})
* #JoinColumn(name="product_id", referencedColumnName="id")
* #var extraFieldData[]
**/
protected $extraFieldData = null;
/**
* #OneToMany(targetEntity="ProductExtraField", mappedBy="??????")
* #var extraField[]
**/
protected $extraField = null;
Offcourse the last couple of lines are not correct. I don't know how to load this data. I want the names of the extra fields to be available with every product. I think $extraField should even be static. How can I configure Doctrine to load these values? Persisting the $extraField values from the Product class is not requirement.
Perhaps a structure like the following:
Product
id
description
etc...
ProductExtraField
product_id
extra_field_id
value
ExtraField
id
label
(anything else? type?)
So your Product will have a OneToMany mapping on ProductExtraField, which will have a ManyToOne mapping to ExtraField. Allowing you to use code such as...
$extraValues = array();
foreach ($product->getExtraFields() as $productExtraField) {
$extraValues[$productExtraField->getExtraField()->getLabel()] = $productExtraField->getValue();
}
// builds array such as array('colour' => 'blue', 'size' => 'small)
Related
So I have a following single inheritance table defined:
/**
* #Entity
* #Table(name="listKeys")
* #InheritanceType("SINGLE_TABLE");
* #DiscriminatorColumn(name="parent", type="string")
* #DiscriminatorMap({"Type1" = "Something1", "Type2" = "Something2"})
*/
abstract class ListKey
{
/**
* #OneToMany(targetEntity="KeyListValue", mappedBy="listKey", cascade={"persist", "remove"}, orphanRemoval=true)
*/
private Collection $listValues;
/**
* #ManyToOne(targetEntity="KeyListValue")
* #JoinColumn(name="defaultKeyListValueId")
*/
private ?KeyListValue $defaultKeyListValue = null;
}
With the list options defined as:
/**
* #Entity
* #Table(name="keyListValues")
*/
class KeyListValue
{
/**
* #Column(type="string")
*/
private $label;
/**
* #ManyToOne(targetEntity="ListKey", inversedBy="listValues", cascade={"persist"})
* #JoinColumn(name="caKeyId")
*/
private ListKey $listKey;
}
Before adding list values to a key, persisting and flushing worked ok, so the key would get inserted first after the commit order calculation. But once I added a new column default key list value, the commit order changes, and key list values try to get inserted first so the transaction fails.
Workaround is that I use flush() after creating new key and the adding the list values but this is problematic since ListKey also has association with some other entities which are not persisted yet at the time of flush so cascades would have to be declared and I don't want that. Any suggestion on how I can redefine this relationship better or a better workaround so the commit order would first insert keys?
I am making blog maker in symfony and doctrine
I am trying to connect, ID of row in blog posts with comments by blog_id value, but I getting this error
\Entity\BlogPosts.php
The association App\Entity\BlogPosts#comments refers to the owning side field App\Entity\Frontend\Blog\Fe_blog_comments#blogId which is not defined as association, but as field.
The association App\Entity\BlogPosts#comments refers to the owning side field App\Entity\Frontend\Blog\Fe_blog_comments#blogId which does not exist.
My actual code looks like this
\Entity\BlogPosts.php
class BlogPosts
{
/**
* #ORM\OneToMany(targetEntity="App\Entity\Frontend\Blog\Fe_blog_comments", mappedBy="blogId")
*/
private $comments;
//...
}
\Entity\Frontend\Blog\Fe_blog_comments.php
class Fe_blog_comments
{
//...
/**
* #ORM\Column(type="integer")
* #ORM\ManyToOne(targetEntity="App\Entity\BlogPosts", inversedBy="comments")
* #ORM\JoinColumn(name="blog_id", referencedColumnName="id")
*/
private $blogId;
//...
}
Remove #ORM\Column(type="integer"), the column should be managed by #ORM\JoinColumn(name="blog_id", referencedColumnName="id")
Having a list of "things" (for example, a list of cities) to display in a select option form field type, how should I manage it?
For example, take the following very short list of cities:
[0] Salerno;
[1] New York;
[2] Paris;
[3] Chicago;
[4] New Delhi;
I would like to do the following things:
Show them in the form select field type;
Store them in the database using their index (0 for Salerno, 1 for New York and so on);
Transform them into strings from the index when I retrieve the information from the database through Doctrine.
One alternative could be the use of a class full of constants, but maybe there is a better solution, so I'm asking here for it! :)
Thank you!
Super easy, use the entity field type. This allows you to use an entity to list the Choices, it even handles mapping the indexes for you.
http://symfony.com/doc/current/reference/forms/types/entity.html
$builder->add('users', 'entity', array(
'class' => 'AcmeHelloBundle:User',
'property' => 'username',
));
The class maps to your entity class. the property tells it which property on the class to show to the user in the select.
A hopefully more direct answer: the most straightforward technique would be to create a City entity. It would look like this:
use Doctrine\ORM\Mapping as ORM;
/**
* City
*
* #ORM\Table(name="city")
* #ORM\Entity
*/
class City
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
protected $id;
/**
* #var string
*
* #ORM\Column(name="city", type="string", length=15, nullable=false)
*/
protected $city;
/**
* Set city
*
* #param string $city
* #return City
*/
public function setCity($city)
{
$this->city = $city;
return $this;
}
/**
* Get city
*
* #return string
*/
public function getCity()
{
return $this->city;
}
}
In a form class you could add City as an entity type (see Chausser's answer for documentation reference).
The city's name could be returned in a controller with something like
$em = $this->getDoctrine()->getManager();
$city = $em->getRepository("YourBundle:City")->find($id);
$cityName = $city->getCity();
I have one entity, say Person, which contains a list of $pets:
protected $pets;
public function getPets()
{
return $this->pets;
}
Standard Doctrine. Unfortunately, these pets may be of different types, such as cats or dogs, or a mix. So I used Class Table Inheritance:
/**
* #ORM\Entity
* #ORM\Table(name="pets")
* #ORM\InheritanceType("JOINED")
* #ORM\DiscriminatorColumn(name="pettype", type="string")
* #ORM\DiscriminatorMap({"cat_animal" = "CatAnimal", "dog_animal" = "DogAnimal"})
*/
class Pet
{
/**
* #ORM\Column(name="eventid", type="integer")
* #ORM\Id
*/
private $id; // protected did not work either
/**
* Get id
*/
public function getId()
{
return $this->id;
}
}
/**
* #ORM\Entity
* #ORM\Table(name="cat_animal")
*/
class CatAnimal extends Pet
{
/**
* #ORM\Column(type="float")
*/
protected $height;
// etc.
}
// DogAnimal class omitted.
This was relatively straightforward using Doctrine's docs.
If I want to get all cats for an individual person, I have discovered I can do this:
public function getCats($person)
{
return $this->getEntityManager()->getRepository('MyBundle:CatAnimal')
->findByPerson($person);
}
However, how do I access the subclasses using a query builder? If I have the Person repository ($repos here), I want to do something like the following:
$repos->createQueryBuilder('person')
->select('pet.height')
->join('person.pets', 'pet')
->where('person = :person')
->setParameter('person', $person);
Except Pet doesn't have height, so this throws an exception. The DQL generated automagically joins to DogAnimal and CatAnimal, so I should be able to access these properties, but I don't know how. I have tried:
$repos->createQueryBuilder('person')
->select('cat.height')
->from('MyBundle:CatAnimal', 'cat)
->join('person.pets', 'pet')
->where('person = :person')
->setParameter('person', $person);
But this seems to do the cartesian product. I can solve that by adding:
->andWhere('person.id = cat.person')
This seems overly complicated for what I want. I have tried looking for the correct way to do this, but resources are limited.
This builds on a previous question, with a similar structure. The names of the tables were changed for clarity and generalisability.
You need to join correctly to Person, adding a field to the Pet class. In my example I named it owner:
$catRepo->createQueryBuilder('cat')
->select('cat.height')
->from('MyBundle:CatAnimal', 'cat')
->join('cat.owner', 'person')
->where('person = :person')
->setParameter('person', $person);
Please, could you help me?
I´m looking for the best way, how to add to entity (Product) some parametrs with values.
For example:
Product T-Shirt would have parametrs: size: XXL, color: red, material: cotton. How to make tables to have the best result - easy adding parametrs to product and easy filtering products by parametrs.
Thank you for your opinions.
You have two options:
A OneToMany relationship with another entity (recommended)
You may create a new entity called ProductProperty and declare a OneToMany relationship from Product to ProductProperty, like this:
The Product entity
/**
* #ORM\Entity
*/
class Product
{
/**
* #ORM\OneToMany(targetEntity="ProductProperty", mappedBy="product", cascade={"remove"})
*/
public $properties;
}
The ProductProperty entity
/**
* #ORM\Entity
*/
class ProductProperty
{
/**
* #ORM\ManyToOne(targetEntity="Product", inversedBy="properties")
* #ORM\JoinColumn(name="product_id", referencedColumnName="id")
*/
public $product;
}
Create an array property in entity Product
Doctrine 2 supports arrays (it serializes the array into a TEXT column). Create a property that behaves like an array:
/**
* #ORM\Entity
*/
class Product
{
/** #ORM\Column(type="array") */
public $properties;
public function __construct()
{
$this->properties = []; //new PHP array notation, if using older PHP use array()
}
}