I'm using FOSUserBundle with Symfony2. I'm attempting to use the Registration Email Confirmation functionality. When I hit the /confirmation/{confirmationToken} url Doctrine throws the following exception
Notice: Undefined index: 000000006553367d000000005133f603 in /Users/jacobspizziri/Documents/Projects/SRC3/vendor/doctrine/orm/lib/Doctrine/ORM/UnitOfWork.php line 2873
This occurs when it tries to hash the Group entity I constructed here:
spl_object_hash($entity)
and $entity looks like this:
Here are the relations I have setup in my entities:
/**
* #ORM\Entity
* #Gedmo\SoftDeleteable(fieldName="deletedAt")
*
* #author jacobspizziri
*/
class Group implements SoftDeletableInterface, TimestampableInterface {
/**
* #ORM\OneToMany(targetEntity="SRC\Bundle\UserBundle\Entity\User", mappedBy="group", cascade={"all"})
*/
protected $users;
}
/**
* #ORM\Entity
* #Gedmo\SoftDeleteable(fieldName="deletedAt")
*/
class User extends BaseUser implements SoftDeletableInterface, TimestampableInterface
{
/**
* #ORM\ManyToOne(targetEntity="SRC\Bundle\UserBundle\Entity\Group", inversedBy="users")
* #ORM\JoinColumn(name="group_id", referencedColumnName="id")
*/
protected $group;
}
My bundle extends FOSUserBundle however I am not extending FOSUserBundle\Entity\Group for my Group
whats going on here?
Related
I'm trying to use the JMSSerializer with Symfony to build a simple json api.
So i have 2 simple Entities (1 User can have many Cars, each Car belongs to one User):
class Car
{
/**
* #ORM\Id()
* #ORM\GeneratedValue()
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\Column(type="string", length=255)
*/
private $name;
/**
* #ORM\ManyToOne(targetEntity="App\Entity\User", inversedBy="cars")
* #ORM\JoinColumn(nullable=false)
*/
private $user;
}
class User extends BaseUser
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #ORM\OneToMany(targetEntity="App\Entity\Car", mappedBy="user", orphanRemoval=true)
*/
private $cars;
}
Now i want to get all Cars with their User.
My Controller:
class CarController extends AbstractController
{
/**
* #param CarRepository $carRepository
*
* #Route("/", name="car_index", methods="GET")
*
* #return Response
*/
public function index(CarRepository $carRepository)
{
$cars = $carRepository->findAll();
$serializedEntity = $this->container->get('serializer')->serialize($cars, 'json');
return new Response($serializedEntity);
}
}
This will throw a 500 error:
A circular reference has been detected when serializing the object of
class \"App\Entity\Car\" (configured limit: 1)
Ok, sounds clear. JMS is trying to get each car with the user, and go to the cars and user ....
So my question is: How to prevent this behaviour? I just want all cars with their user, and after this, the iteration should be stopped.
You need to add max depth checks to prevent circular references.
This can be found in the documentation here
Basically you add the #MaxDepth(1) annotation or configure max_depth if you're using XML/YML configuration. Then serialize like this:
use JMS\Serializer\SerializationContext;
$serializer->serialize(
$data,
'json',
SerializationContext::create()->enableMaxDepthChecks()
);
Example Car class with MaxDepth annotation:
class Car
{
/**
* #\JMS\Serializer\Annotation\MaxDepth(1)
*
* [..]
*/
private $user;
I’m trying to implement this:
With:
User
/**
* #ORM\Entity(repositoryClass="SG\UserBundle\Entity\UserRepository")
* #ORM\Table(name="users")
* #ORM\InheritanceType("JOINED")
* #ORM\DiscriminatorColumn(name="type", columnDefinition="ENUM('lottery')"))
* #ORM\DiscriminatorMap({"lottery"="SG\Lottery\UserBundle\Entity\LotteryUser"})
*/
abstract class User extends Prospect
{
/**
* #ORM\OneToMany(targetEntity="SG\UserBundle\Entity\Subscription", mappedBy="user")
*/
protected $subscriptions;
}
LotteryUser
/**
* #ORM\Entity(repositoryClass="SG\Lottery\UserBundle\Entity\LotteryUserRepository")
* #ORM\Table(name="lottery_users")
*/
class LotteryUser extends User
{
// ...
}
Subscription
/**
* #ORM\Table(name="subscriptions")
* #ORM\Entity(repositoryClass="SG\UserBundle\Entity\SubscriptionRepository")
* #ORM\InheritanceType("JOINED")
* #ORM\DiscriminatorMap({"lottery"="SG\Lottery\UserBundle\Entity\Subscription"})
* #ORM\DiscriminatorColumn(name="game", columnDefinition="ENUM('lottery')"))
*/
abstract class Subscription
{
/**
* #ORM\ManyToOne(targetEntity="SG\UserBundle\Entity\User", inversedBy="subscriptions")
* #ORM\JoinColumn(name="user")
*/
protected $user;
}
Lottery\Subscription
/**
* #ORM\Entity
* #ORM\Table(name="lottery_subscriptions")
*/
class Subscription extends \SG\UserBundle\Entity\Subscription
{
/**
* #ORM\ManyToOne(targetEntity="SG\Lottery\GameBundle\Entity\Package")
* #ORM\JoinColumn(name="package")
*/
protected $package;
}
But when getting the lottery users list with subscription and package tables joined:
$qb = $this->createQueryBuilder('u')
->leftJoin('u.subscriptions', 'sb')
->addSelect('sb')
->leftJoin('sb.package', 'pk')
->addSelect('pk');
It fails:
[Semantical Error] line 0, col 176 near 'p LEFT JOIN u.periods': Error: Class SG\UserBundle\Entity\Subscription has no association named package
I don’t have any idea how to deal correctly, in the Doctrine-way, with this case. I don’t know why Doctrine doesn’t join the subclass Lottery\Subscription to get the package association whereas the subscription entry has its discriminator column to lottery.
Thanks for helping!
Your Entity SG\UserBundle\Entity\Subscription doesn't have $package definition. You have to join to the Lottery\Subscription entity.
class LotteryUser extends User
{
/**
* #ORM\OneToMany(targetEntity="SG\UserBundle\Entity\Lottery\Subscription", mappedBy="user")
*/
protected $lotterySubscriptions;
}
My problem is quite simple but i search for an hour without succeed, i would like to add some constraint to the UserEntity. For example, i would like to limit the length of a username
I think the best way is to not touche FOS in Vendor. I have create my own userBundle with my own layout.html etc ... But i cannot override attribut who is already existing in FosuserBundle (it's working for the layout overriding btw my userBundle is a child of FOS)
the funny thing is "id" has no problem for the overriding
My User entity :
<?php
namespace Diane\UserBundle\Entity;
use FOS\UserBundle\Model\User as BaseUser;
use Doctrine\ORM\Mapping as ORM;
/**
* User
*
* #ORM\Table()
* #ORM\Entity(repositoryClass="Diane\UserBundle\Entity\UserRepository")
*/
class User extends BaseUser
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #var string
* #ORM\Column(name="username", type="string", length=10)
*/
protected $username;
}
Fos User model :
<?php
namespace FOS\UserBundle\Model;
use Doctrine\Common\Collections\Collection;
use Doctrine\Common\Collections\ArrayCollection;
abstract class User implements UserInterface, GroupableInterface
{
protected $id;
/**
* #var string
*/
protected $username;
...
}
i have already try to remove :
/**
* #var string
*/
Error message :
Doctrine\ORM\Mapping\MappingException] Duplicate definition of column
'username' on entity 'Diane\UserBundle\Entity\User' in a field or
discriminator column mapping.
Thanks for any idea you could give me
Try AttributeOverrides Doctrine annotation:
/**
* User
*
* #ORM\Table()
* #ORM\Entity(repositoryClass="Diane\UserBundle\Entity\UserRepository") / class User extends
*
* #ORM\AttributeOverrides({
* #ORM\AttributeOverride(name="username",
* column=#ORM\Column(
* name = "username",
* type = "string",
* length = 10
* )
* )
* })
*
*/
class User extends BaseUser
{
Whats the best practice to check if entity fields exist before persisting it.
Here's the example
Entity
class Pile{
/**
* #var \ABC\CoreBundle\Entity\Record
*
* #ORM\OneToMany(targetEntity="Record")
*
*/
private $records;
/**
* #var \CSC\CoreBundle\Entity\Project
*
* #ORM\ManyToOne(targetEntity="Project")
*
*/
private $project;
/**
* #var string
*
* #ORM\Column(name="Block", type="string", length=255)
*/
private $block;
/**
* #var string
*
* #ORM\Column(name="Type", type="string", length=255)
*/
private $type;
}
class Record{
/**
* #var \CSC\CoreBundle\Entity\Pile
*
* #ORM\ManyToOne(targetEntity="Pile")
*
*/
private $records;
}
There are two controllers that handle the CRUD of Pile and Records.
To create Pile there must not be any duplicate fields [project, block, type]
In Record Controllers I could create Pile together with Record.
Here's the problem where and when do I check the db if a similar Pile entity is created?
Whats the Best Practice?
Copy and paste the query checker in both controller?
Can I use $form->valid() to perform any check in PileType class?
Must I use a service and have both controller to call the service?
In entity life-cycle use pre-insert?
Thanks
Therefore, the fields must be unique?
If so, then it is very simple: UniqueEntity
use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
...
/**
* #ORM\Entity
* #UniqueEntity(
* fields={"project", "block", "type"}
* )
*/
class Pile{
/**
* #var \ABC\CoreBundle\Entity\Record
*
* #ORM\OneToMany(targetEntity="Record")
*
*/
private $records;
/**
* #var \CSC\CoreBundle\Entity\Project
*
* #ORM\ManyToOne(targetEntity="Project")
*
*/
private $project;
/**
* #var string
*
* #ORM\Column(name="Block", type="string", length=255, unique=true)
*/
private $block;
/**
* #var string
*
* #ORM\Column(name="Type", type="string", length=255, unique=true)
*/
private $type;
}
You can use a custom validation constraint in your form, so that $form->isValid() will do the check.
Follow this documentation entry on How to create a Custom Validation Constraint to create the custom validator and then inject doctrine into it to do the check.
UPDATE: Well, I didn't know there was an UniqueEntity Constraint already included in Symfony.
To inject doctrine do the following:
services:
validator.unique.unique_pile:
class: ABC\CoreBundle\Validator\Constraints\UniquePileValidator
arguments: [#doctrine.orm.entity_manager]
tags:
- { name: validator.constraint_validator, alias: unique_pile }
The validator class might then look like this:
// src/ABC/CoreBundle/Validator/Constraints/UniquePileValidator.php
namespace ABC\CoreBundle\Validator\Constraints;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;
class UniquePileValidator extends ConstraintValidator
{
protected $em;
function __construct($em) {
$this->em = $em;
}
public function validate($value, Constraint $constraint)
{
$repo = $this->em->getRepository('ABC\CoreBundle\Entity\Record');
$duplicate_project = $repo->findByProject($value);
$duplicate_block = $repo->findByBlock($value);
$duplicate_type = $repo->findByType($value);
if ($duplicate_project || $duplicate_block || $duplicate_type) {
$this->context->addViolation(
$constraint->message,
array('%string%' => $value)
);
}
}
}
And to be complete, the constraint class:
// src/ABC/CoreBundle/Validator/Constraints/ContainsAlphanumeric.php
namespace ABC\CoreBundle\Validator\Constraints;
use Symfony\Component\Validator\Constraint;
/**
* #Annotation
*/
class ContainsAlphanumeric extends Constraint
{
public $message = 'This Pile already exists!';
public function validatedBy()
{
return 'unique_pile';
}
}
Should be nearly copy/pasteable...
I have AbstractUser super class that extends FOSUser, then I have entities that extends AbstractUser with fields related to that class. For instance Customer has ManyToOne relation to City entity.
Now when I try to log-in with FOSUser login form I'm getting error:
.... SQLSTATE[42S22]: Column not found: 1054 Unknown column 't0.city' in 'field list'
Of course there is no city field in the users table because it's relation column named city_id. Can anybody shed some light for me why doctrine builds query like this? Am I missing something ?
Thanks in advance.
Here is related code parts.
AbstractUser:
/**
* #ORM\Table(name="users")
* #ORM\Entity
* #ORM\MappedSuperclass
* #ORM\InheritanceType("SINGLE_TABLE")
* #ORM\DiscriminatorColumn(name="discr", type="string")
* #ORM\DiscriminatorMap({"admin"="Admin", "customer"="Customer", "seller"="Seller"})
*/
abstract class AbstractUser extends FOSUser
{
/**
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
public function __construct()
{
parent::__construct();
}
}
Customer:
/**
* #ORM\Entity
*/
class Customer extends AbstractUser {
....
/**
* #var City $city
* #ORM\ManyToOne(targetEntity="City", inversedBy="customers")
*/
private $city;
....
}
City:
/**
* #ORM\Table(name="city")
* #ORM\Entity
*/
class City
{
....
/**
* #var ArrayCollection $customers
* #ORM\OneToMany(targetEntity="Customer", mappedBy="city")
*/
private $customers;
....
}
I believe the visibility on $city and $customers has to be protected, not private.
I'm sorry for disturbance. This is my fault that I turned on doctrine cache (and impressed with results btw).
Almost scratched the hole in my head while trying to understand why this is happening. Luckily I ran into another error something woith doctrine and apc. Voila! That gave me a clue where to look.