Extending SonataAdmin User with ManyToMany field - php

I am currently trying to extend the SonataUserBundle's User to add a new ManyToMany relationship with a existing Entity.
I extended the User based on the answer found here - Extending Sonata User Bundle and adding new fields
User.php
/**
* #ORM\ManyToMany(targetEntity="Foo\BarBundle\Entity\Pledge", inversedBy="pledgedUsers")
**/
private $pledgedOn;
// (...) generated getters and setters here
Pledge.php
/**
* #ORM\ManyToMany(targetEntity="Foo\UserBundle\Entity\User", inversedBy="pledgedOn")
**/
private $pledgedUsers;
// (...) generated getters and setters here
The first thing I noticed when I sync the schema, is that it creates 2 pivot tables, instead of just one: pledge_user and user_pledge. I tried adding a #ORM\JoinTable in, but that's just changing the name of one. When I add the same #ORM\JoinTable to both, I get the 'table already exists' error.
When I try to access the user list in admin, I am getting a big sql error
An exception occurred while executing 'SELECT count(DISTINCT u0_.id) AS sclr0 FROM User u0_ LEFT JOIN fos_user_user_group f2_ ON u0_.id = f2_.user_id LEFT JOIN fos_user_group f1_ ON f1_.id = f2_.group_id':
SQLSTATE[42703]: Undefined column: 7 ERROR: column u0_.id does not exist
I am sure this is something simple, but I am smacking my head finding the source of this problem. What did I miss?
Full User.php: http://pastebin.com/TXunsgm1
Full Pledge.php: http://pastebin.com/Mta6aiVm

I knew it was a derpy error. I had
* #ORM\ManyToMany(targetEntity="Foo\UserBundle\Entity\User", inversedBy="pledgedOn")
and
* #ORM\ManyToMany(targetEntity="Foo\BarBundle\Entity\Pledge", inversedBy="pledgedUsers")
One of them had to be mappedBy instead of inversedBy . Changing the second one to
* #ORM\ManyToMany(targetEntity="Foo\BarBundle\Entity\Pledge", mappedBy="pledgedUsers")
fixed the problem.

Related

TYPO3: Extend model and map to existing table

I need to create a custom FE user with some custom fields.
Also, it needs to be assignable through the frontend to different user groups.
You can find my first approach here. Didn't work out that well.
Second approach was to create another extension and follow the guide which is shown here.
First thing I did was to add \TYPO3\CMS\Extbase\Domain\Model\FrontendUser into the Extend existing model class-field for my CustomFEU-model.
Then I created another model which I named FEgroup and I mapped it to the table fe_groups. After that, I connected an n:m relation to the CustomFEU.
When I try to create a new CustomFEU with the new action, it returns a white empty page after submitting the form and no user is being added.
The only strange thing I found was that the /Classes/Domain/Repository/ folder is empty.
TYPO3 7.6.8
Although I didn't edit the files yet, here they are:
Model / Controller / Setup
Did anyone encounter similar problems?
First you need to create the repositories that handle the new user and usergroup models.
Second you try to save the user with $this->customFEURepository->add($newCustomFEU); and the variable customFEURepository does not exist. It would be the best to inject it, it has to be the repository that you should create first. You can inject it like that:
/**
* CustomFEUController
*/
class CustomFEUController extends \TYPO3\CMS\Extbase\Mvc\Controller\ActionController
{
/**
* #var \Vendor\Feregistration\Repository\CustomFEURepository
* #inject
*/
protected $customFEURepository;
// other code ...
}
Don't forget to clear the system cache after adding inject annotations, otherwise it wont work.
Last but not least i can't see the mapping to the database table for your model. You need to add it to your TypoScript (setup.txt)
config.tx_extbase.persistence.classes {
Vendor\Feregistration\Domain\Model\CustomFEU {
mapping {
recordType = 0
tableName = fe_users
}
}
Vendor\Feregistration\Domain\Model\FEGroups {
mapping {
recordType = 0
tableName = fe_groups
}
}
}

Doctrine2: Cannot select entity through identification variables without choosing at least one root entity alias

I am stuck with an originally very simple doctrine 2 query. I have an entity called Category which has a OneToMany relation with itself (for parent and child categories).
/**
* #ORM\ManyToOne(targetEntity="Category", inversedBy="children")
*/
private $parent;
/**
* #ORM\OneToMany(targetEntity="Category", mappedBy="parent")
*/
private $children;
The following query
$q = $this->createQueryBuilder('c')
->leftJoin('c.children', 'cc')
->select('c.name as title, cc')
->where('c.parent IS NULL');
fails with error
Cannot select entity through identification variables without choosing at least one root entity alias.
I don't really get the issue. If I omit the ->select part, the query does work and gives the expected result. I have already searched the forum but couldn't find a solution, that worked. Does anyone have a suggestion? Thanks a lot.
Your issue is that you are trying to select one field from the Category entity while simultaneously selecting the entire object of the joined Category entity. Unlike plain SQL, with the QueryBuilder component you can't select an entity only from the table you are joining on.
If you are looking to return your main Category object with the joined children, you can either do ->select(array('c', 'cc')), or simply omit the ->select() call altogether. The former will automatically select the children you need in a single query. The latter will require another SQL query if you want to access children on the main Category entity.
If there is a reason you want name to select as title in your object, you can always add another function to your entity that is an alias for retrieving the name instead of having to write it in your query:
function getTitle()
{
return $this->getName();
}
Your query is missing some parts. Normal query builder in repo goes like
$q = $this->getEntityManager()
->getRepository('MyBundle:Entity')
->createQueryBuilder(‌​'c')
->select(‌​'c')
->leftjoin(‌​'c.children', 'cc')
->addselect(‌​'cc')
->where(‌​'c.parent is NULL')
....
return $q;

Symfony2 - mapping two tables

I want to join two tables (games and ownership). From there, I want to print those Games which user has assigned to him in Ownership. For example: user (id: 2) has two games (id: 1 and id:2). I want to print only these two.
My controller is as follows:
function getGameAction($id) {
$game = $this->getDoctrine()
->getRepository('GameShelfGamesBundle:Game')
->find($id);
return new Response($game->getOwnership()->getName());
}
Entities: Ownership and Game.
For now, I only get an error:
Fatal error: Call to undefined method Proxies__CG__\GameShelf\UsersBundle\Entity\Ownership::getName() in D:!!XAMPP\htdocs\Symfony\src\GameShelf\GamesBundle\Controller\DefaultController.php on line 50
Look at error message - you don't have either any getOwnership method or even relation with ownership table.
For first you need in you game entity declare relation with ownership:
/*
* #ORM\ManyToOne(targetEntity="Namespace\To\Ownership", inversedBy="games")
* #ORM\JoinColumn(name="ownership_id", referencedColumnName="id")
*/
private $ownership;
And in your Ownership entity:
/**
* #ORM\OneToMany(targetEntity="Namespace\To\Game", mappedBy="ownership")
*/
private $games;
Then run console command to generate setters and getters and everything should goes fine.
You just forgot to add a variable named "name" in your Ownership-Entity. Therefore you don't have any getters and setters automatically generated.
Try to put all your variables at the beginning of your code #Cyprian oversaw your relation because of that.
If you just look at the errormessage you should instantly see where your error is coming from.

Doctrine detaching, caching, and merging

I'm on Doctrine 2.3. I have the following query:
$em->createQuery('
SELECT u, c, p
FROM Entities\User u
LEFT JOIN u.company c
LEFT JOIN u.privilege p
WHERE u.id = :id
')->setParameter('id', $identity)
I then take that, get the result (which is an array, I just take the first element), and run detach $em->detach($result);.
When I go to fetch from the cache (using Doctrine's APC cache driver), I do:
$cacheDriver = new \Doctrine\Common\Cache\ApcCache();
if($cacheDriver->contains($cacheId))
{
$entity = $cacheDriver->fetch($cacheId);
$em->merge($entity);
return $entity;
}
My hope was that this would re-enable the relationship loading on the entity as there are many other relationships tied to the User object other than what's shown in that query.
I'm trying to create a new entity like such:
$newEntity = new Entities\ClientType();
$newEntity['param'] = $data;
$newEntitiy['company'] = $this->user['company'];
$em->persist($newEntity);
$em->flush();
When I do this, I get an error:
A new entity was found through the relationship 'Entities\ClientType#company' that was not configured to cascade persist operations for entity:
Entities\Company#000000005d7b49b500000000dd7ad743.
To solve this issue: Either explicitly call EntityManager#persist() on this unknown entity or configure cascade persist this association in the mapping for example #ManyToOne(..,cascade={"persist"}).
If you cannot find out which entity causes the problem implement 'Entities\Company#__toString()' to get a clue.
This works just fine when I don't use the company entity under the user entity that I got from cache. Is there any way to make this work so I don't have to refetch the company entity from the database every time I want to use it in a relationship with a new entity?
Edit:
This is what I have in my User entity dealing with these two relationships:
/**
* #ManyToOne(targetEntity="Company" , inversedBy="user", cascade={"detach", "merge"})
*/
protected $company;
/**
* #ManyToOne(targetEntity="Privilege" , inversedBy="user", cascade={"detach", "merge"})
*/
protected $privilege;
I am still getting the same error.
Second edit:
Trying a $em->contains($this->user); and $em->contains($this->user['company']); both return false. Which sounds... wrong.
When merging a User, you want the associated Company and Privilege to be merged as well, correct?
This process is called cascading:
http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/working-with-associations.html#transitive-persistence-cascade-operations
In your User entity put cascade={"merge"} in the #ManyToOne annotation (or another type of association-definition you are using) for $company and $privilege.
And if you want the detach call to be cascaded too (which is recommended), put in cascade={"detach", "merge"}.
p.s.: Don't put such cascades on both sides of one association, you'll create an endless loop ;)
Edit:
This piece of code:
$entity = $cacheDriver->fetch($cacheId);
$em->merge($entity); // <-
return $entity;
should be:
$entity = $cacheDriver->fetch($cacheId);
$entity = $em->merge($entity); // <-
return $entity;
The thing with merge() is that it leaves the entity you pass as an argument untouched, and returns a new object that represents the managed version of the entity. So you want to use the return-value, not the argument you passed.

1 to 1..0 relationship in an embedded form with doctrine

One user may have just 1 item or none. (1-1..0 relationship)
I'm trying to accomplish that in symfony2 with doctrine.
I've accomplished an 1 to 1 relationship, it's fairly simple. But how can I specify to doctrine that when I want to create an user, the item can be null? (and not to insert a new row and just leave id_item null)
This is what I have:
// User Class
/**
*
* #ORM\OneToOne(targetEntity="Items", cascade={"persist"})
* #ORM\JoinColumn(name="id_item", referencedColumnName="id", nullable=true)
*
* #var SOA\AXBundle\Entity\Items $userItem
* #Assert\Type(type="SOA\AXBundle\Entity\Items")
*/
protected $userItem;
And of course, I created ItemsTypeForm class, and added the type in my userstypeform class:
// UsersTypeForm Class
->add('userItem', new \SOA\AXBundle\Form\ItemsTypeForm())
When I add a new user, everything goes fine. The user is inserted as well as the item. But when I try to add an user where it has no item (user item fields are blank), I get the following error:
SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'name' cannot be null
It is trying to insert the item, with null values.
While I can live with an 1 to 1 relationship, I would like to learn how to make an 1 to 1..0 relationship.
edited with the real problem. edits are bold.
The annotation of the Assert is causing a problem. You must set that the null value is valid in the Assert.

Categories