I'm using Symfony 2 and I have two entities in different bundles like:
//this class overrides fos_user class
//User\UserBundle\Entity\User
class User extends BaseUser
{
//..
/**
* #ORM\OneToMany(targetEntity="News\AdminBundle\Entity\News", mappedBy="author_id")
*/
protected $news_author;
//...
}
//News\AdminBundle\Entity\News
class News
{
//...
/**
* #ORM\ManyToOne(targetEntity="\User\UserBundle\Entity\User", inversedBy="news_author")
* #ORM\JoinColumn(name="author_id", referencedColumnName="id")
*/
protected $news_author;
//...
}
Both classes (entities) works fine. I have successfully setup fos_user bundle with registration and other stuff. The same if for News class. Then I build relation between those two classes OneTo Many (User -> News) as it is shown in code. This also works fine without errors and I can add news that belongs to user. The problem is when I build a form with entity class like:
->add('year', 'entity', array(
'class' => 'NewsAdminBundle:News',
'query_builder' => function(EntityRepository $er) {
return $er->createQueryBuilder('u')
->groupBy('u.year')
->orderBy('u.year', 'DESC');
},))
This form shows me a years when news are posted (like archive). Years are showing fine, but when I submit (post) a form then I've got error:
Class User\UserBundle\Entity\News does not exist
I figure out that this error is connected with sentence
$form->bindRequest($request);
The problem is because I have two entities in different bundles. How can I solve this error?
Edit:
I solved the problem. When I run
php app/console doctrine:generate:entities User
php app/console doctrine:generate:entities News
then Doctrine generate getters and setters in User and News. In entity News it generates method
/**
* Add news_author
*
* #param User\UserBundle\Entity\News $newsAuthor
*/
public function addNews(User\UserBundle\Entity\News $newsAuthor)
{
$this->news_author[] = $newsAuthor;
}
I was not paying attention to this method and I change it to this
/**
* Add news_author
*
* #param News\AdminBundle\Entity\News $newsAuthor
*/
public function addNews(News\AdminBundle\Entity\News $newsAuthor)
{
$this->news_author[] = $newsAuthor;
}
Now everything works fine. Thanks for all answers.
/**
* #ORM\ManyToOne(targetEntity="User\UserBundle\Entity\User", inversedBy="news_author")
* #ORM\JoinColumn(name="author_id", referencedColumnName="id")
*/
protected $news_author;
You have to remove prefix backslash – see note in Doctrine documentation
Related
Is it possible to set up a search for multiple entities, using the Florian Semm Solr Bundle in Symfony? I'm completely lost, have looked in the documentation of Solarium itself, but couldn't figure out how to set up a search for our Symfony project.
Here's what I did so far:
Solarium and the SolrBundle are both successfully installed.
I indexed 3 entities (for now) with the Solr annotations like that:
/**
* #Solr\Document(repository="UserBundle\Entity\User")
* #Solr\Document(index="*")
*/
class User {
/**
* #Solr\Id
*/
protected $id;
/**
* #Solr\Field(type="string")
*/
protected $firstName;
/**
* #Solr\Field(type="string")
*/
protected $lastName;
}
I set up a controller where I call the solr.client but that's basically how far I got. I can show you my code but it's throwing error messages, because I'm basically just trying around:
class SearchController extends Controller {
/**
* #Route("/search-result/", name="searchBundle")
*/
public function searchAction(Request $request) {
$client = $this->get('solr.client');
$query = $client->createSelect();
$query->setQuery($request->query->all());
// this executes the query and returns the result
$resultset = $client->execute($query);
return $this->render('SearchBundle::search.html.twig', array(
'resultset' => $resultset
));
}
}
How do I get the controller/the bundle to search within all the three bundles/indexed properties?
How do I structure the output?
Couldn't find any tutorials/example codes/guidelines for that specific bundle unfortunately.
What you probably want to do inside your controller is get a repository for the search;
$resultset = $this->get('solr.client')->getRepository('UserBundle:User')->findAll();
return $this->render('SearchBundle::search.html.twig', array(
'resultset' => $resultset
));
Source: https://github.com/floriansemm/SolrBundle#query-a-field-of-a-document
This is either a huge bug in Symfony2 or I'm just not getting it. I've spent literally days trying to understand what is going on here. I have two entities:
Event
Date
I want a relationship where there are many dates to one event. Sounds simple enough, so in my Event entity I have:
/**
* #ORM\OneToMany(targetEntity="Date", mappedBy="event")
*/
protected $dates;
And in my Date entity I have:
/**
* #ORM\ManyToOne(targetEntity="Event", inversedBy="dates")
*/
private $event;
I have also generated a CRUD (doctrine:generate:crud) on the Event entity so that I may add events to the database. In the form builder in my EventType I have added:
->add('date', new DateType())
This is so that I may include the date field in the form, as per the Symfony documentation.
Now comes my problem.
Whenever I run doctrine:generate:entities my entities are created on the Event and Date entity, but they seem to be the wrong way around. On my Event entity I get:
/**
* Constructor
*/
public function __construct()
{
$this->dates = new \Doctrine\Common\Collections\ArrayCollection();
}
/**
* Add dates
*
* #param \Raygun\EventBundle\Entity\Date $dates
* #return Event
*/
public function addDate(\Raygun\EventBundle\Entity\Date $dates)
{
$this->dates[] = $dates;
return $this;
}
/**
* Remove dates
*
* #param \Raygun\EventBundle\Entity\Date $dates
*/
public function removeDate(\Raygun\EventBundle\Entity\Date $dates)
{
$this->dates->removeElement($dates);
}
/**
* Get dates
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getDates()
{
return $this->dates;
}
and on my Date entity I get:
/**
* Set event
*
* #param \Raygun\EventBundle\Entity\Event $event
* #return Date
*/
public function setEvent(\Raygun\EventBundle\Entity\Event $event = null)
{
$this->event = $event;
return $this;
}
/**
* Get event
*
* #return \Raygun\EventBundle\Entity\Event
*/
public function getEvent()
{
return $this->event;
}
Now when I try to load the form so I can add the event/date to the database I get
Neither the property "date" nor one of the methods "getDate()", "date()", "isDate()", "hasDate()", "__get()" exist and have public access in class "Raygun\EventBundle\Entity\Event".
It's like it should be adding getters and setters to the Event entity, NOT the Date entity. I'm really tearing my hair out with this and am thinking of ditching Symfony entirely, as it seems to go completely against logic.
if you want Form component automatically mappes the fields you should change date field to dates:
->add('dates', 'collection', [
'type' => new DateType()
])
or you can add mapped => false option to your date field to map it manually.
Your Event form type should contain a collection type for the protected $dates field, so this line is incorrect:
->add('date', new DateType())
It should be:
->add('dates', 'collection', array('type' => new DateType()))
Please have a look at this Symfony cookbook entry on how to work with form collections:
http://symfony.com/doc/current/cookbook/form/form_collections.html
I'm new to Symfony2. I have to learn it for my new job (it starts this monday). Before that, I used a lot CodeIgniter... so this change a bit.
After reading tons of documentations, tuts, best practices ... create my Own intranet for testing (customers has websites, websites has accesses, accesses has website, website has category, accesses has accesscategory) I still have some questions.
First Question :
When you have a website with frontend and backend you have all the time some repetitives actions like :
- create new entity
- read entity
- update entity
- delete entity
...
In CI, I create a BaseController and a BaseModel and with some extends, I was OK.
This practice is still OK for Symfony 2 or do Symfony have another way to handle that ?
Like AppBundle\Controller\BaseController extended by a AppBundle\Controller\AdminController (and FrontController) extended by AppBundle\Controller\MyEntityController ?
Because Actually, each time, in each controller I have the same code. When I edit an entity (for example), it's the same process : load the entity by id, throw exception if no entity, create and hydrate the form, handleRequest the post and valid the form, reidrect or display the view... but... I always cut/paste the same code... aweful T__T
So I'm searching for the best way to handle that
** Second Question : **
What is the best and elegent way to work with the DoctrineManager ?
Do I have to call it, each time in my actions ? $em = $this->get... or, can I create something like MyEntityManager which call the EntityManager and the repository of my entity ?
Actually, this is what I do :
I create an abstract AppBundle\Manager\BaseManager with loadAndFlush
<?php
namespace AppBundle\Manager;
abstract class BaseManager
{
protected function persistAndFlush($entity)
{
$this->em->persist($entity);
$this->em->flush();
}
}
Then, for each Entity, I create his own manager :
<?php
namespace AppBundle\Manager;
use Doctrine\ORM\EntityManager;
use AppBundle\Manager\BaseManager;
use AppBundle\Entity\Customer;
class CustomerManager extends BaseManager
{
/**
* #var EntityManager
*/
protected $em;
/**
* #param EntityManager $em
*/
public function __construct(EntityManager $em)
{
$this->em = $em;
}
/**
* #param $customerId
* #return null|object
*/
public function loadCustomer($customerId)
{
return $this->getRepository()
->findOneBy(array('id' => $customerId));
}
/**
* #param Customer $customer
*/
public function saveCustomer(Customer $customer)
{
$this->persistAndFlush($customer);
}
/**
* #return \Doctrine\ORM\EntityRepository
*/
public function getRepository()
{
return $this->em->getRepository('AppBundle:Customer');
}
}
Then, I define this manager as a service :
parameters:
app.customer_manager.class: AppBundle\Manager\CustomerManager
services:
app.customer_manager:
class: %app.customer_manager.class%
arguments: [#doctrine.orm.entity_manager]
And Then I use the service in my Controller :
/**
* #Route("/edit/{customerId}", name="customer_edit")
* #Security("has_role('ROLE_ADMIN')")
*/
public function editAction($customerId, Request $request)
{
if (!$customer = $this->get('app.customer_manager')->loadCustomer($customerId)) {
throw new NotFoundHttpException($this->get('translator')->trans('This customer does not exist.'));
}
$form = $this->get('form.factory')->create(new CustomerType(), $customer);
if($form->handleRequest($request)->isValid()) {
$this->get('app.customer_manager')->saveCustomer($customer);
$request->getSession()->getFlashBag()->add('notice', 'Client bien enregistré.');
return $this->redirect(
$this->generateUrl(
'customer_show', array(
'customerId' => $customer->getId()
)
)
);
}
return $this->render('default/customer/add.html.twig', array(
'form' => $form->createView(),
'customer' => $customer
));
}
Is it a good practice, is it too complicated ? Is there any better other way to process in symfony ?
For first question Symfony2 provides CRUD Generator, take a look at this.
For second one you should use Repository Pattern provided by framework, for more information about this checkout following links:
http://msdn.microsoft.com/en-us/library/ff649690.aspx
http://symfony.com/doc/current/book/doctrine.html#custom-repository-classes
Let say I have a Company for which I manage Employees, Cars, Contracts, Buildings, Sites, Products, etc. As you can guess, these are quite independant things, so no inheritance is possible.
For each of these elements (i.e. Entities), I want to be able to attach one or several Documents (click on a button, form opens, select one/several Document or upload a new one).
Linking Document to one kind of entity is not a problem, my problem is that there are many kinds of entities. How should I manage that? I have 2 ideas which have their own problems...:
Create a ManyToMany relationship between Document and Employee, another between Document and Car, etc.
Problem: I have to duplicate the Controller code to attach Document, duplicate the forms, etc.
Create a single join table containing the Document's ID, the related entity's ID and the related entity's class name.
Problem: it doesn't look really clean to me, I didn't really dig in this way but I feel I'll have a lot of "entity mapping" problems.
Any suggestion?
[EDIT]
In fact I have to do the same for Event as well: I need to link some Events to some Employees and/or to some Cars, etc. And in my real case, I have more than 10 Entities to be linked to Event and/or Document, which means duplicating more tha 20 times the code if I go with the solution 1!
Assuming you're using Doctrine ORM, i think you're searching for the Mapped Superclasses inheritance.
The docs are better than words :
http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/inheritance-mapping.html#mapped-superclasses
So finally I managed to solve my problem, following #Rpg600 idea about Mapped Superclasses.
This is probably not the best and cleanest solution ever, I'm not really proud of it but it does the job and it is still better than my first ideas.
I create a BaseEntity which is my a mapped superclass (Employee, Car, etc. Entities have to extend this Class):
/**
* BaseEntity
* #ORM\MappedSuperclass
*/
class BaseEntity {
/**
* #ORM\OneToOne(targetEntity="MyProject\MediaBundle\Entity\Folder")
*/
private $folder;
/**
* Set folder
* #param \Webobs\MediaBundle\Entity\Folder $folder
* #return BaseEntity
*/
public function setFolder(\Webobs\MediaBundle\Entity\Folder $folder = null){
$this->folder = $folder;
return $this;
}
/**
* Get folder
* #return \Webobs\MediaBundle\Entity\Folder
*/
public function getFolder(){
return $this->folder;
}
}
As it is not possible to have a Many-to-Many relationship in a superclass, I use a Folder which will contain one or several Document. This is the dirty part of the solution ; the folder table basically contain only one field which is the id...
class Folder
{
private $id;
/**
* Note : Proprietary side
* #ORM\ManyToMany(targetEntity="MyProject\MediaBundle\Entity\Document", inversedBy="folders", cascade={"persist"})
* #ORM\JoinTable(name="document_in_folder")
*/
private $documents;
// setters and getters
Then I create a helper class (which is declared as a service) to manage the link between any Entity and the Document:
class DocumentHelper extends Controller
{
protected $container;
/** ************************************************************************
* Constructor
* #param type $container
**************************************************************************/
public function __construct($container = null)
{
$this->container = $container;
}
/** ************************************************************************
* Attach Document(s) to an $entity according to the information given in the
* form.
* #param Entity $entity
* #param string $redirectRouteName Name of the route for the redirection after successfull atachment
* #param string $redirectParameters Parameters for the redirect route
* #return Response
**************************************************************************/
public function attachToEntity($entity, $redirectRouteName, $redirectParameters)
{
$folder = $entity->getFolder();
if($folder == NULL){
$folder = new Folder();
$entity->setFolder($folder);
}
$form = $this->createForm(new FolderType(), $folder);
// ------------- Request Management ------------------------------------
$request = $this->get('request');
if ($request->getMethod() == 'POST') {
$form->bind($request); // Link Request and Form
if ($form->isValid()) {
$em = $this->getDoctrine()->getManager();
$em->persist($folder);
$em->persist($entity);
$em->flush();
return $this->redirect($this->generateUrl($redirectRouteName, $redirectParameters));
}
}
return $this->render('MyProjectMediaBundle:Folder:addDocument.html.twig', array(
'form' => $form->createView(),
'entity' => $entity,
));
}
Doing that way, I just have to add one small action in each relevant controller, let say EmployeeController.php:
public function addDocumentAction(Employee $employee)
{
$redirectRouteName = 'MyProjectCore_Employee_see';
$redirectParameters = array('employee_id' => $employee->getId());
return $this->get('myprojectmedia.documenthelper')->attachToEntity($employee,$redirectRouteName,$redirectParameters);
}
Same principle for the display, in the helper I have the common function which I call in my already-existing seeAction() and in the TWIG file I import the common "Document list" display.
That's all folks!
I hope this can help :)
I have a User class which have a One-to-One association with another entity Result
Everything is working fine but anytime I load a set of users, i can see in the profiler that for each user symfony makes a query to load his result.
I don't need the result everywhere, and i manually retrieve it when i need.
I came to believe that symfony loads one-to-one relations automatically with the entity but didn't find out how to avoid it.
My classes :
class User extends BaseUser {
/**
* #ORM\OneToOne(targetEntity="Result", mappedBy="user", cascade={"all"}, orphanRemoval=TRUE)
*/
protected $result;
}
class Result {
/**
* #ORM\OneToOne(targetEntity="User", inversedBy="result")
* #ORM\JoinColumn(name="id_user", referencedColumnName="id")
*/
protected $user;
}
----- EDIT -----
I found out that it only happen when the User entity is loaded in a formbuilder :
$builder
->add('user', 'entity', array(
'class' => 'ThemBaseBundle:User',
'query_builder' => function($repository) {
return $repository->createQueryBuilder('a')
->orderBy('a.lastName', 'ASC');
},
'property' => 'fullName'
))
;
I'm not sure, but probably one-to-one relations are fetched eagerly by default. Try switching the fetching strategry to lazy. See this section for more information.