I am using a service within twig like this
{{ count_service.getCount(term.getId) }}
I want the service to use a repository function, repository function
<?php
namespace AppBundle\Repository;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\EntityRepository;
use Doctrine\ORM\Mapping;
class SynonymRepository extends EntityRepository
{
public function getCount($termId)
{
$qbSynonymType = $this->getEntityManager()->createQueryBuilder();
$synonymTypes = $qbSynonymType->select('synonymType.id, synonymType.type')
->from('AppBundle:SynonymType', 'synonymType')
->getQuery()->getResult();
$qb = $this->getEntityManager()->createQueryBuilder();
$count = [];
$qb->select('count(synonym.synonymId)')
->from('AppBundle:Synonym','synonym');
foreach($synonymTypes as $type) {
$count[$type['type']] = $qb
->where('synonym.term = :termId')
->andWhere('synonym.synonymType = :type')
->setParameter('termId', $termId)
->setParameter('type', $type['id'])
->getQuery()->getSingleScalarResult();
}
$qbTerm = $this->getEntityManager()->createQueryBuilder()->from('AppBundle:Term', 'term');
$count['parent'] = "NaN";
$count['children'] = "NaN";
return $count;
}
}
My service.yml looks like this
synonymrepository:
class: Doctrine\ORM\EntityRepository
factory: ["#doctrine.orm.entity_manager", getRepository]
arguments:
- AppBundle\Entity\SynonymType
term_count:
class: AppBundle\Services\TermCount
arguments:
- "#synonymrepository"
And finally my service looks like this
<?php
namespace AppBundle\Services;
use AppBundle\Repository\SynonymRepository;
class TermCount
{
private $repository;
public function __construct()
{
$this->repository = new SynonymRepository();
}
public function getCount($termId)
{
return $this->repository->getCount($termId);
}
}
When running this I am getting the following error
Type error: Too few arguments to function Doctrine\ORM\EntityRepository::__construct(), 0 passed in /var/www/html/src/AppBundle/Services/TermCount.php on line 15 and exactly 2 expected
I assume this is happening because extending SynonymRepository with the EntityRepository requires EntityManagerInterface $em and Mapping\ClassMetadata $class. But I am not sure how pass them to EntityRepository.
I was using this answer to get me here, lost on how to actually implement the finall bit.
Thanks for helping.
UPDATE
Entity
<?php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
/**
* #ORM\Table(name="synonym")
* #ORM\Entity(repositoryClass="AppBundle\Repository\SynonymRepository")
*/
class Synonym
{
/**
* #var int
* #ORM\Id()
* #ORM\Column(name="synonym_id", type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $synonymId;
/**
* #var Term
* #ORM\ManyToOne(targetEntity="AppBundle\Entity\Term", inversedBy="synonyms")
*/
protected $term;
/**
* #var SynonymType[]
* #ORM\ManyToOne(targetEntity="AppBundle\Entity\SynonymType", inversedBy="synonyms")
*/
protected $synonymType;
/**
* #var int
* #ORM\Column(name="language_id", type="integer")
*/
protected $languageId;
/**
* #var string
* #ORM\Column(name="synonym", type="string", length=255)
*/
protected $synonym;
public function __construct()
{
// $this->synonymType = new ArrayCollection();
}
/**
* #return int
*/
public function getSynonymId(): int
{
return $this->synonymId;
}
/**
* #return Term
*/
public function getTerm(): Term
{
return $this->term;
}
/**
* #param int $termId
* #return Term
*/
public function setTerm(int $termId): Term
{
$this->term = $termId;
return $this->term;
}
/**
* #return SynonymType[]
*/
public function getSynonymType()
{
return $this->synonymType;
}
/**
* #param SynonymType $synonymType
* #return SynonymType
*/
public function setSynonymType(SynonymType $synonymType): SynonymType
{
$this->synonymType = $synonymType;
return $this->synonymType;
}
/**
* #return int
*/
public function getLanguageId(): int
{
return $this->languageId;
}
/**
* #param int $languageId
* #return Synonym
*/
public function setLanguageId(int $languageId): Synonym
{
$this->languageId = $languageId;
return $this;
}
/**
* #return string
*/
public function getSynonym(): string
{
return $this->synonym;
}
/**
* #param string $synonym
* #return Synonym
*/
public function setSynonym(string $synonym): Synonym
{
$this->synonym = $synonym;
return $this;
}
}
You need to use DI (Dependency injection) in your construct insted of using new cause as i see the erreur your SynonymRepository depends on other services
<?php
namespace AppBundle\Services;
use AppBundle\Repository\SynonymRepository;
class TermCount
{
private $repository;
public function __construct(SynonymRepository $synonymRepository)
{
$this->repository = $synonymRepository;
}
public function getCount($termId)
{
return $this->repository->getCount($termId);
}
}
Related
In Symfony4 I have a repository :
<?php
namespace App\Repository;
use App\Entity\Comment;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Symfony\Bridge\Doctrine\RegistryInterface;
class CommentRepository extends ServiceEntityRepository
{
public function __construct(RegistryInterface $registry)
{
parent::__construct($registry, Comment::class);
}
public function findByNews($news)
{
return $this->createQueryBuilder('c')
->where('c.news = :news')
->setParameter('news', $news)
//->setMaxResults(10)
->getQuery()
->getResult()
;
}
}
When I try to use it in this action of my ajax controller:
public function comments(Request $request)
{
if ($request->isXmlHttpRequest()) {
$newsId = $request->get('id');
$newsRepository = $this->getDoctrine()->getRepository(News::class);
$news = $newsRepository->find($newsId);
$commentRepository = $this->getDoctrine()->getRepository(Comment::class);
$comments = $commentRepository->findByNews($news);
$comments = 0;
$serializer = $this->get('serializer');
$response = $serializer->serialize($comments, 'json');
return new JsonResponse(array('data' => $response));
}
return new Response("Error : this is not an ajax request!", 400);
}
I get this error :
Uncaught PHP Exception RuntimeException: "The "App\Entity\Comment" entity has a repositoryClass set to "App\Entity\CommentRepository", but this is not a valid class. Check your class naming. If this is meant to be a service id, make sure this service exists and is tagged with "doctrine.repository_service"." at (...)\vendor\doctrine\doctrine-bundle\Repository\ContainerRepositoryFactory.php line 82
I can't see why the CommentRepository is not valid.
And why this is mentionning App\Entity\CommentRepository instead of App\Repository\CommentRepository?
Any idea ?
Edit :
Here's the Comment entity :
<?php
namespace App\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* MemberBundle\Entity\Comment
*
* #ORM\Table(name="comment")
* #ORM\Entity(repositoryClass="App\Entity\CommentRepository")
*/
class Comment
{
/**
* #var integer $id
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var App\Entity\News $news
*
* #ORM\ManyToOne(targetEntity="App\Entity\News")
* #ORM\JoinColumn(name="news", referencedColumnName="id", onDelete="CASCADE")
*/
private $news;
/**
* #var App\Entity\User $author
*
* #ORM\ManyToOne(targetEntity="App\Entity\User")
* #ORM\JoinColumn(name="author", referencedColumnName="id", onDelete="CASCADE")
*/
private $author;
/**
* #var text $content
*
* #ORM\Column(name="content", type="text")
*/
private $content;
/**
* #var datetime $date
*
* #ORM\Column(name="date", type="datetime")
*/
private $date;
public function __construct() {
$this->date = new \DateTime();
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set news
*
* #param App\Entity\News $news
*/
public function setNews($news)
{
$this->news = $news;
}
/**
* Get news
*
* #return App\Entity\News
*/
public function getNews()
{
return $this->news;
}
/**
* Set author
*
* #param App\Entity\User $author
*/
public function setAuthor($author)
{
$this->author = $author;
}
/**
* Get author
*
* #return App\Entity\User
*/
public function getAuthor()
{
return $this->author;
}
/**
* Set content
*
* #param text $content
*/
public function setContent($content)
{
$this->content = $content;
}
/**
* Get content
*
* #return text
*/
public function getContent()
{
return $this->content;
}
/**
* Set date
*
* #param datetime $date
*/
public function setDate($date)
{
$this->date = $date;
}
/**
* Get date
*
* #return datetime
*/
public function getDate()
{
return $this->date;
}
}
You should change #ORM\Entity(repositoryClass="App\Entity\CommentRepository") to #ORM\Entity(repositoryClass="App\Repository\CommentRepository")
You could otherwise move CommentRepositoryinto Entity directory (and update the namespace accordingly), but it's best to follow the standard structure and keep your repositories in the App\Repository namespace.
When trying to get the default repository class for my entity Lesson I keep getting the following error:
Attempted to load class "LessonRepository" from namespace "DrumLessonBookingApp\DrumLessonBookingBundle\Repository".
Did you forget a "use" statement for another namespace?
I use the exact same method as a User entity which works perfectly fine.
The code for my controller is:
namespace DrumLessonBookingApp\DrumLessonBookingBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use DrumLessonBookingApp\DrumLessonBookingBundle\Entity\User;
use DrumLessonBookingApp\DrumLessonBookingBundle\Entity\Lesson;
use DrumLessonBookingApp\DrumLessonBookingBundle\Repository;
class LoginController extends Controller
{
public function displayAction()
{
return $this->render('DrumLessonBookingAppDrumLessonBookingBundle:Default:login.html.twig');
}
public function processloginAction(Request $request)
{
$doctrine = $this->getDoctrine()->getManager();
$email = $request->get('email');
$pwd = $request->get('pwd');
$user = $doctrine->getRepository('DrumLessonBookingAppDrumLessonBookingBundle:User')->findOneBy(array('email' => $email,'password' => $pwd));
if($user->getAdministrator() == 1)
{
$session = $this->get('session');
$session->set('loggedin', true);
$lessons = $doctrine->getRepository('DrumLessonBookingAppDrumLessonBookingBundle:Lesson')->findAll();
return $this->render('DrumLessonBookingAppDrumLessonBookingBundle:Default:dashboard.html.twig', array("lessons" => $lessons));
}
else {
return new Response('doctrine not working');
}
}
}
I am also having difficulty to generate a custom Respository class using doctrine so tried creating one myself for the User entity but symfny doesn't pick it up or recognise the custom method. See below:
namespace DrumLessonBookingApp\DrumLessonBookingBundle\Repository;
use Doctrine\ORM\EntityRepository;
use DrumLessonBookingApp\DrumLessonBookingBundle\Entity\User;
class UserRepository extends EntityRepository
{
public function loginUser($email, $password)
{
$entityM = $this->getEntityManager();
$dql = $entityM->createQuery(
'SELECT u FROM DrumLessonBookingAppDrumLessonBookingBundle:User u
WHERE u.email = :email
AND WHERE u.password = :pwd');
$dql->setParameter('email', $email);
$dql->setParameter('pwd', $password);
$user = $query->getResult();
return $user;
}
}
I have searched similar questions but cannot find a solution, someone please help!
My Lesson Entity
namespace DrumLessonBookingApp\DrumLessonBookingBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity
* #ORM\Table(name="lessons")
* #ORM\Entity(repositoryClass="DrumLessonBookingApp\DrumLessonBookingBundle\Repository\LessonRepository")
* */
class Lesson {
/**
* #ORM\Column(type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
* */
private $id;
/**
* #ORM\Column(type="date")
* */
private $date;
/**
* #ORM\Column(type="time")
* */
private $time;
/**
* #ORM\ManyToOne(targetEntity="User", inversedBy="lessons")
* #ORM\JoinColumn(name="user_id", referencedColumnName="id")
* */
private $user;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set date
*
* #param \DateTime $date
*
* #return Lesson
*/
public function setDate($date)
{
$this->date = $date;
return $this;
}
/**
* Get date
*
* #return \DateTime
*/
public function getDate()
{
return $this->date;
}
/**
* Set time
*
* #param \DateTime $time
*
* #return Lesson
*/
public function setTime($time)
{
$this->time = $time;
return $this;
}
/**
* Get time
*
* #return \DateTime
*/
public function getTime()
{
return $this->time;
}
/**
* Set User
*
* #param object
* #return Lesson
* */
public function setUser(User $user)
{
$this->user = $user;
return $this;
}
/**
* Set User
*
*
* #return User
* */
public function getUser($user)
{
return $this->user;
}
}
There is nothing in my custom Lesson Repository but surely it should still find the methods such as findAll() etc from the entityRepository it extends
seems you have multiple questions for one answer
you need to reference the repositoryClass it in your Entity-class :
/**
* USER
*
* #ORM\Table(name="users")
* #ORM\Entity(repositoryClass="DrumLessonBookingApp\DrumLessonBookingBundle\Repository\UserRepository")
*/
class User
{
i guess you missing the same at your Lesson Entity.
You dont have to add a "use" statement then
I try to use the functions TechParentInsert in the controller I am getting an error:
Attempted to call function "TechParentInsert" from namespace "TestyBundle\Controller".
500 Internal Server Error - UndefinedFunctionException
In controller I have:
"use TestyBundle\Repository\TechParentRepository;" when i've defined "TechParentInsert"
What am I doing wrong?
-----------------------------My CODE
Controller TestyController:
namespace TestyBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
use Symfony\Component\HttpFoundation\Request;
use Doctrine\ORM\Query\AST\Functions\ConcatFunction;
use Doctrine\ORM\EntityRepository;
use TestyBundle\Entity\Sort;
use TestyBundle\Form\SortType;
use TestyBundle\Repository\SortRepository;
use TestyBundle\Repository\TechParentRepository;
/**
* #Route("/testy")
*
*/
class TestyController extends Controller
{
/**
* (other actions )
*
*/
/**
* #Route(
* "/parent/{parent}", name="TEST_sort_new"
* )
*
* #Template
*/
public function TechParentNewAction( Request $request, int $parent = 0 )
{
$repo2 = $this->getDoctrine()->getRepository( 'TestyBundle:Sort' );
$sortNew = $repo2->findOneBy( ['zz' => 0]);
$sortNew->setParentString( $sortNew->getParentString( ) . (string) $sortNew->getId() );
$sortNew->setZz( 1 );
$newRecordID = $sortNew->getId();
$op1 = TechParentInsert( $newRecordID );
$em->persist( $sortNew );
$em->flush();
return $this->redirect( $this->generateUrl( 'TEST_sort' ) );
}
return [ 'data1' => $sortNew ];
}
}
Repository: TechParentRepository
<?php
namespace TestyBundle\Repository;
use TestyBundle\Entity\TechParent;
class TechParentRepository extends \Doctrine\ORM\EntityRepository
{
public function TechParentInsert( $idsort)
{
$parent = new TechParent();
$parent->setIdSorty( $idsort);
$parent->setIdParent( $idsort);
$parent->setIsOwn( TRUE);
$em = $this->getDoctrine()->getManager();
$em->persist($parent);
$em->flush();
return 1;
}
}
My entity: TechParent
<?php
namespace TestyBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* TechParent
*
* #ORM\Table(name="tech_parent")
* #ORM\Entity(repositoryClass="TestyBundle\Repository\TechParentRepository")
*/
class TechParent
{
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var int
*
* #ORM\Column(name="idSorty", type="integer")
*/
private $idSorty;
/**
* #var int
*
* #ORM\Column(name="idParent", type="integer")
*/
private $idParent;
/**
* #var bool
*
* #ORM\Column(name="isOwn", type="boolean")
*/
private $isOwn;
/**
* Get id
*
* #return int
*/
public function getId()
{
return $this->id;
}
/**
* Set idSorty
*
* #param integer $idSorty
*
* #return TechParent
*/
public function setIdSorty($idSorty)
{
$this->idSorty = $idSorty;
return $this;
}
/**
* Get idSorty
*
* #return int
*/
public function getIdSorty()
{
return $this->idSorty;
}
/**
* Set idParent
*
* #param integer $idParent
*
* #return TechParent
*/
public function setIdParent($idParent)
{
$this->idParent = $idParent;
return $this;
}
/**
* Get idParent
*
* #return int
*/
public function getIdParent()
{
return $this->idParent;
}
/**
* Set isOwn
*
* #param boolean $isOwn
*
* #return TechParent
*/
public function setIsOwn($isOwn)
{
$this->isOwn = $isOwn;
return $this;
}
/**
* Get isOwn
*
* #return bool
*/
public function getIsOwn()
{
return $this->isOwn;
}
}
When you're accessing a method from different class you have to use ClassName::method(), but in this case the TechParentRepository has dependecies for sure. Because of dependency injection, there's a best practice in Symfony to define repository as a service and then use it this way:
$techParentRepository = $this->get('tech_parent_repository ');
$techParentRepository->TechParentInsert();
Little advice - good practise also is to name classes uppercase, but methods lowercase, so public function techParentInsert($idsort) would be better.
Since autowiring in Symfony 2.8 and moreover Symfony 3.3 (May 2017) there is much cleaner way to pass dependencies to controller.
1. Controller
namespace TestyBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use TestyBundle\Repository\SortRepository;
use TestyBundle\Repository\TechParentRepository;
final class TestyController extends Controller
{
/**
* #var SortRepository
*/
private $sortRepository;
/**
* #var TechParentRepository
*/
private $techParentRepository;
public function __constructor(
SortRepository $sortRepository,
TechParentRepository $techParentRepository,
) {
$this->sortRepository = $sortRepository;
$this->techParentRepository = $techParentRepository;
}
public function TechParentNewAction(int $parent = 0)
{
$sortNew = $this->sortRepository->findOneBy([
'zz' => 0
]);
$sortNew->setParentString($sortNew->getParentString() . (string) $sortNew->getId());
$sortNew->setZz(1);
$newRecordID = $sortNew->getId();
$this->techParentRepository->TechParentInsert($newRecordID);
// redirect etc...
}
}
2. Controller services registration
# app/config/services.yml
services:
_defaults:
autowire: true
# PSR-4 autodiscovery
TestyBundle\:
resource: '../../src/TestyBundle' # located in /src/TestyBundle
And you are ready to go!
You can read about Symfony 3.3 dependency injection (in this case registering services in config and using it in controller) news in these 2 posts:
https://www.tomasvotruba.cz/blog/2017/05/07/how-to-refactor-to-new-dependency-injection-features-in-symfony-3-3/
https://symfony.com/blog/the-new-symfony-3-3-service-configuration-changes-explained
I'm trying to make an easy listAction to retrieve data from Doctrine but I got this error:
Attempted to load class "ProductRepository" from namespace "AppBundle\Entity".
Did you forget a "use" statement for another namespace?
This come out when i call the route ex.com/list that must
to list the data coming from product table
Controller: (src/AppBundle/Controller)
<?php
namespace AppBundle\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Translation\Translator;
use Symfony\Component\Translation\MessageSelector;
use AppBundle\Entity\Product;
use Symfony\Component\HttpFoundation\Response;
new Translator('it', new MessageSelector(), __DIR__.'/../cache');
class DefaultController extends Controller
{
/**
* #Route("/", name="homepage")
* #param Request $request
* #return \Symfony\Component\HttpFoundation\Response
*/
public function indexAction(Request $request)
{
$request->getLocale();
$request->setLocale('it');
return $this->render('default/index.html.twig', [
'base_dir' => realpath($this->getParameter('kernel.root_dir').'/..'),
]);
}
/**
*
* #Route("list", name="list")
* #return Response
*
*/
public function listAction()
{
return $product = $this->getDoctrine()
->getRepository('AppBundle\Entity\Product')
->findAll();
/* if (!$product) {
throw $this->createNotFoundException(
'Nessun prodotto trovato'
);
}*/
}
/**
* #Route("create",name="create")
* #return Response
*/
public function createAction()
{
$product = new Product();
$product->setName('Pippo Pluto');
$product->setPrice('19.99');
$product->setDescription('Lorem ipsum dolor');
$product->setSeller('1');
$em = $this->getDoctrine()->getManager();
$em->persist($product);
$em->flush();
return $this->render('default/index.html.twig');
}
/**
* #param $id
* #Route("show/{id}",name="show/{id}")
* #return Response
*/
public function showAction($id)
{
$product = new Product();
$product = $this->getDoctrine()
->getRepository('AppBundle:Product')
->find($id);
if (!$product) {
throw $this->createNotFoundException(
'Nessun prodotto trovato per l\'id '.$id
);
}
}
}
Entity: (src/AppBundle/Entity)
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* Product
*
* #ORM\Table(name="product")
* #ORM\Entity(repositoryClass="AppBundle\Entity\ProductRepository")
*/
class Product
{
/**
* #var int
*
* #ORM\Column(name="`id`", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="`name`", type="string")
*/
private $name;
/**
* #var float
*
* #ORM\Column(name="`price`", type="float")
*/
private $price;
/**
* #var string
*
* #ORM\Column(name="`description`", type="string")
*/
private $description;
/**
* #var int
*
* #ORM\Column(name="`seller`", type="integer")
*/
private $seller;
/**
* Get id
*
* #return int
*/
public function getId()
{
return $this->id;
}
/**
* Set name
*
* #param string $name
*
* #return Product
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Set price
*
* #param float $price
*
* #return Product
*/
public function setPrice($price) {
$this->price = $price;
return $this;
}
/**
* Set description
*
* #param string $description
*
* #return Product
*/
public function setDescription($description) {
$this->description = $description;
return $this;
}
/**
* Set seller
*
* #param int $seller
*
* #return Product
*/
public function setSeller($seller) {
$this->seller = $seller;
return $this;
}
/**
* Get name
*
* #return string
*/
public function getName()
{
return $this->name;
}
/**
* Get price
*
* #return float
*/
public function getPrice()
{
return $this->price;
}
/**
* Get description
*
* #return string
*/
public function getDescription()
{
return $this->description;
}
/**
* Get seller
*
* #return int
*/
public function getSeller()
{
return $this->seller;
}
}
I can't understand what I'm missing to use. thanks.
That error "Attempted to load class "ProductRepository" from namespace "AppBundle\Entity" is generated because you, by mistake I guess, renamed the repositoryClass in your AppBundle/Entity/Product class.
So instead of * #ORM\Entity(repositoryClass="AppBundle\Entity\ProductRepository") you should have * #ORM\Entity(repositoryClass="AppBundle\Repository\ProductRepository"), which means that the repository classes are meant to be located into Repository directory and not Entity.
And a controller action method must always return a response, or a redirect, etc.
And, even though your way works too, you would always want to call the findAll() method on a repository object, and not an entity one. So, again,
in your listAction instead of ->getRepository('AppBundle\Entity\Product')->findAll() needs to be ->getRepository('AppBundle:Product')->findAll()
I might be wrong, but i think that is becouse You dont render anything. Try this code: $product = $this->getDoctrine() ->getRepository('AppBundle\Entity\Product') ->findAll(); return $this->render('default/index.html.twig',['product' => $product]);
First of all: the error I'm getting is: Entities passed to the choice field must be managed
I have these entities:
- user (belongs to one or many teams)
- team (has one or 2 users)
- challenge (has 2 teams)
I'd like to build a ChallengeType form where a user can fill in the two users for the two teams and create the challenge. I think I need an embedded form here.
I've made a TeamType Form class: (I would expect to get a select box from this, where all users are listed)
<?php
namespace Tennisconnect\DashboardBundle\Form\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilder;
class TeamType extends AbstractType
{
public function buildForm(FormBuilder $builder, array $options)
{
$builder->add('players', 'entity', array(
'class' => 'TennisconnectUserBundle:User',
'multiple' => true
));
}
public function getName()
{
return 'team';
}
public function getDefaultOptions(array $options)
{
return array('data_class' => 'Tennisconnect\DashboardBundle\Entity\Team');
}
}
This is the ChallengeType form class:
<?php
namespace Tennisconnect\DashboardBundle\Form\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilder;
class ChallengeType extends AbstractType
{
public function buildForm(FormBuilder $builder, array $options)
{
$builder->add('teams', 'collection', array('type' => new TeamType()));
}
public function getName()
{
return 'challenge';
}
public function getDefaultOptions(array $options)
{
return array('data_class' => 'Tennisconnect\DashboardBundle\Entity\Challenge');
}
}
Challenge entity:
namespace Tennisconnect\DashboardBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Tennisconnect\DashboardBundle\Entity\Team;
use Symfony\Component\Validator\Constraints as Assert;
use Doctrine\Common\Collections\ArrayCollection;
/**
* #ORM\Entity
* #ORM\Table(name="challenge")
*/
class Challenge
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #ORM\ManyToMany(targetEntity="Team", mappedBy="teams")
*/
protected $teams;
public function __construct()
{
$this->teams = new ArrayCollection();
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Add teams
*
* #param Tennisconnect\DashboardBundle\Entity\Team $teams
*/
public function addTeam(Team $teams)
{
$this->teams[] = $teams;
}
/**
* Get teams
*
* #return Doctrine\Common\Collections\Collection
*/
public function getTeams()
{
return $this->teams;
}
}
Team entity:
namespace Tennisconnect\DashboardBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
use Doctrine\Common\Collections\ArrayCollection;
use Tennisconnect\UserBundle\Entity\User;
use Tennisconnect\DashboardBundle\Entity\Challenge;
use Tennisconnect\DashboardBundle\Entity\Match;
/**
* #ORM\Entity
* #ORM\Table(name="team")
*/
class Team
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #ORM\ManyToMany(targetEntity="Tennisconnect\UserBundle\Entity\User", mappedBy="teams")
*/
protected $players;
/**
* #ORM\ManyToMany(targetEntity="challenge", inversedBy="teams", cascade= {"persist"})
*/
protected $challenges;
/**
* #ORM\ManyToMany(targetEntity="Match", inversedBy="teams")
*/
protected $matches;
public function __construct()
{
$this->players = new ArrayCollection();
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Add players
*
* #param Tennisconnect\UserBundle\Entity\User $players
*/
public function addUser(User $players)
{
$this->players[] = $players;
}
/**
* Get players
*
* #return Doctrine\Common\Collections\Collection
*/
public function getPlayers()
{
return $this->players;
}
/**
* Add matches
*
* #param Tennisconnect\DashboardBundle\Entity\Match $matches
*/
public function addMatch(Match $matches)
{
$this->matches[] = $matches;
}
/**
* Get matches
*
* #return Doctrine\Common\Collections\Collection
*/
public function getMatches()
{
return $this->matches;
}
/**
* Add challenges
*
* #param Tennisconnect\DashboardBundle\Entity\challenge $challenges
*/
public function addchallenge(challenge $challenges)
{
$this->challenges[] = $challenges;
}
/**
* Get challenges
*
* #return Doctrine\Common\Collections\Collection
*/
public function getChallenges()
{
return $this->challenges;
}
}
Challenge controller:
class ChallengeController extends Controller
{
public function newAction()
{
$challenge = new Challenge();
$form = $this->createForm(new ChallengeType(), $challenge);
return $this->render('TennisconnectDashboardBundle:Challenge:new.html.twig', array('form' => $form->createView()));
}
}
You've created forms that are displaying a ManyToMany collection; set the multiple option in your formbuilder for those widgets to true (it defaults false, which fundamentally conflicts with a ToMany relationship).
If you have the error Entities passed to the choice field must be managed. Maybe persist them in the entity manager? with a ManyToMany relationship between 2 entities, when using a form type, it may come from your entity constructor :
If your form is "TeamType", try to remove the ArrayCollection initialization of your "Team" entity.
Your Team class become :
namespace Tennisconnect\DashboardBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
use Doctrine\Common\Collections\ArrayCollection;
use Tennisconnect\UserBundle\Entity\User;
use Tennisconnect\DashboardBundle\Entity\Challenge;
use Tennisconnect\DashboardBundle\Entity\Match;
/**
* #ORM\Entity
* #ORM\Table(name="team")
*/
class Team
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #ORM\ManyToMany(targetEntity="Tennisconnect\UserBundle\Entity\User", mappedBy="teams")
*/
protected $players;
/**
* #ORM\ManyToMany(targetEntity="challenge", inversedBy="teams", cascade= {"persist"})
*/
protected $challenges;
/**
* #ORM\ManyToMany(targetEntity="Match", inversedBy="teams")
*/
protected $matches;
public function __construct()
{
// REMOVE $this->players = new ArrayCollection();
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Add players
*
* #param Tennisconnect\UserBundle\Entity\User $players
*/
public function addUser(User $players)
{
$this->players[] = $players;
}
/**
* Get players
*
* #return Doctrine\Common\Collections\Collection
*/
public function getPlayers()
{
return $this->players;
}
/**
* Add matches
*
* #param Tennisconnect\DashboardBundle\Entity\Match $matches
*/
public function addMatch(Match $matches)
{
$this->matches[] = $matches;
}
/**
* Get matches
*
* #return Doctrine\Common\Collections\Collection
*/
public function getMatches()
{
return $this->matches;
}
/**
* Add challenges
*
* #param Tennisconnect\DashboardBundle\Entity\challenge $challenges
*/
public function addchallenge(challenge $challenges)
{
$this->challenges[] = $challenges;
}
/**
* Get challenges
*
* #return Doctrine\Common\Collections\Collection
*/
public function getChallenges()
{
return $this->challenges;
}
}
The problem is solved.
I had to add the "allow_add" option to my collection in the ChallengeType class.
The challenge controller class needed some editing too. I added 2 teams to the Challenge object before passing it through to the form.