I am using symfony 3 and trying to get the categories translated with mysql db. That's why I am using KnpLabs/DoctrineBehaviors, which should be the best for symfony.
I have done all like it is discribed in the documentation.
Category:
/**
* MdCategories
*
* #ORM\Table(name="md_category")
* #ORM\Entity(repositoryClass="AppBundle\Repository\CategoryRepository")
*/
class Category implements ORMBehaviors\Tree\NodeInterface, \ArrayAccess
{
use ORMBehaviors\Translatable\Translatable,
ORMBehaviors\Sortable\Sortable,
ORMBehaviors\Tree\Node;
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="NONE")
*/
protected $id;
CategoryTranslation:
/**
* #ORM\Table(name="md_category_translation")
* #ORM\Entity
*/
class CategoryTranslation
{
use ORMBehaviors\Translatable\Translation;
/**
* #var name
* #ORM\Column(type="string", length=120, nullable=false)
*/
protected $name;
/**
* #var route
*
* #ORM\Column(type="string", length=150)
*/
protected $route;
/**
* #var metaKey
*
* #ORM\Column(type="string", length=255)
*/
protected $metaKey;
/**
* #var metaTitle
*
* #ORM\Column(type="string", length=100)
*/
protected $metaTitle;
/**
* #var metaDescription
*
* #ORM\Column(type="string", length=120)
*/
protected $metaDescription;
/**
* #return name
*/
public function getName()
{
return $this->name;
}
/**
* #param name $name
* #return Categories
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* #return route
*/
public function getRoute()
{
return $this->route;
}
/**
* #param route $route
* #return Categories
*/
public function setRoute($route)
{
$this->route = $route;
return $this;
}
/**
* #return metaKey
*/
public function getMetaKey()
{
return $this->metaKey;
}
/**
* #param metaKey $metaKey
* #return Categories
*/
public function setMetaKey($metaKey)
{
$this->metaKey = $metaKey;
return $this;
}
/**
* #return metaTitle
*/
public function getMetaTitle()
{
return $this->metaTitle;
}
/**
* #param metaTitle $metaTitle
* #return Categories
*/
public function setMetaTitle($metaTitle)
{
$this->metaTitle = $metaTitle;
return $this;
}
/**
* #return metaDescription
*/
public function getMetaDescription()
{
return $this->metaDescription;
}
public function setMetaDescription($metaDescription)
{
$this->metaDescription = $metaDescription;
return $this;
}
public function __call($method, $arguments)
{
return $this->proxyCurrentLocaleTranslation($method, $arguments);
}
}
CategoryRepository:
class CategoryRepository extends EntityRepository
{
use ORMBehaviors\Tree\Tree;
}
config.yml:
knp_doctrine_behaviors:
translatable: true
tree: true
sortable: true
# All others behaviors are disabled
and registering the bundle
new Knp\DoctrineBehaviors\Bundle\DoctrineBehaviorsBundle(),
The databases are generated correctly
But how do I fill the categoryTranslation Data with the right local ?
$category = new Category;
$category->setCurrentLocale('de');
$category->setId(1); // tree nodes need an id to construct path.
$category->setName('Foobar');
$em->persist($category);
$em->flush();
This did not work !
I am surprised, that there is no KNP Translationsubscriber is listened in the subcribed events of symfony
Here is the solution.
$category = new Category;
$category->translate('de')->setName('Foobar');
$em->persist($category);
$category->mergeNewTranslations();
$em->flush();
Related
My symfony 2 project require to assign users to a company hierachy. So I try to use tree of StofDoctrineExtension bundle for this project. Here is my Entity class for "category":
<?php
namespace Application\Sonata\UserBundle\Entity;
use Doctrine\Common\Collections\ArrayCollection;
use Gedmo\Mapping\Annotation as Gedmo;
use Doctrine\ORM\Mapping as ORM;
/**
* #Gedmo\Tree(type="nested")
* #ORM\Table(name="category")
* #ORM\Entity(repositoryClass="Gedmo\Tree\Entity\Repository\NestedTreeRepository")
*/
class Category
{
/**
* #ORM\Column(type="integer")
* #ORM\Id
* #ORM\GeneratedValue
*/
private $id;
/**
* #ORM\Column(length=64)
*/
private $title;
/**
* #var integer
*
* #Gedmo\TreeLeft
* #ORM\Column(type="integer")
*/
private $treeLeft;
/**
* #var integer
*
* #Gedmo\TreeLevel
* #ORM\Column(type="integer")
*/
private $treeLevel;
/**
* #var integer
*
* #Gedmo\TreeRight
* #ORM\Column(type="integer")
*/
private $treeRight;
/**
* #Gedmo\TreeParent
* #ORM\ManyToOne(targetEntity="Category", inversedBy="children")
* #ORM\JoinColumn(name="parent_id", referencedColumnName="id", onDelete="CASCADE")
*/
private $parent;
/**
* #Gedmo\TreeRoot
* #ORM\Column(type="integer", nullable=true)
*/
private $root;
/**
* #ORM\OneToMany(targetEntity="Category", mappedBy="parent")
*/
private $children;
/**
* #ORM\OneToMany(targetEntity="User", mappedBy="category")
*/
private $users;
public function __toString()
{
return ($this->title) ? $this->title : '单位';
}
/**
* Constructor
*/
public function __construct()
{
$this->children = new \Doctrine\Common\Collections\ArrayCollection();
$this->users = new \Doctrine\Common\Collections\ArrayCollection();
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set title
*
* #param string $title
*
* #return Category
*/
public function setTitle($title)
{
$this->title = $title;
return $this;
}
/**
* Get title
*
* #return string
*/
public function getTitle()
{
return $this->title;
}
/**
* Get treeLeft
*
* #return integer
*/
public function getTreeLeft()
{
return $this->treeLeft;
}
/**
* Get treeLevel
*
* #return integer
*/
public function getTreeLevel()
{
return $this->treeLevel;
}
/**
* Get treeRight
*
* #return integer
*/
public function getTreeRight()
{
return $this->treeRight;
}
/**
* Get root
*
* #return integer
*/
public function getRoot()
{
return $this->root;
}
/**
* Set parent
*
* #param \Application\Sonata\UserBundle\Entity\Category $parent
*
* #return Category
*/
public function setParent(\Application\Sonata\UserBundle\Entity\Category $parent = null)
{
$this->parent = $parent;
return $this;
}
/**
* Get parent
*
* #return \Application\Sonata\UserBundle\Entity\Category
*/
public function getParent()
{
return $this->parent;
}
/**
* Get children
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getChildren()
{
return $this->children;
}
/**
* Add user
*
* #param \Application\Sonata\UserBundle\Entity\User $user
*
* #return Category
*/
public function addUser(\Application\Sonata\UserBundle\Entity\User $user)
{
$this->users[] = $user;
return $this;
}
/**
* Remove user
*
* #param \Application\Sonata\UserBundle\Entity\User $user
*/
public function removeUser(\Application\Sonata\UserBundle\Entity\User $user)
{
$this->users->removeElement($user);
}
/**
* Get users
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getUsers()
{
return $this->users;
}
}
and my CategoryAdmin.php:
......
/**
* {#inheritdoc}
*/
protected function configureFormFields(FormMapper $formMapper)
{
$formMapper
->add('title')
->add('parent', 'entity', array(
'class' => 'Application\Sonata\UserBundle\Entity\Category', // tree class
'query_builder' => function($er) {
return $er->createQueryBuilder('c')
->orderBy('c.treeLeft', 'ASC');
},
'required' => false,
))
;
}
When I created an category entity, only parent and root value are correctly set, treeLeft, treeRight and treeLevel are zero. I check the sample in the document, it did mention someting about eventlistener. Should I add an eventlestener for this? and How? Thanks for any help.
After I deleted all records and create new one, it works.
I tried very hard to get the KNP Paginator to work.
I only want to oder an Entity to the id, but the pagination accept all the params but does noting with it!
Here´s my code:
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
The Controller class:
class StartController extends Controller
{
public function indexAction(Request $request)
{
$em = $this->getDoctrine()->getManager();
$dql = "SELECT a FROM MainArtBundle:Art a";
$query = $em->createQuery($dql);
$paginator = $this->get('knp_paginator');
$pagination = $paginator->paginate(
$query,
$request->query->get('page', 1) /*page number*/,
8 /*limit per page*/
);
$pagination->setUsedRoute('homepage');
if (!$pagination) {
throw $this->createNotFoundException('Unable to find Art entities.');
}
return $this->render('MainShowBundle:Default:index.html.twig', array(
'pagination' => $pagination,
));
}
The Twig Template:
<li>{{ knp_pagination_sortable(pagination, 'Oldest', 'a.id', {'direction': 'desc'}) }}</li>
<li>{{ knp_pagination_sortable(pagination, 'Newest', 'a.id', {'direction': 'asc'}) }}</li>
The ArtEntity (the entire Entity because perhaps the mistake is caused by the entity, can it be)
<?php
namespace Main\ArtBundle\Entity;
use Gedmo\Mapping\Annotation as Gedmo;
use Doctrine\ORM\Mapping as ORM;
use Main\LikeBundle\Entity\Thumb;
use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Component\HttpFoundation\Request;
/**
* Art
*
* #ORM\Table(name="art")
* #ORM\Entity(repositoryClass="Main\ArtBundle\Entity\ArtRepository")
*/
class Art
{
/**
* #var integer $id
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string $locale
*
* #ORM\Column(name="locale", type="string", length=5, nullable=false)
*/
protected $locale;
/**
* #var arrayCollection $user
*
* #ORM\ManyToOne(targetEntity="Main\UserBundle\Entity\User", inversedBy="arts")
*
*/
protected $user;
/**
* #var \Doctrine\Common\Collections\ArrayCollection $visits
*
* #ORM\OneToMany(targetEntity="Main\ArtBundle\Entity\ArtVisit", mappedBy="art", fetch="EXTRA_LAZY")
*
*/
protected $visits;
/**
* #var \Doctrine\Common\Collections\ArrayCollection $tags
*
* #ORM\ManyToMany(targetEntity="Tags", inversedBy="arts", cascade={"persist"})
*/
protected $tags;
/**
* #var \Doctrine\Common\Collections\ArrayCollection $feature_partner
* #ORM\ManyToMany(targetEntity="Main\UserBundle\Entity\User", inversedBy="feature_partner")
*
*/
protected $feature_partner;
/**
* #var string $headline
*
* #Assert\NotBlank()
*
* #ORM\Column(type="string", length=255, unique=false, nullable=false)
*/
protected $headline;
/**
* #var \Main\StorageBundle\Entity\Image
*
* #ORM\OneToOne(targetEntity="Main\StorageBundle\Entity\Image")
* #ORM\Column(nullable=true)
*/
protected $image;
/**
* #var string $content
*
* #Assert\NotBlank()
*
* #ORM\Column(type="text", unique=false, nullable=false)
*/
protected $content;
/**
* #var string $description
*
* #ORM\Column(type="text", unique=false, nullable=true)
*/
protected $description;
/**
* #var datetime $created
*
* #Gedmo\Timestampable(on="create")
* #ORM\Column(type="datetime")
*/
private $created;
/**
* #var datetime $updated
*
* #Gedmo\Timestampable(on="update")
* #ORM\Column(type="datetime")
*/
private $updated;
/**
* #var datetime $contentChanged
*
* #ORM\Column(name="content_changed", type="datetime", nullable=true)
* #Gedmo\Timestampable(on="change", field={"headline", "content"})
*/
private $contentChanged;
/**
* #var integer $viewed
*
* #ORM\Column(name="viewed", type="integer", nullable=true)
*/
private $viewed;
/**
* #var object $CommentThread
*
*/
private $thread_id;
/**
* #var \Doctrine\Common\Collections\ArrayCollection $thumbs
*
* #ORM\OneToMany(targetEntity="Main\LikeBundle\Entity\Thumb", mappedBy="entity", fetch="EXTRA_LAZY")
*/
private $thumbs;
/**
* Constructor.
*/
public function __construct()
{
$this->tags = new \Doctrine\Common\Collections\ArrayCollection();
$this->feature_partner = new \Doctrine\Common\Collections\ArrayCollection();
$this->thumbs = new \Doctrine\Common\Collections\ArrayCollection();
$this->commentThread = new \Main\ArtBundle\Entity\CommentThread($this->getId());
/*$request = new Request();
$this->locale = $request->getLocale()*/;
}
/**
* #return string
*/
public function __toString()
{
return $this->getHeadline();
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set user
*
* #param integer $userId
* #return Art
*/
public function setUserId($userId)
{
$this->user = $userId;
return $this;
}
/**
* Get user
*
* #return integer
*/
public function getUserId()
{
return $this->user;
}
/**
* Set tags
*
* #param integer $tags
* #return Art
*/
public function setTags($tags)
{
$this->tags = $tags;
return $this;
}
/**
* Get tags
*
* #return integer
*/
public function getTags()
{
return $this->tags;
}
/**
* Set headline
*
* #param string $headline
* #return Art
*/
public function setHeadline($headline)
{
$this->headline = $headline;
return $this;
}
/**
* Get headline
*
* #return string
*/
public function getHeadline()
{
return $this->headline;
}
/**
* Set content
*
* #param string $content
* #return Art
*/
public function setContent($content)
{
$this->content = $content;
return $this;
}
/**
* Get content
*
* #return string
*/
public function getContent()
{
return $this->content;
}
/**
* Set created
*
* #param \DateTime $created
* #return Art
*/
public function setCreated($created)
{
$this->created = $created;
return $this;
}
/**
* Get created
*
* #return \DateTime
*/
public function getCreated()
{
return $this->created;
}
/**
* Set updated
*
* #param \DateTime $updated
* #return Art
*/
public function setUpdated($updated)
{
$this->updated = $updated;
return $this;
}
/**
* Get updated
*
* #return \DateTime
*/
public function getUpdated()
{
return $this->updated;
}
/**
* Set contentChanged
*
* #param \DateTime $contentChanged
* #return Art
*/
public function setContentChanged($contentChanged)
{
$this->contentChanged = $contentChanged;
return $this;
}
/**
* Get contentChanged
*
* #return \DateTime
*/
public function getContentChanged()
{
return $this->contentChanged;
}
/**
* Set feature_partner
*
* #param integer $featurePartner
* #return Art
*/
public function setFeaturePartner($featurePartner)
{
$this->feature_partner = $featurePartner;
return $this;
}
/**
* Get feature_partner
*
* #return \Doctrine\Common\Collections\ArrayCollection
*/
public function getFeaturePartner()
{
return $this->feature_partner;
}
/**
* Add feature_partner
*
* #param \Main\UserBundle\Entity\User $featurePartner
* #return Art
*/
public function addFeaturePartner(\Main\UserBundle\Entity\User $featurePartner)
{
$this->feature_partner[] = $featurePartner;
return $this;
}
/**
* Remove feature_partner
*
* #param \Main\UserBundle\Entity\User $featurePartner
*/
public function removeFeaturePartner(\Main\UserBundle\Entity\User $featurePartner)
{
$this->feature_partner->removeElement($featurePartner);
}
/**
* Set description
*
* #param string $description
* #return Art
*/
public function setDescription($description)
{
$this->description = $description;
return $this;
}
/**
* Get description
*
* #return string
*/
public function getDescription()
{
return $this->description;
}
/**
* Set user
*
* #param \Main\UserBundle\Entity\User $user
* #return Art
*/
public function setUser(\Main\UserBundle\Entity\User $user = null)
{
$this->user = $user;
return $this;
}
/**
* Get user
*
* #return \Main\UserBundle\Entity\User
*/
public function getUser()
{
return $this->user;
}
/**
* Add tags
*
* #param \Main\ArtBundle\Entity\Tags $tags
* #return Art
*/
public function addTag(\Main\ArtBundle\Entity\Tags $tags)
{
$this->tags[] = $tags;
return $this;
}
/**
* Remove tags
*
* #param \Main\ArtBundle\Entity\Tags $tags
*/
public function removeTag(\Main\ArtBundle\Entity\Tags $tags)
{
$this->tags->removeElement($tags);
}
/**
* Add visits
*
* #param \Main\ArtBundle\Entity\ArtVisit $visits
* #return Art
*/
public function addVisit(\Main\ArtBundle\Entity\ArtVisit $visits)
{
$this->visits[] = $visits;
return $this;
}
/**
* Remove visits
*
* #param \Main\ArtBundle\Entity\ArtVisit $visits
*/
public function removeVisit(\Main\ArtBundle\Entity\ArtVisit $visits)
{
$this->visits->removeElement($visits);
}
/**
* Get visits
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getVisits()
{
return $this->visits;
}
/**
* Set locale
*
* #param string $locale
* #return Art
*/
public function setLocale($locale)
{
$this->locale = $locale;
return $this;
}
/**
* Get locale
*
* #return string
*/
public function getLocale()
{
return $this->locale;
}
/**
* Set image
*
* #param \Main\StorageBundle\Entity\Image $image
* #return Art
*/
public function setImage(\Main\StorageBundle\Entity\Image $image = null)
{
$this->image = $image;
return $this;
}
/**
* Get image
*
* #return \Main\StorageBundle\Entity\Image
*/
public function getImage()
{
return $this->image;
}
/**
* Set viewed
*
* #param integer $viewed
* #return Art
*/
public function setViewed($viewed)
{
$this->viewed = $viewed;
return $this;
}
/**
* Get viewed
*
* #return integer
*/
public function getViewed()
{
return $this->viewed;
}
/**
* Set thumbs
*
* #param \Main\LikeBundle\Entity\Thumb $thumbs
* #return Art
*/
public function setThumbs(Thumb $thumbs = null)
{
$this->thumbs = $thumbs;
return $this;
}
/**
* Get thumbs
*
* #return \Doctrine\Common\Collections\ArrayCollection $thumbs
*/
public function getThumbs()
{
return $this->thumbs;
}
/**
* Add thumb
*
* #param \Main\LikeBundle\Entity\Thumb $thumb
* #return $this $thumbs
*/
public function addThumb(Thumb $thumb)
{
$this->thumbs[] = $thumb;
return $this;
}
/**
* Remove thumbs
*
* #param \Main\LikeBundle\Entity\Thumb $thumbs
*/
public function removeThumb(\Main\LikeBundle\Entity\Thumb $thumbs)
{
$this->thumbs->removeElement($thumbs);
}
/**
* Count all Thumbs of the piece of art.
*/
public function countAllThumbs() {
return $this->thumbs->count();
}
/**
* Check weather a user has thumbed a piece of art or not.
*/
public function isThumbed($user) {
// my first Closure :D
$p = function($key, $element) use ($user) {
return $element->getUser() == $user;
};
return $this->thumbs->exists($p);
}
/**
* Get the thumb object from a special user.
*/
public function getThumbFromUser ($user) {
$p = function($element) use ($user) {
return $element->getUser() == $user;
};
return $this->thumbs->filter($p);
}
}
The KNP Pagination Configuration (in config.yml)
knp_paginator:
page_range: 5 # default page range used in pagination control
default_options:
page_name: page # page query parameter name
sort_field_name: sort # sort field query parameter name
sort_direction_name: direction # sort direction query parameter name
distinct: true # ensure distinct results, useful when ORM queries are using GROUP BY statements
template:
pagination: ::Pagination\twitter_bootstrap_v3_pagination.html.twig # sliding pagination controls template
sortable: ::Pagination\sortable_link.html.twig # sort link template
I have dumped the pagination object in the controller and in the template as well. Everytime the params are there (direction= asc or desc) something like this is in the url:
?sort=a.id&direction=desc&page=1
but if I click on the link to change the direction: nothing change!!
I believe the knp pagination has a bug! Or I am very stupid ;)
If anyone can help me, I will be very happy!
Greetings Michael
For me, I created a new file knp_paginator.yaml and not knp_paginator.yml and I added this configuration and evrything works:
knp_paginator:
page_range: 5 # number of links shown in the pagination menu (e.g: you have 10 pages, a page_range of 3, on the 5th page you'll see links to page 4, 5, 6)
default_options:
page_name: page # page query parameter name
sort_field_name: sort # sort field query parameter name
sort_direction_name: direction # sort direction query parameter name
distinct: true # ensure distinct results, useful when ORM queries are using GROUP BY statements
filter_field_name: filterField # filter field query parameter name
filter_value_name: filterValue # filter value query parameter name
template:
pagination: '#KnpPaginator/Pagination/twitter_bootstrap_v4_pagination.html.twig' # sliding pagination controls template
sortable: '#KnpPaginator/Pagination/sortable_link.html.twig' # sort link template
filtration: '#KnpPaginator/Pagination/filtration.html.twig' # filters template
I'm lost in a complexe relation (for me). I've a entity project for an entity client and you can attach users to a project. When i try to add a project without users, no problem. But, when i try to add a project and users Sf2 display this error :
Entity of type Intranet\IntranetBundle\Entity\ProjectUser is missing an assigned ID for field 'project'. The identifier generation strategy for this entity requires the ID field to be populated before EntityManager#persist() is called. If you want automatically generated identifiers instead you need to adjust the metadata mapping accordingly.
I'm understand it's angry because the project_id is null. But i don't know why it's null.
My Project.php
namespace Intranet\IntranetBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Gedmo\Mapping\Annotation as Gedmo;
use Symfony\Component\Validator\Constraints as Assert;
/**
* Project
*
* #ORM\Table()
* #ORM\Entity(repositoryClass="Intranet\IntranetBundle\Entity\ProjectRepository")
*/
class Project
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="name", type="string", length=255)
* #Assert\NotBlank(
* message = "The field cannot be empty"
* )
*/
private $name;
/**
* #Gedmo\Slug(fields={"name"})
* #ORM\Column(length=255, unique=true)
*/
private $slug;
/**
* #var string
*
* #ORM\Column(name="contact_client", type="text", nullable=true)
*/
private $contactClient;
/**
* #var string
*
* #ORM\Column(name="technologies", type="string", length=255, nullable=true)
*/
private $technologies;
/**
* #var string
*
* #ORM\Column(name="languages", type="string", length=255, nullable=true)
*/
private $languages;
/**
* #var string
*
* #ORM\Column(name="extern", type="text", nullable=true)
*/
private $extern;
/**
* #var string
*
* #ORM\Column(name="url_prod", type="string", length=255, nullable=true)
*/
private $urlProd;
/**
* #var string
*
* #ORM\Column(name="url_staging", type="text", nullable=true)
*/
private $urlStaging;
/**
* #var string
*
* #ORM\Column(name="url_dev", type="text", nullable=true)
*/
private $urlDev;
/**
* #var string
*
* #ORM\Column(name="hosting_company", type="string", length=255, nullable=true)
*/
private $hostingCompany;
/**
* #var string
*
* #ORM\Column(name="hosting_type", type="string", length=255, nullable=true)
*/
private $hostingType;
/**
* #var string
*
* #ORM\Column(name="hosting_manager", type="text", nullable=true)
*/
private $hostingManager;
/**
* #var string
*
* #ORM\Column(name="ssh", type="text", nullable=true)
*/
private $ssh;
/**
* #var string
*
* #ORM\Column(name="ftp", type="text", nullable=true)
*/
private $ftp;
/**
* #var string
*
* #ORM\Column(name="db", type="text", nullable=true)
*/
private $db;
/**
* #var string
*
* #ORM\Column(name="emails", type="text", nullable=true)
*/
private $emails;
/**
* #var string
*
* #ORM\Column(name="cms", type="text", nullable=true)
*/
private $cms;
/**
* #var string
*
* #ORM\Column(name="web_services", type="text", nullable=true)
*/
private $webServices;
/**
* #var string
*
* #ORM\Column(name="comment", type="text", nullable=true)
*/
private $comment;
/**
* #ORM\ManyToOne(targetEntity="Intranet\IntranetBundle\Entity\Client", inversedBy="projects")
* #ORM\JoinColumn(nullable=false)
*/
private $client;
/**
* #ORM\OneToMany(targetEntity="Intranet\IntranetBundle\Entity\ProjectUser", mappedBy="project", cascade={"persist"})
*/
private $projectUsers;
public function __construct()
{
$this->projectUsers = new \Doctrine\Common\Collections\ArrayCollection();
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set name
*
* #param string $name
* #return Project
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*
* #return string
*/
public function getName()
{
return $this->name;
}
/**
* Set slug
*
* #param string $slug
* #return Client
*/
public function setSlug($slug)
{
$this->slug = $slug;
return $this;
}
/**
* Get slug
*
* #return string
*/
public function getSlug()
{
return $this->slug;
}
/**
* Set contactClient
*
* #param string $contactClient
* #return Project
*/
public function setContactClient($contactClient)
{
$this->contactClient = $contactClient;
return $this;
}
/**
* Get contactClient
*
* #return string
*/
public function getContactClient()
{
return $this->contactClient;
}
/**
* Set technologies
*
* #param string $technologies
* #return Project
*/
public function setTechnologies($technologies)
{
$this->technologies = $technologies;
return $this;
}
/**
* Get technologies
*
* #return string
*/
public function getTechnologies()
{
return $this->technologies;
}
/**
* Set languages
*
* #param string $languages
* #return Project
*/
public function setLanguages($languages)
{
$this->languages = $languages;
return $this;
}
/**
* Get languages
*
* #return string
*/
public function getLanguages()
{
return $this->languages;
}
/**
* Set extern
*
* #param string $extern
* #return Project
*/
public function setExtern($extern)
{
$this->extern = $extern;
return $this;
}
/**
* Get extern
*
* #return string
*/
public function getExtern()
{
return $this->extern;
}
/**
* Set urlProd
*
* #param string $urlProd
* #return Project
*/
public function setUrlProd($urlProd)
{
$this->urlProd = $urlProd;
return $this;
}
/**
* Get urlProd
*
* #return string
*/
public function getUrlProd()
{
return $this->urlProd;
}
/**
* Set urlStaging
*
* #param string $urlStaging
* #return Project
*/
public function setUrlStaging($urlStaging)
{
$this->urlStaging = $urlStaging;
return $this;
}
/**
* Get urlStaging
*
* #return string
*/
public function getUrlStaging()
{
return $this->urlStaging;
}
/**
* Set urlDev
*
* #param string $urlDev
* #return Project
*/
public function setUrlDev($urlDev)
{
$this->urlDev = $urlDev;
return $this;
}
/**
* Get urlDev
*
* #return string
*/
public function getUrlDev()
{
return $this->urlDev;
}
/**
* Set hostingCompany
*
* #param string $hostingCompany
* #return Project
*/
public function setHostingCompany($hostingCompany)
{
$this->hostingCompany = $hostingCompany;
return $this;
}
/**
* Get hostingCompany
*
* #return string
*/
public function getHostingCompany()
{
return $this->hostingCompany;
}
/**
* Set hostingType
*
* #param string $hostingType
* #return Project
*/
public function setHostingType($hostingType)
{
$this->hostingType = $hostingType;
return $this;
}
/**
* Get hostingType
*
* #return string
*/
public function getHostingType()
{
return $this->hostingType;
}
/**
* Set hostingManager
*
* #param string $hostingManager
* #return Project
*/
public function setHostingManager($hostingManager)
{
$this->hostingManager = $hostingManager;
return $this;
}
/**
* Get hostingManager
*
* #return string
*/
public function getHostingManager()
{
return $this->hostingManager;
}
/**
* Set ssh
*
* #param string $ssh
* #return Project
*/
public function setSsh($ssh)
{
$this->ssh = $ssh;
return $this;
}
/**
* Get ssh
*
* #return string
*/
public function getSsh()
{
return $this->ssh;
}
/**
* Set ftp
*
* #param string $ftp
* #return Project
*/
public function setFtp($ftp)
{
$this->ftp = $ftp;
return $this;
}
/**
* Get ftp
*
* #return string
*/
public function getFtp()
{
return $this->ftp;
}
/**
* Set db
*
* #param string $db
* #return Project
*/
public function setDb($db)
{
$this->db = $db;
return $this;
}
/**
* Get db
*
* #return string
*/
public function getDb()
{
return $this->db;
}
/**
* Set emails
*
* #param string $emails
* #return Project
*/
public function setEmails($emails)
{
$this->emails = $emails;
return $this;
}
/**
* Get emails
*
* #return string
*/
public function getEmails()
{
return $this->emails;
}
/**
* Set cms
*
* #param string $cms
* #return Project
*/
public function setCms($cms)
{
$this->cms = $cms;
return $this;
}
/**
* Get cms
*
* #return string
*/
public function getCms()
{
return $this->cms;
}
/**
* Set webServices
*
* #param string $webServices
* #return Project
*/
public function setWebServices($webServices)
{
$this->webServices = $webServices;
return $this;
}
/**
* Get webServices
*
* #return string
*/
public function getWebServices()
{
return $this->webServices;
}
/**
* Set comment
*
* #param string $comment
* #return Project
*/
public function setComment($comment)
{
$this->comment = $comment;
return $this;
}
/**
* Get comment
*
* #return string
*/
public function getComment()
{
return $this->comment;
}
/**
* Set client
*
* #param \Intranet\IntranetBundle\Entity\Client $client
* #return Project
*/
public function setClient(\Intranet\IntranetBundle\Entity\Client $client)
{
$this->client = $client;
return $this;
}
/**
* Get client
*
* #return \Intranet\IntranetBundle\Entity\Client
*/
public function getClient()
{
return $this->client;
}
public function addProjectUser(\Intranet\IntranetBundle\Entity\ProjectUser $projectUser)
{
$this->projectUsers[] = $projectUser;
}
public function removeProjectUser(\Intranet\IntranetBundle\Entity\ProjectUser $projectUser)
{
$this->projectUsers->removeElement($projectUser);
}
public function getProjectUsers()
{
return $this->projectUsers;
}
}
My ProjectUser.php
namespace Intranet\IntranetBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity
*/
class ProjectUser
{
/**
* #ORM\Id
* #ORM\ManyToOne(targetEntity="Intranet\IntranetBundle\Entity\Project", inversedBy="projectUsers")
*/
private $project;
/**
* #ORM\Id
* #ORM\ManyToOne(targetEntity="Intranet\UserBundle\Entity\User")
*/
private $user;
/**
* #ORM\Column(name="profil", type="smallint")
*/
private $profil;
public function setProject(\Intranet\IntranetBundle\Entity\Project $project)
{
$project->addProjectUser($this);
$this->project = $project;
}
public function getProject()
{
return $this->project;
}
public function setUser(\Intranet\UserBundle\Entity\User $user)
{
$this->user = $user;
}
public function getUser()
{
return $this->user;
}
public function setProfil($profil)
{
$this->profil = $profil;
}
public function getProfil()
{
return $this->profil;
}
}
profil = smallint for the job of the user (1=manager, 2=designer, ...)
My ProjectController (addAction)
public function addAction()
{
$project = new Project;
$form = $this->createForm(new ProjectType, $project);
$request = $this->get('request');
if ($request->getMethod() == 'POST') {
$form->bind($request);
if ($form->isValid()) {
$em = $this->getDoctrine()->getManager();
$em->persist($project);
$em->flush();
foreach ($form->get('projectUsers')->getData() as $u) {
$u->setProject($project);
$em->persist($u);
}
$em->flush();
$this->get('session')->getFlashBag()->add('success', 'The project : '. $project->getName() .' has been added');
return $this->redirect($this->generateUrl('clients_list'));
}
}
return $this->render('IntranetIntranetBundle:Project:add_project.html.twig', array(
'form' => $form->createView()
));
}
Thanks for your help
Well, first of all, you shouldn't specify #ORM\Id annotation on every foreign key in your ProjectUser entity - it is for primary keys.
Then you should declare column join on foreign key fields:
/**
* #ORM\ManyToOne(targetEntity="Intranet\IntranetBundle\Entity\Project", inversedBy="projectUsers")
* #ORM\JoinColumn(name="project_id", referencedColumnName="id")
*/
private $project;
/**
* #ORM\ManyToOne(targetEntity="Intranet\IntranetBundle\Entity\User", inversedBy="projects")
* #ORM\JoinColumn(name="user_id", referencedColumnName="id")
*/
private $user;
You also should have a field like
class User
{
// ...
/**
* #ORM\OneToMany(targetEntity="Intranet\IntranetBundle\Entity\ProjectUser", mappedBy="user")
*/
private $projects;
// ...
}
Finally, to add user to project, I suggest you embed a ProjectUserType form with user selection into ProjectType form. In your controller, you can have something like
public function addAction()
{
$project = new Project;
$projectUser = new ProjectUser();
$projectUser->setProject($project);
$project->addProjectUser($projectUser);
$form = $this->createForm(new ProjectType, $project);
// ...
And in form ProjectUserType
class ProjectUserType extends AbstractType {
public function buildForm(FormBuilderInterface $builder, array $options) {
$builder->add('user', 'entity', array(
'class' => 'Intranet:IntranetBundle:User'
));
// ...
Hope this helps at least a little bit.
When you code : $em->persist($project);
$project is equal to $project = new Project; (don't you have forget '()' ?)
Actually the $projet is empty... To do this, I think you forget to code :
$project = $form->getData();
I use FOSUserBundle and 'group' function
At first in my User.php
There were such getter and setter
/**
* Add groups
*
* #param \Acme\UserBundle\Entity\Group $groups
* #return User
*/
public function addGroup(\Acme\UserBundle\Entity\Group $groups)
{
$this->groups[] = $groups;
return $this;
}
/**
* Remove groups
*
* #param \Acme\UserBundle\Entity\Group $groups
*/
public function removeGroup(\Acme\UserBundle\Entity\Group $groups)
{
$this->groups->removeElement($groups);
}
/**
* Get groups
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getGroups()
{
return $this->groups;
}
but,this error happens
FatalErrorException: Compile Error: Declaration of Acme\UserBundle\Entity\User::addGroup() must be compatible with that of FOS\UserBundle\Model\GroupableInterface::addGroup()
in FOS\UserBundle\Model\GroupableInterface
public function addGroup(GroupInterface $group);
in my Acme\UserBundle\Entity\User
public function addGroup(\Acme\UserBundle\Entity\Group $groups)
{
$this->groups[] = $groups;
return $this;
}
How can I adjust the argument type or correct this error?
For now,I have commented out these three function.
at that time it looked works well.
But now ,I use Sonataadmin bundle and in
#SonataAdminBundle/Admin/UserAdmin.php
protected function configureFormFields(FormMapper $formMapper){
$formMapper
->with('General')
->add('groups','entity',array('property' => 'name',
'multiple' => true,
'class' => 'UserBundle:Group',
))
}
it shows this form correctly but when I push submit button to regist,
it shows
Error: Call to a member function contains() on a non-object in ~~~/FOS/UserBundle/Model/User.php line 572
in /FOS/UserBundle/Model/user.php
there is function likt this
public function addGroup(GroupInterface $group)
{
var_dump($group);# I added to check
if (!$this->getGroups()->contains($group)) {
$this->getGroups()->add($group);
}
return $this;
}
var_dump($group) shows
object(Acme\UserBundle\Entity\Group)#923 (3) { ["id":protected]=> int(2) ["name":protected]=> string(12) "TeacherGroup" ["roles":protected]=> array(0) { } }
I guess it has group information correctly..
How can I fix this problem?
my whole user.php
// src/Acme/UserBundle/Entity/User.php
namespace Acme\UserBundle\Entity;
use FOS\UserBundle\Entity\User as BaseUser;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
use FOS\UserBundle\Model\GroupableInterface;
/**
* #ORM\Entity
* #ORM\Table(name="fos_user")
* #ORM\HasLifecycleCallbacks
*/
class User extends BaseUser
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*
*/
protected $id;
/**
*
* #ORM\OneToOne(targetEntity="Acme\UserBundle\Entity\Lesson", mappedBy="teacher")
*/
private $LessonAsTeacher;
/**
*
* #ORM\OneToMany(targetEntity="Acme\UserBundle\Entity\Lesson", mappedBy="student*removethis : name of the variable in Lesson.php*")
*/
private $LessonAsStudent;
/**
*
* #ORM\ManyToOne(targetEntity="Acme\UserBundle\Entity\Sex", inversedBy="sex*removethis : name of the variable in user.php*")
* #ORM\JoinColumn(name="sex", referencedColumnName="id",nullable=false)
*/
private $sex;
/**
* #ORM\ManyToMany(targetEntity="Acme\UserBundle\Entity\Group")
* #ORM\JoinTable(name="fos_user_user_group",
* joinColumns={#ORM\JoinColumn(name="user_id", referencedColumnName="id")},
* inverseJoinColumns={#ORM\JoinColumn(name="group_id", referencedColumnName="id")}
* )
*/
protected $groups;
/**
* #ORM\Column(type="string", length=255)
*
* #Assert\NotBlank(message="Please enter your first name.", groups={"Registration", "Profile"})
* #Assert\MinLength(limit="0", message="The name is too short.", groups={"Registration", "Profile"})
* #Assert\MaxLength(limit="255", message="The name is too long.", groups={"Registration", "Profile"})
*/
protected $firstname;
/**
* #ORM\Column(type="string", length=255)
*
* #Assert\NotBlank(message="Please enter your last name.", groups={"Registration", "Profile"})
* #Assert\MinLength(limit="0", message="The name is too short.", groups={"Registration", "Profile"})
* #Assert\MaxLength(limit="255", message="The name is too long.", groups={"Registration", "Profile"})
*/
protected $lastname;
/**
* #ORM\Column(type="date")
*/
protected $birthday;
/**
* #var \DateTime
*
* #ORM\Column(name="createdAt", type="datetime")
*/
private $createdAt;
/**
* #var \DateTime
*
* #ORM\Column(name="updatedAt", type="datetime")
*/
private $updatedAt;
public function __construct()
{
parent::__construct();
// your own logic
}
public function getFirstname()
{
return $this->firstname;
}
public function setFirstname($name)
{
$this->firstname = $name;
return $this;
}
public function getLastname()
{
return $this->lastname;
}
public function setLastname($name)
{
$this->lastname = $name;
return $this;
}
public function getSex()
{
return $this->sex;
}
public function setSex($sex)
{
$this->sex = $sex;
return $this;
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set age
*
* #param integer $age
* #return User
*/
public function setAge($age)
{
$this->age = $age;
return $this;
}
/**
* Get age
*
* #return integer
*/
public function getAge()
{
return $this->age;
}
/**
* Set birthday
*
* #param \DateTime $birthday
* #return User
*/
public function setBirthday($birthday)
{
$this->birthday = $birthday;
return $this;
}
/**
* Get birthday
*
* #return \DateTime
*/
public function getBirthday()
{
return $this->birthday;
}
/**
* #ORM\PrePersist
*/
public function prePersist()
{
$this->createdAt = new \DateTime;
$this->updatedAt = new \DateTime;
}
/**
* #ORM\PreUpdate
*/
public function preUpdate()
{
$this->updatedAt = new \DateTime;
}
/**
* Set createdAt
*
* #param \DateTime $createdAt
* #return User
*/
public function setCreatedAt($createdAt)
{
$this->createdAt = $createdAt;
return $this;
}
/**
* Get createdAt
*
* #return \DateTime
*/
public function getCreatedAt()
{
return $this->createdAt;
}
/**
* Set updatedAt
*
* #param \DateTime $updatedAt
* #return User
*/
public function setUpdatedAt($updatedAt)
{
$this->updatedAt = $updatedAt;
return $this;
}
/**
* Get updatedAt
*
* #return \DateTime
*/
public function getUpdatedAt()
{
return $this->updatedAt;
}
/**
* Get groups
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getGroups()
{
return $this->groups;
}
/**
* Add groups
*
* #param \Acme\UserBundle\Entity\Group $groups
* #return User
*/
// public function addGroup(\Acme\UserBundle\Entity\Group $groups)
// {
// $this->groups[] = $groups;
// return $this;
// }
/**
* Remove groups
*
* #param \Acme\UserBundle\Entity\Group $groups
*/
// public function removeGroup(\Acme\UserBundle\Entity\Group $groups)
// {
// $this->groups->removeElement($groups);
// }
}
my whole Group.php
namespace Acme\UserBundle\Entity;
use FOS\UserBundle\Entity\Group as BaseGroup;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity
* #ORM\Table(name="fos_group")
*/
class Group extends BaseGroup
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
}
The problem is that you override getGroups() like this:
/**
* Get groups
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getGroups()
{
return $this->groups;
}
But you never initialized $this->groups, so when you call $this->getGroups()->contains(), it says that $this->getGroups() is a non-object, which is true!
To solve this you have 2 solutions.
You can initialize groups in the constructor of User:
public function __construct()
{
parent::__construct();
&this->groups = new ArrayCollection();
}
Or you can change the getGroups() function to return a new object if groups hasn't been initialized:
public function getGroups()
{
return $this->groups ?: $this->groups = new ArrayCollection();
}
In both cases, don't forget to add use Doctrine\Common\Collections\ArrayCollection; at the beginning of User.php.
I got the same error:
FatalErrorException: Compile Error: Declaration of Acme\UserBundle\Entity\User::addGroup() must be compatible with that of FOS\UserBundle\Model\GroupableInterface::addGroup()
After searching I found out (FOS Git Issue 988) that this special error is a Doctrine 'Bug' or sth.
Doctrine should not generate the method at all because there is an implementation of addGroup() in the base class.
I worked around it by modifying the signature from
public function addGroup(\MyBundleNamespace\Entity\Group $groups)
public function removeGroup(\MyBundleNamespace\Entity\Group $groups)
to
public function addGroup(\FOS\UserBundle\Model\GroupInterface $groups)
public function removeGroup(\FOS\UserBundle\Model\GroupInterface $groups)
This way you prevent Doctrine from generating these two functions with the wrong signature.
Version Infos:
Symfony 2.2.1
DoctrineORM 2.2.3
FOSUserBundle 1.3.1
PHP 5.4.4-14
Maybe this can help someone else!
I came across this problem and the simple solution was to change the declaration of the groups variable from public to protected:
/**
* #var \Doctrine\Common\Collections\Collection
*/
protected $groups;
solution is simply: remove all setters and getters from your own entity in your own userBundle and always run doctrine:generate:entities for specyfic bundle, not for all.
Reading this page I've setup a form to handle PATCH requests.
I've a Player entity:
<?php
namespace Acme\PlayerBundle\Entity;
use Symfony\Component\Validator\Constraints as Assert;
use Doctrine\ORM\Mapping as ORM;
/**
* Acme\PlayerBundle\Entity\Player
*
* #ORM\Table()
* #ORM\Entity(repositoryClass="Acme\PlayerBundle\Entity\PlayerRepository")
*/
class Player
{
/**
* #var integer $id
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string $name
*
* #ORM\Column(name="name", type="string", length=255)
* #Assert\NotBlank()
*/
private $name;
/**
* #ORM\ManyToOne(targetEntity="Acme\UserBundle\Entity\User", inversedBy="players")
* #ORM\JoinColumn(nullable=false)
*/
private $owner;
/**
* #ORM\ManyToOne(targetEntity="Acme\TeamBundle\Entity\Team", inversedBy="players")
* #ORM\JoinColumn(nullable=false)
* #Assert\NotBlank()
*/
private $team;
/**
* #var integer $shirtNumber
*
* #ORM\Column(name="shirtNumber", type="smallint")
* #Assert\NotBlank()
*/
private $shirtNumber;
/**
* #var integer $vsid
*
* #ORM\Column(name="vsid", type="integer", nullable=true)
*/
private $vsid;
/**
* #var string $firstname
*
* #ORM\Column(name="firstname", type="string", length=255, nullable=true)
*/
private $firstname;
/**
* #var string $lastname
*
* #ORM\Column(name="lastname", type="string", length=255, nullable=true)
*/
private $lastname;
/**
* #var boolean $deleted
*
* #ORM\Column(name="deleted", type="boolean")
*/
private $deleted = false;
/**
* #var integer $role
*
* #ORM\Column(type="integer", nullable=true)
*/
private $role;
/**
* Create the user salt
*/
public function __construct()
{
//TODO: just for test
$this->uniqueId = substr(uniqid(), 0, 14);
}
/* MANAGED BY DOCTRINE, DON'T EDIT */
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set name
*
* #param string $name
* #return Player
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*
* #return string
*/
public function getName()
{
return $this->name;
}
/**
* Set shirtNumber
*
* #param integer $shirtNumber
* #return Player
*/
public function setShirtNumber($shirtNumber)
{
$this->shirtNumber = $shirtNumber;
return $this;
}
/**
* Get shirtNumber
*
* #return integer
*/
public function getShirtNumber()
{
return $this->shirtNumber;
}
/**
* Set vsid
*
* #param integer $vsid
* #return Player
*/
public function setVsid($vsid)
{
$this->vsid = $vsid;
return $this;
}
/**
* Get vsid
*
* #return integer
*/
public function getVsid()
{
return $this->vsid;
}
/**
* Set firstname
*
* #param string $firstname
* #return Player
*/
public function setFirstname($firstname)
{
$this->firstname = $firstname;
return $this;
}
/**
* Get firstname
*
* #return string
*/
public function getFirstname()
{
return $this->firstname;
}
/**
* Set lastname
*
* #param string $lastname
* #return Player
*/
public function setLastname($lastname)
{
$this->lastname = $lastname;
return $this;
}
/**
* Get lastname
*
* #return string
*/
public function getLastname()
{
return $this->lastname;
}
/**
* Set deleted
*
* #param boolean $deleted
* #return Player
*/
public function setDeleted($deleted)
{
$this->deleted = $deleted;
return $this;
}
/**
* Get deleted
*
* #return boolean
*/
public function getDeleted()
{
return $this->deleted;
}
/**
* Set role
*
* #param integer $role
* #return Player
*/
public function setRole($role)
{
$this->role = $role;
return $this;
}
/**
* Get role
*
* #return integer
*/
public function getRole()
{
return $this->role;
}
/**
* Set owner
*
* #param Acme\UserBundle\Entity\User $owner
* #return Player
*/
public function setOwner(\Acme\UserBundle\Entity\User $owner)
{
$this->owner = $owner;
return $this;
}
/**
* Get owner
*
* #return Acme\UserBundle\Entity\User
*/
public function getOwner()
{
return $this->owner;
}
/**
* Set team
*
* #param Acme\TeamBundle\Entity\Team $team
* #return Player
*/
public function setTeam(\Acme\TeamBundle\Entity\Team $team)
{
$this->team = $team;
return $this;
}
/**
* Get team
*
* #return Acme\TeamBundle\Entity\Team
*/
public function getTeam()
{
return $this->team;
}
}
and a Team entity:
<?php
namespace Acme\TeamBundle\Entity;
use Symfony\Component\Validator\Constraints as Assert;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM;
/**
* Acme\TeamBundle\Entity\Team
*
* #ORM\Table()
* #ORM\Entity(repositoryClass="Acme\TeamBundle\Entity\TeamRepository")
*/
class Team
{
/**
* #var integer $id
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string $uniqueId
*
* #ORM\Column(name="uniqueId", type="string", length=15)
*/
private $uniqueId;
/**
* #ORM\ManyToOne(targetEntity="Acme\UserBundle\Entity\User", inversedBy="teams")
* #ORM\JoinColumn(nullable=false)
*/
private $owner;
/**
* #var string $name
*
* #ORM\Column(name="name", type="string", length=50)
* #Assert\NotBlank()
*/
private $name;
/**
* #var string $homeColor
*
* #ORM\Column(name="homeColor", type="string", length=7, nullable=true)
*/
private $homeColor;
/**
* #var string $awayColor
*
* #ORM\Column(name="awayColor", type="string", length=7, nullable=true)
*/
private $awayColor;
/**
* #var string $homeShirt
*
* #ORM\Column(name="homeShirt", type="string", length=50, nullable=true)
*/
private $homeShirt;
/**
* #var string $awayShirt
*
* #ORM\Column(name="awayShirt", type="string", length=50, nullable=true)
*/
private $awayShirt;
/**
* #var string $teamLogo
*
* #ORM\Column(name="teamLogo", type="string", length=50, nullable=true)
*/
private $teamLogo;
/**
* #var boolean $deleted
*
* #ORM\Column(name="deleted", type="boolean")
*/
private $deleted = false;
/**
* #ORM\OneToMany(targetEntity="Acme\PlayerBundle\Entity\Player", mappedBy="team", cascade={"persist", "remove"})
*/
private $players;
/**
* #ORM\OneToMany(targetEntity="Acme\MatchBundle\Entity\Match", mappedBy="homeTeam")
*/
private $homeMatches;
/**
* #ORM\OneToMany(targetEntity="Acme\MatchBundle\Entity\Match", mappedBy="awayTeam")
*/
private $awayMatches;
/**
* Create the user salt
*/
public function __construct()
{
$this->players = new ArrayCollection();
$this->homeMatches = new ArrayCollection();
$this->awayMatches = new ArrayCollection();
//TODO: just for test
$this->uniqueId = substr(uniqid(), 0, 14);
}
public function getMatches()
{
return array_merge($this->awayMatches->toArray(), $this->homeMatches->toArray());
}
/* MANAGED BY DOCTRINE, DON'T EDIT */
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set uniqueId
*
* #param string $uniqueId
* #return Team
*/
public function setUniqueId($uniqueId)
{
$this->uniqueId = $uniqueId;
return $this;
}
/**
* Get uniqueId
*
* #return string
*/
public function getUniqueId()
{
return $this->uniqueId;
}
/**
* Set name
*
* #param string $name
* #return Team
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*
* #return string
*/
public function getName()
{
return $this->name;
}
/**
* Set homeColor
*
* #param string $homeColor
* #return Team
*/
public function setHomeColor($homeColor)
{
$this->homeColor = $homeColor;
return $this;
}
/**
* Get homeColor
*
* #return string
*/
public function getHomeColor()
{
return $this->homeColor;
}
/**
* Set awayColor
*
* #param string $awayColor
* #return Team
*/
public function setAwayColor($awayColor)
{
$this->awayColor = $awayColor;
return $this;
}
/**
* Get awayColor
*
* #return string
*/
public function getAwayColor()
{
return $this->awayColor;
}
/**
* Set homeShirt
*
* #param string $homeShirt
* #return Team
*/
public function setHomeShirt($homeShirt)
{
$this->homeShirt = $homeShirt;
return $this;
}
/**
* Get homeShirt
*
* #return string
*/
public function getHomeShirt()
{
return $this->homeShirt;
}
/**
* Set awayShirt
*
* #param string $awayShirt
* #return Team
*/
public function setAwayShirt($awayShirt)
{
$this->awayShirt = $awayShirt;
return $this;
}
/**
* Get awayShirt
*
* #return string
*/
public function getAwayShirt()
{
return $this->awayShirt;
}
/**
* Set teamLogo
*
* #param string $teamLogo
* #return Team
*/
public function setTeamLogo($teamLogo)
{
$this->teamLogo = $teamLogo;
return $this;
}
/**
* Get teamLogo
*
* #return string
*/
public function getTeamLogo()
{
return $this->teamLogo;
}
/**
* Set deleted
*
* #param boolean $deleted
* #return Team
*/
public function setDeleted($deleted)
{
$this->deleted = $deleted;
return $this;
}
/**
* Get deleted
*
* #return boolean
*/
public function getDeleted()
{
return $this->deleted;
}
/**
* Add players
*
* #param Acme\PlayerBundle\Entity\Player $players
* #return Team
*/
public function addPlayer(\Acme\PlayerBundle\Entity\Player $players)
{
$this->players[] = $players;
return $this;
}
/**
* Remove players
*
* #param Acme\PlayerBundle\Entity\Player $players
*/
public function removePlayer(\Acme\PlayerBundle\Entity\Player $players)
{
$this->players->removeElement($players);
}
/**
* Get players
*
* #return Doctrine\Common\Collections\Collection
*/
public function getPlayers()
{
return $this->players;
}
/**
* Add homeMatches
*
* #param Acme\MatchBundle\Entity\Match $homeMatches
* #return Team
*/
public function addHomeMatche(\Acme\MatchBundle\Entity\Match $homeMatches)
{
$this->homeMatches[] = $homeMatches;
return $this;
}
/**
* Remove homeMatches
*
* #param Acme\MatchBundle\Entity\Match $homeMatches
*/
public function removeHomeMatche(\Acme\MatchBundle\Entity\Match $homeMatches)
{
$this->homeMatches->removeElement($homeMatches);
}
/**
* Get homeMatches
*
* #return Doctrine\Common\Collections\Collection
*/
public function getHomeMatches()
{
return $this->homeMatches;
}
/**
* Add awayMatches
*
* #param Acme\MatchBundle\Entity\Match $awayMatches
* #return Team
*/
public function addAwayMatche(\Acme\MatchBundle\Entity\Match $awayMatches)
{
$this->awayMatches[] = $awayMatches;
return $this;
}
/**
* Remove awayMatches
*
* #param Acme\MatchBundle\Entity\Match $awayMatches
*/
public function removeAwayMatche(\Acme\MatchBundle\Entity\Match $awayMatches)
{
$this->awayMatches->removeElement($awayMatches);
}
/**
* Get awayMatches
*
* #return Doctrine\Common\Collections\Collection
*/
public function getAwayMatches()
{
return $this->awayMatches;
}
/**
* Set owner
*
* #param Acme\UserBundle\Entity\User $owner
* #return Team
*/
public function setOwner(\Acme\UserBundle\Entity\User $owner)
{
$this->owner = $owner;
return $this;
}
/**
* Get owner
*
* #return Acme\UserBundle\Entity\User
*/
public function getOwner()
{
return $this->owner;
}
}
Now I've created a player form class with the app/console and I've edited the team field to be an instance of the Team entity, this way:
<?php
namespace Acme\PlayerBundle\Form;
use Acme\TeamBundle\Entity\TeamRepository;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class PlayerType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('name')
->add('shirtNumber')
->add('firstname')
->add('lastname')
->add('role')
->add('team', 'entity', array(
'class' => 'AcmeTeamBundle:Team',
'query_builder' => function(TeamRepository $er) {
$query = $er->createQueryBuilder('t');
return $query;
}
));
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Acme\PlayerBundle\Entity\Player',
'csrf_protection' => false
));
}
public function getName()
{
return 'player';
}
}
And this is the relevant part of my controller:
/**
* Create a new player
*
* #Route(".{_format}", name="api_player_create")
* #Method("POST")
* #ApiDoc(
* description="Create a new player",
* statusCodes={
* 201="Player created and informations are returned",
* 400="Missing informations",
* 403="The user isn't authorized"
* },
* input="Acme\PlayerBundle\Form\PlayerType",
* return="Acme\PlayerBundle\Entity\Player"
* )
*
* #return Renders the player just created
*/
public function createPlayerAction()
{
return $this->processForm(new Player());
}
/**
* Edit a player
*
* #param integer $id The id of the player to be created
*
* #Route("/{id}.{_format}", name="api_player_patch", requirements={ "id": "\d+" })
* #Method("PATCH")
* #ApiDoc(
* description="Edit a player",
* statusCodes={
* 200="Player is updated",
* 400="Missing informations",
* 403="The user isn't authorized"
* },
* input="Acme\PlayerBundle\Form\PlayerType",
* return="Acme\PlayerBundle\Entity\Player"
* )
*
* #return Renders the player just edited
*/
public function editPlayerAction(Player $player)
{
if ($player->getOwner() != $this->getUser()) {
throw new ApiException\PermissionDeniedException;
}
return $this->processForm($player);
}
/**
* Function to handle a form to create/edit a player
*
* #param Player $player The player to be created or edited
*
* #return Api Response
*/
private function processForm(Player $player)
{
/**
* Check if the player is new (to be created) or we're editing a player
*/
$statusCode = is_null($player->getId()) ? 201 : 200;
$form = $this->createForm(new PlayerType(), $player);
$form->bind($this->getRequest());
if ($form->isValid()) {
if($player->getTeam()->getOwner() != $this->getUser()) {
throw new ApiException\PermissionDeniedException;
}
$player->setOwner($this->getUser());
$this->entityManager->persist($player);
$this->entityManager->flush();
return $this->apiResponse->getResponse($player, $statusCode);
}
return $this->apiResponse->getResponse($form, 400, 'Missing arguments');
}
The player creation works fine, the player edit doesn't, when the user makes the api request, passing the ID in the url and the name of the player I get:
Catchable Fatal Error: Argument 1 passed to Acme\PlayerBundle\Entity\Player::setTeam() must be an instance of Acme\TeamBundle\Entity\Team, null given, called in /Volumes/Dati/Users/alessandro/Sites/acme-api/vendor/symfony/symfony/src/Symfony/Component/Form/Util/PropertyPath.php on line 538 and defined in /Volumes/Dati/Users/alessandro/Sites/acme-api/src/Acme/PlayerBundle/Entity/Player.php line 278
Seems that form is trying to set the Team to null, why?
I've tried both sending and not the team as the form parameters but it doesn't work.
Any clue?
Figured it out that null unsent fields in the form is the default behaviour in symfony.
There is an open request for partial form binding in symfony. For now a guy created a form event subscriber that adds the missing fields with the actual values:
https://gist.github.com/3720535
This is his code:
<?php
namespace Foo;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\Form\FormEvent;
/**
* Changes Form->bind() behavior so that it treats not set values as if they
* were sent unchanged.
*
* Use when you don't want fields to be set to NULL when they are not displayed
* on the page (or to implement PUT/PATCH requests).
*/
class PatchSubscriber implements EventSubscriberInterface
{
public function onPreBind(FormEvent $event)
{
$form = $event->getForm();
$clientData = $event->getData();
$clientData = array_replace($this->unbind($form), $clientData ?: array());
$event->setData($clientData);
}
/**
* Returns the form's data like $form->bind() expects it
*/
protected function unbind($form)
{
if ($form->hasChildren()) {
$ary = array();
foreach ($form->getChildren() as $name => $child) {
$ary[$name] = $this->unbind($child);
}
return $ary;
} else {
return $form->getClientData();
}
}
static public function getSubscribedEvents()
{
return array(
FormEvents::PRE_BIND => 'onPreBind',
);
}
}
to add to the form you have to edit the buildForm method in the form class:
public function buildForm(FormBuilderInterface $builder, array $options)
{
$subscriber = new PatchSubscriber();
$builder->addEventSubscriber($subscriber);
$builder->add('name');
....
}
In this case you're ok to use the PATCH REST requests to edit an entity just by the sent fields