Entity Not Found error in symfony2 Form - forms

I have a symfony2 Form CategoryType with a buildForm:
public function buildForm(FormBuilderInterface $builder, array $options) {
$builder->add('language', 'entity', array(
'class' => 'Evr\HomeBundle\Entity\Language',
'property' => 'language'
)
)
->add('category', 'text', array('label' => 'category.category', 'required' => true));
}
As you can expect, I have two entities Category and Language, of which Category is a child of Language (One language can have many categories, and one category belongs to 1 or 0 language)
Category
<?php
namespace Evr\HomeBundle\Entity;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM;
/**
* Category
*
* #ORM\Table(name="ev_category")
* #ORM\Entity
*/
class Category
{
/**
* #var integer
*
* #ORM\Column(name="category_id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
*
* #ORM\ManyToOne(targetEntity="Language",inversedBy="categories")
* #ORM\JoinColumn(name="language_id",referencedColumnName="language_id")
*/
private $language;
/**
* #var string
*
* #ORM\Column(name="category", type="string", length=255)
*/
private $category;
/**
* #ORM\OneToMany(targetEntity="Subcategory", mappedBy="category")
*/
protected $subcategories;
public function __construct(){
$this->subcategories=new ArrayCollection();
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set language
*
* #param integer $language
* #return Category
*/
public function setLanguage($language) {
$this->language = $language;
return $this;
}
/**
* Get language
*
* #return integer
*/
public function getLanguage() {
return $this->language;
}
/**
* Set category
*
* #param \string $category
* #return Category
*/
public function setCategory($category)
{
$this->category = $category;
return $this;
}
/**
* Get category
*
* #return \string
*/
public function getCategory()
{
return $this->category;
}
}
Language
<?php
namespace Evr\HomeBundle\Entity;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM;
/**
* Language
*
* #ORM\Table(name="ev_language")
* #ORM\Entity
*/
class Language
{
/**
* #var integer
*
* #ORM\Column(name="language_id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="language", type="string", length=128)
*/
private $language;
/**
* #var string
*
* #ORM\Column(name="code", type="string", length=10)
*/
private $code;
/**
* #var boolean
*
* #ORM\Column(name="direction", type="boolean")
*/
private $direction;
/**
* #ORM\OneToMany(targetEntity="Category", mappedBy="language")
*/
protected $categories;
/**
* #ORM\OneToMany(targetEntity="Country", mappedBy="language")
*/
protected $countries;
public function __construct(){
$this->categories=new ArrayCollection();
$this->countries=new ArrayCollection();
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set language
*
* #param string $language
* #return Language
*/
public function setLanguage($language)
{
$this->language = $language;
return $this;
}
/**
* Get language
*
* #return string
*/
public function getLanguage()
{
return $this->language;
}
/**
* Set code
*
* #param string $code
* #return Language
*/
public function setCode($code)
{
$this->code = $code;
return $this;
}
/**
* Get code
*
* #return string
*/
public function getCode()
{
return $this->code;
}
/**
* Set direction
*
* #param boolean $direction
* #return Language
*/
public function setDirection($direction)
{
$this->direction = $direction;
return $this;
}
/**
* Get direction
*
* #return boolean
*/
public function getDirection()
{
return $this->direction;
}
}
When editing a category, I need to display the current values in a form, so that the user can modify them and save.
Here I have a controller editAction(), whose mission is to display the edition form:
public function editAction($id) { //id of the category to modify
$category = $this->getDoctrine()->getRepository('EvrHomeBundle:Category')->find($id); //return the category with id
$categoryForm = $this->createForm(new CategoryType(),$category); //building the form
return $this->render('EvrAdminBundle:Categories:edit.html.twig', array('categoryForm' => $categoryForm->createView(), 'category' => $category));
}//render the form
Remember that the CategoryType has an element which type : entity, which loads the languages in A select box.
But when trying to populate the form CategoryType with the current data (Category and Language) , Symfony returns an Error : Entity Not Found
Symfony doesn't specify in which line the error occures, but I think it's around this line :
$categoryForm = $this->createForm(new CategoryType(),$category); //building the form
Because when I remove the second argument of createForm : $category, it displays an empty form (just like an add category form
Is there a solution for this issue? And how can I create a form with current data from the database, considering the fact that it contains an entity element.
Thank you

If you have a database without referential integrity enforced, then you can delete a record even though another record is pointing to it (they should be linked through a foreign key). Then when you try to grab the record it seem to work but when you want to access attributes of that entity (this is when the real access to the database occurs) it can't find the entity with that record_id and so "Entity not found".
Ex:
$user=new User();
$car=$user->getCar(); /*The user had a CAR record assigned with Id = 1 but the record was
deleted.
The record USER still has the id of 1.*/
/*No error up till here*/
$carName=$car->getName(); /*Error occurs because it tries to grab the record with id of 1
which was deleted*/

Try to use \ in front of entity namespace:
'class' => '\Evr\HomeBundle\Entity\Language',

Related

Symfony2: Could not load type "submit"

I am working with Symfony building a form in a Controller. Upon trying to view to the form on my browser; I get the following error page which states: "Could not load type "submit"". Whilst there are similar questions to this one, none address the submit button. In this instance what is the best way of solving this problem?
This is my controller(below)
public function indexAction(Request $request)
{
$user = new User();
$user->setFirstname("isambard");
$user->setEmail("wewewewew#hotmail.co.uk");
$user->setEnquiry("asdasda");
$form = $this->createFormBuilder($user)
->add('firstname','text')
->add('email', 'text')
->add('save','submit', array('label' => 'Create Task'))
->getForm();
return $this->render('delete.html.twig', array(
'form' => $form->createView(),
));
}
This is my User entity class (below):
class User
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="firstname", type="string", length=100)
*/
private $firstname;
/**
* #var string
*
* #ORM\Column(name="email", type="string", length=100)
*/
private $email;
/**
* #var string
*
* #ORM\Column(name="enquiry", type="string", length=100)
*/
private $enquiry;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set firstname
*
* #param string $firstname
* #return User
*/
public function setFirstname($firstname)
{
$this->firstname = $firstname;
return $this;
}
/**
* Get firstname
*
* #return string
*/
public function getFirstname()
{
return $this->firstname;
}
/**
* Set email
*
* #param string $email
* #return User
*/
public function setEmail($email)
{
$this->email = $email;
return $this;
}
/**
* Get email
*
* #return string
*/
public function getEmail()
{
return $this->email;
}
/**
* Set enquiry
*
* #param string $enquiry
* #return User
*/
public function setEnquiry($enquiry)
{
$this->enquiry = $enquiry;
return $this;
}
/**
* Get enquiry
*
* #return string
*/
public function getEnquiry()
{
return $this->enquiry;
}
}
This is probably because you are using an older version of Symfony framework. As the documentation states.
2.3 Support for submit buttons was introduced in Symfony 2.3. Before that, you had to add buttons to the form's HTML manually.
You should either update your framework or manually insert the submit button in the twig template.

symfony form entity update

I'm trying to create a for with an entity.
My controller:
$questionnaire = $em->getRepository('questionnaireBundle:questionnaire')->findOneBy(array('id' => $id));
$form = $this->createForm(new questionnaireType(), $questionnaire);
QuestionnaireType:
public function buildForm(FormBuilderInterface $builder, array $options) {
$builder->add('nom', 'text', array('label' => 'Nom:'));
$builder->add('nbreQuestions', 'text', array('label' => 'Nombre de questions:'));
$builder->add('type', 'entity', array('class' => 'questionnaireBundle:type', 'property' => 'type'));
$builder->add('envoyer', 'submit', array('label' => 'Enregistrer', 'attr' => array('class' => 'btn btn-success col-md-12')));
}
The entity: questionnaire
namespace questionnaireBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
/**
* questionnaire
*
* #ORM\Table()
* #ORM\Entity
*/
class questionnaire {
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="nom", type="string", length=255)
*/
private $nom;
/**
* #var string
*
* #ORM\Column(name="type", type="string", length=255)
*/
private $type;
/**
* #var integer
*
* #ORM\Column(name="nbreQuestions", type="integer")
*
* #Assert\NotBlank(message="Veuillez entrer un nombre de questions.")
* #Assert\Type(type="integer")
*/
private $nbreQuestions;
/**
* Get id
*
* #return integer
*/
public function getId() {
return $this->id;
}
/**
* Set nom
*
* #param string $nom
* #return questionnaire
*/
public function setNom($nom) {
$this->nom = $nom;
return $this;
}
/**
* Get nom
*
* #return string
*/
public function getNom() {
return $this->nom;
}
/**
* Set type
*
* #param string $type
* #return type
*/
public function setType($type) {
$this->type = $type;
return $this;
}
/**
* Get type
*
* #return string
*/
public function getType() {
return $this->type;
}
/**
* Set nbreQuestions
*
* #param integer $nbreQuestions
* #return questionnaire
*/
public function setNbreQuestions($nbreQuestions) {
$this->nbreQuestions = $nbreQuestions;
return $this;
}
/**
* Get nbreQuestions
*
* #return integer
*/
public function getNbreQuestions() {
return $this->nbreQuestions;
}
public function __toString() {
return (string) $this->getNom();
}
}
The field nom, nbreQuestions will automatically be fully with the entity questionnaire, but type is not update!
Anybody knows why?
Thanks
Best regards
that must do a second query behind the sense, but you can increase performance by dql & join:
use this code:
$questionnaire = $em->createQuery('select q from questionnaireBundle:questionnaire q join q.type t where q.id = :id')->setParameter('id', $id)->getSingleResult();
$form = $this->createForm(new questionnaireType(), $questionnaire);
The reason of not selecting the proper type in your for is that entity type builds choices as
entity_id => property_value
So it is comparing your values from questionnaire type to the ids from your type entity and it will not find a match. Moreover if you update your questionnaire object the type will be changed to the id of type entity.
I see here two solutions:
proposed by #ghanbari to make relation from questionnaire to type
make your form as a service and inject entityManager than build your choices like you want (type => type) and change the field from entity type to choice type

How to show a collection form with the exact number of records available in a table

I am using symfony2 and doctrine.
I have a list of contacts and they are classified in a number of groups.
These groups are stored in a table.
Then I have users in my application and for each users I want to specify their rights: no/read/write.
In order to achieve this I have created a userspermission table as such :
<?php
namespace Curuba\contactsBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use APY\DataGridBundle\Grid\Mapping as GRID;
/**
* userspermissions
*
* #ORM\Table()
* #ORM\Entity(repositoryClass="Curuba\contactsBundle\Entity\userspermissionsRepository")
*/
class userspermissions
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="permission", type="string", length=10)
*
* #GRID\Column(title="Permission")
*
*/
private $permission;
/**
* #ORM\ManyToOne(targetEntity="groupes", inversedBy="permissions")
* #ORM\JoinColumn(nullable=false)
*
* #GRID\Column(title="Groupes")
*/
private $groupe;
/**
* #ORM\ManyToOne(targetEntity="users", inversedBy="permissions")
* #ORM\JoinColumn(nullable=false)
*
* #GRID\Column(title="Permission")
*/
private $user;
Now in my user form, I would need to show a table with all available groups and a drop-down list in front of them.
But I dont know how to achieve that without a collection and then asking the user to add a group permission, select a group and the according permission.
Thanks in advance.
You can use an ManyToOne relation.
For example with an User and Group
<?php
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity
* #ORM\Table(name="groups")
*/
class Group
{
const CLASS_NAME = __CLASS__;
/**
* #var integer
*
* #ORM\Id()
* #ORM\GeneratedValue(strategy="AUTO")
* #ORM\Column(name="id",type="integer")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="label",type="string",length=255)
*/
private $label;
/**
* #param int $id
*/
public function setId($id)
{
$this->id = $id;
}
/**
* #return int
*/
public function getId()
{
return $this->id;
}
/**
* #param string $label
*/
public function setLabel($label)
{
$this->label = $label;
}
/**
* #return string
*/
public function getLabel()
{
return $this->label;
}
/**
* #return string
*/
public function __toString()
{
return $this->getLabel();
}
}
and the User entity
<?php
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM;
/**
*
* #ORM\Entity
* #ORM\Table(name="user")
*/
class User
{
const CLASS_NAME = __CLASS__;
/**
* #var integer
*
* #ORM\Id()
* #ORM\GeneratedValue(strategy="AUTO")
* #ORM\Column(name="id",type="integer")
*/
private $id;
/**
* #var string
*
* #ORM\Column(type="string", name="label", length=255)
*/
private $label;
/**
* #ORM\ManyToMany(targetEntity="Group")
* #ORM\JoinTable(name="user_group",
* joinColumns={#ORM\JoinColumn(name="user_id", referencedColumnName="id")},
* inverseJoinColumns={#ORM\JoinColumn(name="group_id", referencedColumnName="id")}
* )
**/
private $groups;
public function __construct()
{
$this->groups = new ArrayCollection();
}
/**
* #param int $id
*/
public function setId($id)
{
$this->id = $id;
}
/**
* #return int
*/
public function getId()
{
return $this->id;
}
/**
* #param string $label
*/
public function setLabel($label)
{
$this->label = $label;
}
/**
* #return string
*/
public function getLabel()
{
return $this->label;
}
/**
* #param Group $group
*
* #return bool
*/
public function hasGroup(Group $group)
{
return $this->groups->contains($group);
}
/**
* #param Group $group
*
* #return $this
*/
public function addGroup(Group $group)
{
if (false === $this->hasGroup($group)) {
$this->groups->add($group);
}
return $this;
}
/**
* #return \Doctrine\Common\Collections\ArrayCollection
*/
public function getGroups()
{
return $this->groups;
}
/**
* #return string
*/
public function __toString()
{
return $this->getLabel();
}
}
and finally create an form type like this :
class UserType extends AbstractType
{
const NAME = 'userType';
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('label', 'text');
$builder->add('groups', 'entity', array(
'class' => Group::CLASS_NAME,
'multiple' => true,
'expanded' => true,
));
}
/**
* #param OptionsResolverInterface $resolver
*/
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => User::CLASS_NAME,
));
}
/**
* Returns the name of this type.
*
* #return string The name of this type
*/
public function getName()
{
return self::NAME;
}
}
I have found how to do this. This is in fact very simple and I was probably expecting something more complex...
I have added a function in my controller (could be in my entity...) and I cal this function when I create a new user entity or when I edit one (in case a groupe has been added in the mean time.
Here is the code:
private function autocompleteForm(users $user) {
$em = $this->getDoctrine()->getManager();
$groupes = $em->getRepository('contactsBundle:groupes')->findAll();
if ($user) {
foreach ($groupes as $groupe) {
$permission = $em->getRepository('contactsBundle:userspermissions')->findOneBy(array('groupe' => $groupe, 'user' => $user));
if(!$permission) {
$permission = new userspermissions();
$permission->setGroupe($groupe);
$user->addPermission($permission);
}
}
}
return $user;
}
I am happy to explain more if someone needs...

Symfony2, field type entity, "many-to-many" relation with extra fields, problems with the relation/ArrayCollection/multipe checkboxes in form

I want to create a form for a simple entry management.
I got the entities Entry, EntryUser, and User.
Tables in database: entry, entry_user and user.
I think i am close to be successful, but i got some problems here.
In my form, the author can check the users he want to add to the entry via checkboxes. Symfony/Doctrine should do the relation work for me and add rows into entry_user. One row for one selected checkbox.
Entry.php
/**
* #ORM\Entity
* #ORM\Table(name="entry")
*/
class Entry {
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #ORM\OneToMany(targetEntity="EntryUser", mappedBy="entry", cascade={"all"}, orphanRemoval=true)
*/
protected $users;
function __construct() {
$this->users = new ArrayCollection();
}
/**
* Add user
*
* #param User $user
* #return $this
*
*/
public function addUser(User $user)
{
if (!$this->users->contains($user)) {
$this->users->add($user);
}
return $this;
}
/**
* Remove user
*
* #param User $user
* #return $this
*/
public function removeUser(User $user)
{
if ($this->users->contains($user)) {
$this->users->removeElement($user);
}
return $this;
}
/**
* #return array
*/
public function getUsers()
{
return $this->users->toArray();
}
/**
* Returns the true ArrayCollection of Users.
* #return Doctrine\Common\Collections\ArrayCollection
*/
public function getUsersCollection()
{
return $this->users;
}
}
User.php
/**
* #ORM\Entity
* #ORM\Table(name="user")
*/
class User implements AdvancedUserInterface, EquatableInterface, \Serializable {
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #ORM\Column(type="string", length=255)
*/
protected $name;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set name
*
* #param string $name
* #return User
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*
* #return string
*/
public function getName()
{
return $this->name;
}
// Many other methods for user sign in, roles and so on...
}
EntryUser.php
/**
* #ORM\Entity
* #ORM\Table(name="entry_user")
*/
class EntryUser {
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #var integer
*
* #ORM\Column(name="user_id", type="integer", nullable=true)
*/
protected $user_id;
/**
* #var integer
*
* #ORM\Column(name="entry_id", type="integer", nullable=true)
*/
protected $entry_id;
/**
* #var User
*
* #ORM\ManyToOne(targetEntity="User", cascade={"persist"})
* #ORM\JoinColumn(name="user_id", referencedColumnName="id", onDelete="CASCADE")
*/
protected $user;
/**
* #var Entry
*
* #ORM\ManyToOne(targetEntity="Entry", inversedBy="users")
* #ORM\JoinColumn(name="entry_id", referencedColumnName="id", onDelete="SET NULL")
*/
protected $entry;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set user_id
*
* #param integer $userId
* #return EntryUser
*/
public function setUserId($userId)
{
$this->user_id = $userId;
return $this;
}
/**
* Get user_id
*
* #return integer
*/
public function getUserId()
{
return $this->user_id;
}
/**
* Set entry_id
*
* #param integer $entryId
* #return EntryUser
*/
public function setEntryId($entryId)
{
$this->entry_id = $entryId;
return $this;
}
/**
* Get entry_id
*
* #return integer
*/
public function getEntryId()
{
return $this->entry_id;
}
/**
* Set user
*
* #param User $user
* #return EntryUser
*/
public function setUser(User $user = null)
{
$this->user = $user;
return $this;
}
/**
* Get user
*
* #return User
*/
public function getUser()
{
return $this->user;
}
/**
* Set entry
*
* #param Entry $entry
* #return EntryUser
*/
public function setEntry(Entry $entry = null)
{
$this->entry = $entry;
return $this;
}
/**
* Get entry
*
* #return Entry
*/
public function getEntry()
{
return $this->entry;
}
}
I use ManyToOne relationships here because i want to use a file named EntryUser.php to add some custom fields later. I need this because i must store some additional data there in entry_user.
Because:
And it's the right thing to do. Create a new entity with the new fields, and if you need it, create a custom repository to add the methods you need.
A <--- Many to many with field ---> B
would become
A --One to many--> C (with new fields) <-- One to many--B
and of course, C has ManyToOne relationships with both A and B.
See the comments in: ManyToMany relationship with extra fields in symfony2 orm doctrine
My EntryType.php form definition includes the following, to create the checkboxes for the template:
$builder->add('users', 'entity', array(
'class' => 'MyCompMyAppBundle:User',
'multiple' => true,
'expanded' => true,
'property' => 'name',
'label' => 'Freunde',
'query_builder' => function(EntityRepository $er) {
return $er->createQueryBuilder('u')->select('a')
->from('MyComp\MyAppBundle\Entity\User', 'a')
->where('EXISTS (
SELECT b
FROM MyComp\MyAppBundle\Entity\UserFriend b
WHERE b.created_by = :my_user_id
AND b.friend_user_id = a.id
)')
->andWhere('EXISTS (
SELECT c
FROM MyComp\MyAppBundle\Entity\UserFriend c
WHERE c.created_by = a.id
AND c.friend_user_id = :my_user_id
)')
->setParameter('my_user_id', $this->user->getId());
},
'required' => true,
));
As you can see, i load User objects here for the form field (type: entity).
UserFriend is another entity (table: user_friend). A friend list is saved there. Here all the friends gets loaded. They will be shows as the checkboxes.
Now, if i go to my form in my browser, and check some users for the entry und if i submit the form, i get this error:
ORMException: Found entity of type MyComp\MyAppBundle\Entity\User on association MyComp\MyAppBundle\Entity\Entry#friends, but expecting MyComp\MyAppBundle\Entity\EntryUser
So it is very confusing.
How can i make this work?
How can i make symfony and doctrine work to insert data automatically into entry and entry_user?
Important: I want to make it possible that the author can edit the entry later. So the checkboxes should be selected by default as it is saved in entry_user.
I just try to understand this and got a little bit confused. But i dont know how to make this work.
I found an awesome solution in the web. I was searching for many days now, but this guy made my day! :-)
You can read how it works and learn from an awesome example here!
Happy coding!
For this case you should check "form collections" in Symfony: http://symfony.com/doc/current/cookbook/form/form_collections.html
With this technique you will add a form type to crate a single "EntryUser" and after that you can add a collection of that form to the parent form. Quite easy and well explained in the liked article.

Editing Slug using Gedmo TreeSlugHandler

I have an entity that is hierarchical using the Gedmo Tree Doctrine extension in Symfony 2. The code for the Category entity is:
<?php
namespace MD\Entity;
use Doctrine\Common\Collections\ArrayCollection;
use Symfony\Component\Validator\Constraints as Assert;
use Doctrine\ORM\Mapping as ORM;
use Gedmo\Mapping\Annotation as Gedmo;
use MD\Entity\Extension\Treeable;
/**
* Category
*
* #ORM\Entity(repositoryClass="MD\Entity\Repository\CategoryRepository")
*
* #Gedmo\Tree(type="nested")
*/
class Category
{
/**
* Entity Extensions
*/
use Treeable;
/**
* The ID of the category
*
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* The title of the category
*
* #var string
*
* #ORM\Column(type="string", length=255)
*
* #Assert\NotBlank(message="category.title.not_blank")
* #Assert\Length(
* max=255,
* maxMessage="category.title.length.max"
* )
*/
protected $title;
/**
* The description of the category
*
* #var string
*
* #ORM\Column(type="text")
*
* #Assert\NotBlank(message="category.description.not_blank")
*/
protected $description;
/**
* The parent of the category
*
* #var Category
*
* #ORM\ManyToOne(targetEntity="Category", inversedBy="children")
* #ORM\JoinColumn(name="parent_id", referencedColumnName="id", onDelete="CASCADE")
*
* #Gedmo\TreeParent
*/
protected $parent;
/**
* The children of the category
*
* #var ArrayCollection
*
* #ORM\OneToMany(targetEntity="Category", mappedBy="parent", cascade={"persist"})
* #ORM\OrderBy({"left" = "ASC"})
*/
protected $children;
/**
* The slug of the category
*
* #var string
*
* #ORM\Column(type="string", length=255, unique=true)
*
* #Gedmo\Slug(handlers={
* #Gedmo\SlugHandler(class="Gedmo\Sluggable\Handler\TreeSlugHandler", options={
* #Gedmo\SlugHandlerOption(name="parentRelationField", value="parent"),
* #Gedmo\SlugHandlerOption(name="separator", value="/")
* })
* }, fields={"title"})
*/
protected $slug;
/**
* Constructor
*/
public function __construct()
{
$this->children = new ArrayCollection();
}
/**
* Get the ID of the category
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set the title of the category
*
* #param string $title
*
* #return $this
*/
public function setTitle($title)
{
$this->title = $title;
return $this;
}
/**
* Get the title of the category
*
* #return string
*/
public function getTitle()
{
return $this->title;
}
/**
* Set the description of the category
*
* #param string $description
*
* #return $this
*/
public function setDescription($description)
{
$this->description = $description;
return $this;
}
/**
* Get the description of the category
*
* #return string
*/
public function getDescription()
{
return $this->description;
}
/**
* Set the parent of the category
*
* #param Category $parent
*
* #return $this
*/
public function setParent(Category $parent = null)
{
$this->parent = $parent;
if (null !== $parent) {
$parent->addChild($this);
}
return $this;
}
/**
* Get the parent of the category
*
* #return Category
*/
public function getParent()
{
return $this->parent;
}
/**
* Add a child to the category
*
* #param Category $child
*
* #return $this
*/
public function addChild(Category $child = null)
{
if (!$this->children->contains($child)) {
$this->children->add($child);
$child->setParent($this);
}
return $this;
}
/**
* Get the children of the category
*
* #return ArrayCollection
*/
public function getChildren()
{
return $this->children;
}
/**
* Set the slug of the category
*
* #param string $slug
*
* #return $this
*/
public function setSlug($slug)
{
$this->slug = $slug;
return $this;
}
/**
* Get the slug of the category
*
* #return string
*/
public function getSlug()
{
return $this->slug;
}
/** Magic Methods */
/**
* Return a string representation of the category
*
* #return string
*/
public function __toString()
{
return $this->getTitle();
}
}
Given a category with a title of Bands and a sub-category with a title of Rock, the latter category, on creation, has a slug of bands/rock. This works as expected.
When I add the slug field to a form, however, when I edit the entity, I initially get bands/rock added to the form field. If I change this to bands/rock-and-roll and submit the form, the slug gets updated to bands/bands-rock-and-roll and not bands/rock-and-roll as I'd expect.
If I edit the category and set the slug field to rock-and-roll, then submit the form, the slug gets updated to bands/rock-and-roll. I'd expect the slug to be rock-and-roll after update.
What do I need to do to fix this behaviour? I essentially want the slug to be auto-generated with the handler if it's not provided, but to be set to exactly what I provide if I do provide it.
Thanks
looking at the docs of the Gedmo Tree Doctrine extension and it's relative code, it's not a wrong behaviour because the slug is composed accordingly with the "TreeSlugHandler" method = parentFieldName/field-You-Have-Inserted (that happens every time you edit the slug).
If you need at the same moment of a slug for a specific category and of another that follows the category tree you can add another property (ex: cat_slug) with the simple annotation: #Gedmo\Slug(fields={"fieldYouWantToSlug"}).
Remember that every time (using the "TreeSlugHandler" method) you edit the slug (changing the precedent), every subcategory will be updated with the new slug.
I hope I was helpful