I have two classes:
User:
/** #Entity #Table(name="users") */
class User {
/**
* #Id #GeneratedValue #Column(type="integer")
* #var integer
*/
protected $id;
/**
* #Column(type="string", length=20, unique=TRUE)
* #var string
*/
protected $login;
/**
* #OneToMany(targetEntity="News", mappedBy="author")
*/
protected $news;
public function __construct() {
$this->news = new \Doctrine\Common\Collections\ArrayCollection;
}
}
and News:
/** #Entity #Table(name="news") */
class News {
/**
* #Id #GeneratedValue #Column(type="integer")
* #var integer
*/
protected $id;
/**
* #Column(type="string", length=100)
* #var string
*/
protected $title;
/**
* #Column(type="text")
* #var string
*/
protected $content;
/**
* #ManyToOne(targetEntity="User", inversedBy="news")
* #JoinColumn(referencedColumnName="id")
*/
protected $author;
}
When I will make this code
$q = $this->db->createQuery('SELECT u FROM User u WHERE u.id = '.$id);
$user = $q->getSingleResult();
does the Doctrine will download all news (created by particular user) from database?
It won't until you request a user's news by calling the news accessor method. If you rewrite your query as
SELECT u, n FROM User u JOIN u.news n
Then a user and his news will be all returned as the result.
You can also check the query generated by doctrine using a logger:
$config->setSQLLogger(new Doctrine\DBAL\Logging\EchoSQLLogger);
PS: never do this: u.id = '.$id in queries to avoid sql injections. Instead, use placeholders:
$q = $this->db->createQuery('SELECT u FROM User u WHERE u.id = :id');
$q->setParameter('id', $id);
Related
In Symfony, we can get current logged-in user data using $this->getUser(), but my problem is when I access this statement, I am getting all the user-associated data set. which has OneToMany relationships with another entity, and it has a lot of data.
Example:
User Entity
`
class User implements UserInterface
{
/**
* #var string
* #ORM\Id
* #ORM\Column(type="string", length=10)
*
*/
protected $id;
/**
* #var string
* #ORM\Column(type="string")
*/
protected $email;
/**
* #var array
* #ORM\Column(type="json")
*/
protected $roles;
/**
* One User has Many Posts.
* #ORM\OneToMany(targetEntity="App\Entity\Post", mappedBy="user", fetch="LAZY")
*
*
*/
private Collection $posts;
`
Post Entity
`
class Post
{
/**
* #var string
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
* #ORM\Column(type="integer", length=11)
*/
private $id;
/**
* Many posts have one user.
* #ORM\ManyToOne(targetEntity="App\Entity\User", inversedBy="post", fetch="EXTRA_LAZY")
* #ORM\JoinColumn(name="userId", referencedColumnName="id")
*/
private $user;
`
I am looking to get rid of the user-associated data set or limit the associated data set to limit 1.
Thank you for the help in advance. :)
found solution after hours of search.
You will be required to add Symfony Serializer #Ignore attribute on the Entity class.
Example
use Symfony\Component\Serializer\Annotation\Ignore;
class User implements UserInterface
{
/**
* #var string
*
*/
#[ORM\Id]
#[ORM\Column(type: 'string', length: 10)]
protected $id;
/**
* #var string
*/
#[ORM\Column(type: 'string')]
protected $email;
/**
* #var array
*/
#[ORM\Column(type: 'json')]
protected $roles;
/**
* #var Post
*/
#[ORM\OneToMany(targetEntity: 'App\Entity\Post', mappedBy: 'user', fetch: 'LAZY')]
#[Ignore]
private Collection $posts;
I hope this help someone. Cheers!
I got this error from my UserRepository:
[Semantical Error] line 0, col 51 near 'h': Error: Class DokMngr\Entity\User has no association named id
I understand that the error comes from the missing declaration inside my user entity. I can not find a correct syntax when a field is both a generated id and a OneToMany association.
Hope somebody can help me to solve my problem or at least explain why I can't use an id as an association.
class UserRepository extends EntityRepository
{
public function findAllwithHistoryCount() {
$qb = $this->createQueryBuilder('u')
->leftJoin('u.id', 'h');
return $qb->getQuery()->getResult();
}
}
/**
* #Entity(repositoryClass="DokMngr\Repository\UserRepository")
* #Table(name="users")
*/
class User implements UserInterface
{
/**
* #Id
* #Column(type="integer")
* #GeneratedValue
*/
protected $id;
}
/**
* #Entity(repositoryClass="DokMngr\Repository\HistoryRepository")
* #Table(name="history")
*/
class History
{
/**
* #Id
* #Column(type="integer")
* #GeneratedValue
*/
protected $id;
/**
* #ManyToOne(targetEntity="User", inversedBy="id")
* #JoinColumn(name="user", referencedColumnName="id")
*/
protected $user;
}
Thanks to Olibiaz I found my error in reasoning.
I thought the whole time that I have to create an association between User.id and History.user like inside the database.
But instead I have to create a new field histories in my User entity. (which exactly not exist inside the database)
So here's the corrected entities:
User
use Doctrine\Common\Collections\ArrayCollection;
/**
* #Entity(repositoryClass="DokMngr\Repository\UserRepository")
* #Table(name="users")
*/
class User implements UserInterface
{
/**
* #Id
* #Column(type="integer")
* #GeneratedValue
*/
protected $id;
/**
* #OneToMany(targetEntity="History", mappedBy="user")
*/
private $histories;
}
History
/**
* #Entity(repositoryClass="DokMngr\Repository\HistoryRepository")
* #Table(name="history")
*/
class History
{
/**
* #Id
* #Column(type="integer")
* #GeneratedValue
*/
protected $id;
/**
* #ManyToOne(targetEntity="User", inversedBy="histories")
* #JoinColumn(name="user", referencedColumnName="id")
*/
protected $user;
}
I have a Developers entity and table named CodeUserReference
class CodeUserReference
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
*#ORM\ManyToOne(targetEntity="Artel\CustomerBundle\Entity\Developers", inversedBy="newreference")
*/
protected $alluser;
/**
* #ORM\Column(type="string", length=255)
*/
protected $codereference;
and Developers
class Developers extends SUser
{
/**
* #var string
*
* #ORM\Column(name="email", type="string", length=255, unique=false, nullable=false)
* #Assert\Length(min=3, max=255)
* #Assert\NotBlank
*/
protected $email;
/**
* #ORM\ManyToMany(targetEntity="Artel\CustomerBundle\Entity\CodeUserReference", inversedBy="alluser")
*/
protected $newreference;
I have get query in my Action
public function profileGetAction(Request $request)
{
$em = $this->getDoctrine()->getManager();
$code_user_reference = $em->getRepository('ArtelCustomerBundle:CodeUserReference')->findOneByCodereference($request->query->get('reference'));
$user_by_email = $em->getRepository('ArtelCustomerBundle:Developers')->findOneByEmail($request->query->get('email'));
if (!empty($code_user_reference) && empty($user_by_email))
{
$id = $code_user_reference->getAlluser()->getId();
$user_by_reference = $em->getRepository('ArtelCustomerBundle:Developers')->findOneById($id);
$user_by_reference_json = $em->getRepository('ArtelCustomerBundle:Developers')->createQueryBuilder('d')
->where('d.id= :id')
->groupBy('d.id')
->setParameter('id', $code_user_reference->getAlluser()->getId())
->getQuery()->getArrayResult();
echo json_encode( array('user' => $user_by_reference_json));
die;
}
If(empty($code_user_reference) && !empty($user_by_email))
.......
I get Id in code_user_reference, then I find Developers objects with this ID, then I create a QueryBuilder and in this QueryBuilder I find the developers objects again, for JSON table. I find this very hard, who knows easier practics ?
There is certanly mismapping.
if you have #ORM\ManyToOne from one site, there should be #ORM\OneToMany from other.
Or, if you need many-to-many relationship, there should be #ORM\ManyToMany on both entities.
Also, relation should be mapped at one side. If you have (targetEntity="Artel\CustomerBundle\Entity\Developers", inversedBy="newreference") it means it should be mapped here
something like
#ORM\ManyToOne(targetEntity="Artel\CustomerBundle\Entity\Developers", inversedBy="newreference")
#ORM\JoinColumn(name="id_developer", referencedColumnName="id")
and at the other side must be mappedBy instead of inversedBy
* #ORM\OneToMany(targetEntity="Artel\CustomerBundle\Entity\CodeUserReference", mappedBy="alluser")
I have the following situation:
/**
* #Entity
* #Table(name="users")
*/
class Users{
/**
*
* #Id #Column(type="integer")
* #GeneratedValue
*/
protected $id_user;
/**
* #OneToMany(targetEntity="Items",mappedBy="user")
*/
private $items;
//this method sould return distinct items by name or group by name
public function getItems(){
return $this->items;
}
}
/**
* #Entity
* #Table(name="items")
*/
class Items{
/**
*
* #Id #Column(type="integer")
* #GeneratedValue
*/
protected $id_item;
/**
*
* #Id #Column(type="string")
*/
protected $name;
/**
* #ManyToOne(targetEntity="User",inversedBy="items")
* #JoinColumn(name="id_user", referencedColumnName="id_user" ,onDelete="CASCADE")
*/
protected $user;
}
In my view i send an $UserEntity, my problem is that i want to display only items that have unique name.
So If i do $items=$userEntity->getItems(); i receive all user items, not only unique one.
How can i solve this situation?
Thanks
select distinct with DQL should do the trick
I'm having problems writing a correct DQL for my code (Exception : Invalid PathExpression. Must be a StateFieldPathExpression).
I'll start by sketching the structure of my project.
Every entity inherits from IdentifiableObject that provides every entity with an id
/**
* #MappedSuperclass
*/
class IdentifiableObject {
/**
* #Id
* #Column(type="integer")
* #GeneratedValue(strategy="IDENTITY")
*/
protected $id;
/**
* getters and setters go here
*/
}
Then we have a User object that has a list of "UserProperties"
/**
* #Entity
* #Table(name="users")
*/
class User extends IdentifiableObject {
/**
* Other unimportant vars go here
*/
/**
* #Column(type="string")
*/
private $userName;
/**
* #OneToMany(targetEntity="UserProperty", mappedBy="user", cascade={"persist", "remove"}, orphanRemoval=true)
*/
private $userProperties = null;
public function __construct() {
$this->userProperties = new ArrayCollection();
}
/**
* Getters and setters go here
*/
}
The Userproperty has a property (which is basicaly a type saying what kind of userproperty it is) and a value
/**
* #Entity
* #Table(name="userProperties")
*/
class UserProperty extends IdentifiableObject {
/**
* #OneToOne(targetEntity="Property")
* #JoinColumn(name="propertyID", referencedColumnName="id")
*/
private $property;
/**
* #ManyToOne(targetEntity="User")
* #JoinColumn(name="userID", referencedColumnName="id")
*/
private $userValue
}
And finally the Property
/**
* #Entity
* #Table(name="properties")
*/
class Property extends IdentifiableObject {
/**
* #Column(type="string")
*/
private $name;
/**
* #Column(type="string")
*/
private $description;
/**
* #Column(type="integer")
*/
private $mandatory = 0;
/**
* #OneToOne(targetEntity="PropertyType")
* #JoinColumn(name="type", referencedColumnName="id")
*/
private $type;
}
What i would like to do is get all Users that have a Userproperty corresponding to a certain Property.
My attempt was :
$queryUserId = "SELECT userprop.user FROM UserProperty userprop JOIN userprop.property prop WHERE prop.id = '$propertyId'";
or
$queryUserId = "SELECT user FROM User user JOIN user.userProperties userprop WHERE userprop in(SELECT up FROM UserProperty up WHERE up.property = '$property')";
As of today i'm not able to get something sensible out of the system other then "Invalid PathExpression. Must be a StateFieldPathExpression"...
Anyone can help?
Edit: I'll clarify what i'm trying to do here.
What i want is the DQL version of this sql query (which works):
SELECT *
FROM users
WHERE id
IN (
SELECT u.userId
FROM userproperties u, properties p
WHERE u.propertyID = p.id
AND p.id =1
)
Where the p.id = xxx would be the property object (or at least the id) that i want to use in my search.
Ok seems i have found a working DQL solution:
$query = "SELECT user from User user WHERE user.id in(SELECT u FROM UserProperty up JOIN up.user u WHERE up.property = '$property')"
Works! (You need to join on user in the subQuery else you get the dreaded "Invalid PathExpression" exception.