QueryBuilder Invalid PathExpression. Must be a StateFieldPathExpression - php

Trying to fetch all supplierUsers where the id is DISTINCT and hydrate the results.
The SQL query to get all the results would be the following
SELECT DISTINCT supplier_user_id FROM job_item_quote
The Query builder to fetch the above.
$qb = $this->createQueryBuilder('a')
->select('a.supplierUser')
->distinct(true);
$result = $qb->getQuery()->getResult();
Outputted getQuery(). Which is exactly what I'm looking for.
SELECT DISTINCT a.supplierUser FROM Project\Entities\JobItemQuote a
The error thrown when trying to fetch distinct users
[Semantical Error] line 0, col 18 near 'supplierUser,': Error: Invalid PathExpression. Must be a StateFieldPathExpression.
I've tried adding joins in for supplierUser in hopes it would fix. Same error thrown.
JobItemQuote Entity
/**
* #ORM\Entity(repositoryClass="Project\Repositories\JobItemQuote\JobItemQuoteRepository")
* #ORM\Table(name="job_item_quote")
*/
class JobItemQuote extends BaseEntity
{
public static $joins = [
'supplierUser' => SupplierUser::class,
'jobItem' => JobItem::class
];
/**
* #ORM\Id
* #ORM\GeneratedValue
* #ORM\Column(type="integer")
* #var int
*/
protected $id; // thekey
/**
* #ORM\ManyToOne(targetEntity="JobItem", inversedBy="quotes")
* #var JobItem
*/
protected $jobItem;
/**
* #ORM\ManyToOne(targetEntity="SupplierUser")
* #var SupplierUser
*/
protected $supplierUser;
....
}
SupplierUser Entity
/**
* #ORM\Entity(repositoryClass="Project\Repositories\SupplierUser\SupplierUserRepository")
* #ORM\Table(name="supplier_user")
*/
class SupplierUser extends User {
public static $joins = [
'supplier' => Supplier::class,
'supplierGroup' => SupplierGroup::class
];
/**
* #ORM\OneToOne(targetEntity="Supplier", inversedBy="supplierUser", cascade={"persist"})
* #var Supplier
*/
protected $supplier;
/**
* #ORM\ManyToOne(targetEntity="SupplierGroup")
* #var Group
*/
protected $supplierGroup;
....
}

Your need is to retrieve the list of supplierUsers associated with JobItemQuote, so you should make the query in JobItemQuoteRepository making a join with supplierUsers, you find bellow the example :
$qb = $this->createQueryBuilder('jiq')
->select('su')
->join(SupplierUser::class, 'su', Join::With, 'su.id = jiq.supplierUser')
->distinct(true)
;
$result = $qb->getQuery()->getResult();
By this query you will have the list of SupplierUser (distinctly) assoiated to JobsItemQuote.

Related

Doctrine ORM Association creates PHP proxy class

Why are Proxy classes created instead of entity objects?
DoctrineORMModule\Proxy\__CG__\App\Entity\FormType vs \App\Entity\FormType
Setup: Laminas, Doctrine ORM
Class Project{}
Class ProjectForm
{
/**
* #ORM\Id
* #ORM\Column(name="id")
* #ORM\GeneratedValue
*/
protected $id;
/**
* #ORM\OneToOne(targetEntity="FormType")
* #ORM\JoinColumn(name="form_type_id", referencedColumnName="id")
*/
protected $formType;
/**
* #ORM\OneToOne(targetEntity="Project")
* #ORM\JoinColumn(name="project_id", referencedColumnName="id")
*/
protected $project;
/**
* #ORM\Column(name="label")
*/
protected $label;
/**
* #ORM\Column(name="status")
*/
protected $status;
/**
* #ORM\Column(name="order_nr")
*/
protected $order;
}
Class FormType
{/**
* #ORM\Id
* #ORM\Column(name="id")
* #ORM\GeneratedValue
*/
protected $id;
/**
* #ORM\Column(name="code")
*/
protected $code;
/**
* #ORM\Column(name="label_txt")
*/
protected $label;
:
:
}
Then, using a custom extended Repository use the query builder to get data from storage
$qb->select('pc','ft')
->from(\App\Entity\ProjectForm::class,'pc')
->join(\App\Entity\FormType::class,'ft')
->where($qb->expr()->eq('pc.project',$projectId))
->andWhere('pc.formType=ft.id');
SQL Generated is/seems correct (when passing project ID 1) and returns the correct number of rows
SELECT p0_.id AS id_0, p0_.label AS label_1, p0_.status AS status_2, p0_.order_nr AS order_nr_3, f1_.id AS id_4, f1_.code AS code_5, f1_.label_txt AS label_txt_6, p0_.form_type_id AS form_type_id_7, p0_.project_id AS project_id_8 FROM project_forms p0_ INNER JOIN form_types f1_ WHERE p0_.project_id = 1 AND p0_.form_type_id = f1_.id
The same resultset is visible via
$this->getEntityManager()->getRepository(\Eho\Core\Entity\ProjectForm::class)->findBy(['project'=>$projectId],[]);
With $result[0]->getProject()->getTitle() returning the correct string but $result[0]->getFormType()->getName() throwing and error due to class \DoctrineORMModule\Proxy\__CG__\Entity\FormType being returned from getFormType()...???
Project::getTite() -> string
ProjectForm->getName() -> string
EDIT: Also tried different join for giggles
$joinOn = \Doctrine\ORM\Query\Expr\Join::ON;
$joinWith = \Doctrine\ORM\Query\Expr\Join::WITH;
$qb->select('pf','ft')
->from(\App\Entity\ProjectForm::class,'pf')
->innerJoin(\App\Entity\FormType::class,'ft',$joinWith, 'pf.formType=ft.id')
->where($qb->expr()->eq('pf.project',$projectId));
With SQL generated:
SELECT ...fields... FROM project_forms p0_ INNER JOIN form_types f1_ ON (p0_.form_type_id = f1_.id) WHERE p0_.project_id = 1
But the same resultsets (with Proxy classes are returned)...
Why is ONE entity (project) populated correctly and another (formType) as a proxy...?

"NOT EXISTS" Query with Many to Many Relation Doctrine Symfony3

I would like to build a query that brings me all the games for a logged in user that he has not yet joined. For this I have built these 2 Entities. They are connected by many to many.
class Game
{
public function __construct()
{
$this->users = new ArrayCollection();
}
/**
* #ORM\Column(type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
*
* #var Users[]
*
* #ORM\ManyToMany(
* targetEntity="Domain\Entity\User",
* inversedBy="user",
* fetch="EAGER"
* )
*/
private $users;
/**
* #return array
*/
public function getUsers() : array
{
return $this->users->getValues();
}
/**
* #param User $users
*/
public function setUser($users)
{
if(is_array($users)){
/** #var User $user */
foreach ($users as $user){
$this->users->add($user);
}
} else {
$this->users->add($users);
}
}
}
And the User Entity
class User implements AdvancedUserInterface
{
/**
* #ORM\Column(type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
}
The Entities has more attributes but i think they are not important.
Also I tried these Query, but it doesn't work.
/**
* #param User $user
* #return array
*/
public function fetchAllNonActivatedWhereYouNotJoin(User $user): array
{
$qb = $this->createQueryBuilder('g');
$qb->select('g')
->innerJoin('g.users', 'u')
->where('u.id != :user')
->andWhere('g.activate = 0')
->setParameter('user', $user->getId())
->getQuery()->getResult();
return $qb->getQuery()->getResult();
}
Does anyone know a solution? Its Symfony 3 and Doctrine in PHP 7.1
One way to do it is left join the 2 entities starting from the game repository as you do, with a join condition to the logged in user and have a condition that users is empty:
$qb->leftJoin('g.users', 'u', Join::WITH, 'u.id = :user')
->andWhere('g.activate = 0')
->having('COUNT(u) = 0')
->groupby('g')
->setParameter('user', $user->getId())
->getQuery()->getResult();
This works because of doctrine hydration, which hydrates the users property on the limited joined query(in this case each game will either have the logged in user or not in the users collection).
There are also other ways to achieve this
Be careful with this if you are doing consecutive queries with the query builder, as the entity manager keeps references to the already hydrated relations. Reference of the issue

Uncaught PHP Exception Doctrine\ORM\Query\QueryException: "[Semantical Error] line?

I am trying to create a search field for the rejected transactions page in our web application project, I'm using symfony2 framework, I'm stuck coz there was an error saying,
'[Semantical Error] line 0, col 235 near 'b JOIN b.ediAk403ErrorCodes': Error: Class Matrix\MatrixEdiBundle\Entity\EdiTransaction has no association named edi997Details'
and also
'CRITICAL - Uncaught PHP Exception Doctrine\ORM\Query\QueryException: "[Semantical Error] line 0, col 235 near 'b JOIN b.ediAk403ErrorCodes': Error: Class Matrix\MatrixEdiBundle\Entity\EdiTransaction has no association named edi997Details" at /tmxpage/apache/htdocsEDI/Editracker/vendor/doctrine/orm/lib/Doctrine/ORM/Query/QueryException.php line 63 '
here is my code for that (in my repository) :
public function getDetails($gsNumber, $senderId, $receiverId, $page = 1, $limit = 5 ){
$em = $this->getEntityManager();
$query = $em->createQuery(
'SELECT partial a.{ediTransactionId, senderId, receiverId, gsNumber, isaNumber, fileName },
partial b.{errorCodeId, noOfTrans},
partial c.{errorCode, condition}
FROM MatrixEdiBundle:EdiTransaction a
JOIN a.edi997Details b
JOIN b.ediAk403ErrorCodes c
WHERE b.errorCodeId != 1
AND a.flag = 1
AND a.gsNumber LIKE :gsNumber
AND a.senderId LIKE :senderId
AND a.recieverId LIKE :receiverId')
->setParameter('gsNumber', "%gsNumber%")
->setParameter('senderId', "%senderId%")
->setParameter('receiverId'ssss, "%receiverId%")
->setFirstResult(($page-1)*$limit)
->setMaxResults($limit);
$paginator = new Paginator($query, $fetchJoinCollection = false );
$paginator->setUseOutputWalkers(false);
return $paginator;
}
and here is my entity code for the talble ediAk403ErrorCodes :
class EdiAk403ErrorCodes
{
/**
* #var string
*
* #ORM\Column(name="condition", type="string", length=50, nullable=false)
*/
private $condition;
/**
* #var integer
*
* #ORM\Column(name="error_code", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $errorCode;
/**
* Set condition
*
* #param string $condition
* #return EdiAk403ErrorCodes
*/
public function setCondition($condition)
{
$this->condition = $condition;
return $this;
}
/**
* Get condition
*
* #return string
*/
public function getCondition()
{
return $this->condition;
}
/**
* Get errorCode
*
* #return integer
*/
public function getErrorCode()
{
return $this->errorCode;
}
/**
* Get edi997Details
*
* #return \Matrix\MatrixEdiBundle\Entity\Edi997Details
*/
public function getEdi997Details()
{
return $this->edi997Details;
}
}
Seems your Entity Class EdiTransaction don't have an explicit doctrine relation with the table EdiAk403ErrorCodes. So try adding the field definition with the correct annotation in the EdiTransaction class as follow:
EdiTransaction
/**
* #ORM\ManyToOne(targetEntity="Matrix\MatrixEdiBundle\Entity\Edi997Details", inversedBy="editTransactions")
* #ORM\JoinColumn(name="edit_details_id", referencedColumnName="id")
*/
private $edi997Details;
Hope this help
The single letters are used as a short name for a table. In your first line, you associate MatrixEdiBundle:EdiTransaction with the letter a. So a.edi997Details only makes sense if it's a column of the a table. I believe all you need is this:
FROM MatrixEdiBundle:EdiTransaction a
JOIN edi997Details b
JOIN ediAk403ErrorCodes c

How to map and use a DB View from Doctrine2

I have a view on nomencladores schema called obtenerPaisesPorFabricanteProductoSolicitud. This is the content for the view:
SELECT
ps.id AS psid,
ps.nombre,
fps.id AS fpsid
FROM
(
(
nomencladores.pais ps
JOIN nomencladores.pais_fabricante_producto_solicitud pfps ON ((pfps.pais_id = ps.id))
)
JOIN negocio.fabricante_producto_solicitud fps ON (
(
pfps.fabricante_producto_solicitud_id = fps.id
)
)
);
I'm trying to map the view as follow:
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity
* #ORM\Table(name="nomencladores.obtenerPaisesPorFabricanteProductoSolicitud", schema="nomencladores")
*/
class ObtenerPaisesPorFabricanteProductoSolicitud
{
/**
* #ORM\Id
* #ORM\Column(name="psid", type="integer", nullable=false, unique=true)
*/
protected $ps;
/**
* #ORM\Column(name="fpsid", type="integer")
*/
protected $fps;
/**
* #ORM\Column(name="nombre", type="string")
*/
protected $nombre;
public function getPs()
{
return $this->ps;
}
public function getFps()
{
return $this->fps;
}
public function getNombre()
{
return $this->nombre;
}
}
But any time I run this code on it:
$ent = $em->getRepository("AppBundle:ObtenerPaisesPorFabricanteProductoSolicitud")->findBy(
array(
"fps" => $entF->getId()
)
);
I got this result:
An exception occurred while executing 'SELECT t0.psid AS psid1,
t0.fpsid AS fpsid2, t0.nombre AS nombre3 FROM
nomencladores.obtenerPaisesPorFabricanteProductoSolicitud t0 WHERE
t0.fpsid = ?' with params [22]:
SQLSTATE[42P01]: Undefined table: 7 ERROR: relation "nomencladores.obtenerpaisesporfabricanteproductosolicitud" does not
exist LINE 1: ...d1, t0.fpsid AS fpsid2, t0.nombre AS nombre3 FROM
nomenclado...
If I remove the annotations then the error transform on this:
"Class
"AppBundle\Entity\ObtenerPaisesPorFabricanteProductoSolicitud"
is not a valid entity or mapped super class."
Why Doctrine2 or Symfony tries to execute the query instead go through the view? How I can execute the view from Symfony2/Doctrine2 side?
EDIT
As a side note I'm using PostgreSQL as DB and it haves several squemas, in this case I wrote the view at nomencladores schemas but I tried putting also in public schema and none works, apparently Doctrine doesn't find the view on the schema

Doctrine 2 PlainValue expected

I'm having trouble executing a Doctrine DQL Query. This is the error it gives me.
Doctrine\Common\Annotations\AnnotationException: [Syntax Error] Expected PlainValue,
got 'integer' at position 13 in property Base\Session::$lifetime.
My code looks like this:
$query = $em->createQuery("SELECT s FROM Base\Session s WHERE s.session = \"$id\"");
Where $id is the current session_id. My Model looks like:
namespace Base;
/** #Entity #Table(name="session") */
class Session extends Skeleton {
/**
* #Id #Column(type="integer")
* #GeneratedValue(strategy="AUTO")
*/
protected $id;
/** #Column(length=32) */
protected $session;
/** #Column(type=integer) */
protected $lifetime;
/** #Column(type=integer) */
protected $modified;
/** #Column(type="text") */
protected $data;
}
You have two errors in this:
You have to double quote your annotations, i.e. #Column(type="integer") not #Column(type=integer). Doctrine\Common\Annotations\AnnotationException is thrown when your mapping is wrong. This has nothing to do with the query.
Your query should use prepared statements, i.e.
$query = $em->createQuery("SELECT s FROM Base\Session s WHERE s.session = ?1");
$query->setParameter(1, $id);

Categories