symfony doctrine getArrayResult error 500 - symfony

I'm trying to grab some data from an table which works fine as long as I don't use
->andwhere('s.client_id = :clientid')
->setParameter('clientid', $this->clientId)
I f use the two line above to locate only neccessary data, I end up in a error 500 :(:(
The entity looks like:
class SanitationType
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #ORM\ManyToOne(targetEntity="Pr\UserBundle\Entity\Client")
* #ORM\JoinColumn(name="client_id", referencedColumnName="id")
*/
private $client;
/**
* #ORM\Column(type="string", length=20)
* #Gedmo\Translatable
*/
private $name;
/**
* #ORM\Column(type="string", length=255, nullable=true)
* #Gedmo\Translatable
*/
private $description;
/**
* #ORM\Column(name="`enabled`", type="boolean")
*/
private $enabled;
/**
* #ORM\Column(type="string", length=255, nullable=true)
*/
private $created_by;
/**
* #ORM\Column(type="datetime", nullable=true)
*/
private $created;
..............
and my script to grab the data inside the controller looks like this:
$query = $em->createQueryBuilder()
->select('s')
->from('PrSensorBundle:SanitationType', 's')
->where('s.enabled = 1')
->andwhere('s.client_id = :client_id')
->setParameter('client_id', $this->clientId)
->orderBy('s.name', 'ASC')
->getQuery();
$results=$query->getArrayResult();
I don't see any error but it is not working at all :(:(
Do I forgot something?

Couple of things. First, it's not clear what $this->clientId refers to, but if you're trying to reference the id of the client object associated with a SanitationType object, then you'd need to have a public getClient() method on the SanitationType class and a getId() method on the Client class. So obtaining the client id from a SanitationType object $sanitationType then becomes:
$sanitationType->getClient()->getId()
Second, there is no client_id property in the SanitationType class. Doctrine sees the properties of a class as you've defined them. So in this case, to look up a SanitationType object(s) in the database by the id of a Client association(s), you would need to perform an inner join. Your query builder would look like this:
$query = $em->createQueryBuilder()
->select('s')
->from('PrSensorBundle:SanitationType', 's')
->innerJoin('s.client', 'sc')
->where('s.enabled = 1')
->andwhere('sc.id = :client_id')
->setParameter('client_id', $this->clientId)
->orderBy('s.name', 'ASC')
->getQuery();
$results=$query->getArrayResult();

Related

Creating more comprehensive associations with Querybuilder in Symfony

I'm building a query that would be for creating a list of Posts that have a Project that is associated to the user, and within that structure hit the right criteria for "tierAccess."
My query builder:
$qb = $this->em->createQueryBuilder();
foreach($subs as $sub)
{
if($sub->getDisabled() == true)
{
continue;
}
$qb->select('p')
->from('App\Entity\ProjectPost', 'p')
->where('project = '.$sub->getProject()->getId())
->andwhere('p.Published = true')
->andwhere('p.TierAccess = '.$sub->getProjectTier()->getId())
->orderBy('p.PostTime', 'DESC');
$query = $qb->getQuery();
$object[] = $query->execute();
}
What I am aiming to do is add posts that the user subscription will allow for, and within that subscription making sure their access to this post is allowed (ie: tierAccess).
I then return the object variable to pass along to my Twig template file.
The error I'm receiving is:
[Semantical Error] line 0, col 45 near 'project = 3 AND': Error: 'project' is not defined.
My ProjectPost entity:
class ProjectPost
{
/**
* #ORM\Id
* #ORM\GeneratedValue
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\Column(type="string", length=255)
*/
private $PostTitle;
/**
* #ORM\Column(type="text", nullable=true)
*/
private $PostHero;
/**
* #ORM\Column(type="string", length=255, nullable=false)
*/
private $PostType;
/**
* #ORM\Column(type="text")
*/
private $PostBody;
/**
* #ORM\ManyToOne(targetEntity=Project::class, inversedBy="projectPosts")
* #ORM\JoinColumn(nullable=false)
*/
private $Project;
/**
* #ORM\Column(type="array", nullable=true)
*/
private $TierAccess = [];
/**
* #ORM\Column(type="datetimetz", nullable=true)
*/
private $PostTime;
/**
* #ORM\ManyToOne(targetEntity=User::class, inversedBy="projectPosts")
* #ORM\JoinColumn(nullable=true)
*/
private $PostBy;
/**
* #ORM\Column(type="array", nullable=true)
*/
private $PostCategories = [];
/**
* #ORM\Column(type="boolean")
*/
private $Published;
/**
* #ORM\Column(type="string", length=255, nullable=true)
*/
private $PostCover;
/**
* #ORM\Column(type="boolean")
*/
private $PostSupporter = 0;
}
The basic mistake is this one:
->where('p.Project = '.$sub->getProject()->getId())
Notice that you declare p to be the alias of Post, and then you don't use it. And even if you define the property as Project, you were trying to use it as project.
Nevertheless, the whole thing is rather suspect. Executing a query within a loop usually points to something wrong with the design.
A simpler approach, using WHERE IN instead of a loop and multiple selects:
// get the "subs" ids in an array:
$subsIds = array_map(fn($s) => $s->getProject()->getId(), $subs);
qb->select('p')
->from('App\Entity\ProjectPost', 'p')
->where('p.Project IN :subsIds')
->andwhere('p.Published = true')
->andwhere('p.TierAccess = '.$sub->getProjectTier()->getId())
->orderBy('p.PostTime', 'DESC')
->setParameter('subsIds', $subsIds)
;
$result = $qb->getQuery()->getResult;

Symfony join entities in one-to-many relationship

I am working on a Symfony project recording sales as relating to stock.
My reasoning:
one sale item is associated to one stock item
one stock item can be associated to multiple sale items
As a result, I setup a one-to-many sale-to-stock relationship as show in the following code snippets:
class Sale
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var float
*
* #ORM\Column(name="cost", type="float")
*/
private $cost;
/**
* #var \DateTime
*
* #ORM\Column(name="date", type="datetime")
*/
private $date;
/**
* #ORM\ManyToOne(targetEntity="iCerge\Salesdeck\StockBundle\Entity\Stock", inversedBy="sales")
* #ORM\JoinColumn(name="sid", referencedColumnName="id")
*/
protected $stock;
...
... and ...
class Stock
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="name", type="string", length=255)
*/
private $name;
/**
* #var \DateTime
*
* #ORM\Column(name="created", type="datetime")
*/
private $created;
/**
* #var \DateTime
*
* #ORM\Column(name="updated", type="datetime")
*/
private $updated;
/**
* #ORM\OneToMany(targetEntity="iCerge\Salesdeck\SalesBundle\Entity\Sale", mappedBy="stock")
*/
protected $sales;
...
NOW, if my code for implementing a one-to-many relationship is correct, I am trying to load a sale object with it's associated stock data in one query using the following code:
public function fetchSale($sid){
$query = $this->createQueryBuilder('s')
->leftjoin('s.stock', 't')
->where('s.id = :sid')
->setParameter('sid', $sid)
->getQuery();
return $query->getSingleResult();
}
The fetchSale function is from my projects SaleRepository.php class.
The leftjoin part of the query is what I hoped would successfully fetch the related stock information but I just get no output ([stock:protected]) as is shown below:
myprog\SalesProj\SalesBundle\Entity\Sale Object
(
[id:myprog\SalesProj\SalesBundle\Entity\Sale:private] => 50
[cost:myprog\SalesProj\SalesBundle\Entity\Sale:private] => 4.99
[date:myprog\SalesProj\SalesBundle\Entity\Sale:private] => DateTime Object
(
[date] => 2015-04-18 17:12:00
[timezone_type] => 3
[timezone] => UTC
)
[stock:protected] =>
[count:myprog\SalesProj\SalesBundle\Entity\Sale:private] => 5
)
How I can successfully fetch a sales' related stock data in the same query?
Doctrine is lazy-loading by default, so it's possible that $stock hasn't been initialized and the dump is not showing it. Try dumping $sale->getStock(). That tells Doctrine to go fetch it.
You can also force the loading of the Stock by selecting it:
public function fetchSale($sid){
$query = $this->createQueryBuilder('s')
->leftjoin('s.stock', 't')
->where('s.id = :sid')
->setParameter('sid', $sid)
->select('s', 't')
->getQuery();
return $query->getSingleResult();
}
By the way, fetchSale($sid) as it is now is the same as calling:
$entityManager->getRepository('SalesBundle:Sale')->find($sid);
You can use Doctrine's eager loading feature.
1. Always load associated object:
If you always want to fetch the stock object when loading the sale object, you can update your entity definition (see docs for #ManyToOne) by adding a fetch="EAGER" to the #ManyToOne definition:
/**
* #ORM\ManyToOne(targetEntity="iCerge\Salesdeck\StockBundle\Entity\Stock", inversedBy="sales", fetch="EAGER")
* #ORM\JoinColumn(name="sid", referencedColumnName="id")
*/
protected $stock;
Doctrine will then take care of loading all required objects in as few queries as possible.
2. Sometimes load associated object:
If you want to load the associated object only in some queries and not by default, according to the manual you can also tell Doctrine to use eager loading on a specific query. In your case, this may look like:
public function fetchSale($sid){
$query = $this->createQueryBuilder('s')
->where('s.id = :sid')
->setParameter('sid', $sid)
->getQuery();
$query->setFetchMode("FQCN\Sale", "stock", \Doctrine\ORM\Mapping\ClassMetadata::FETCH_EAGER);
return $query->getSingleResult();
}

Notice: Trying to get property of non-object in vendor/doctrine/orm/lib/Doctrine/ORM/Internal/Hydration/ObjectHydrator.php line 481

I have a really strange case related to doctrine, loggable (DoctrineExtension) and listeners.
I will explain the situation I am having here and below is all the code I think is related to the problem.
I have two entities (Agreement and Template) where an agreement is based on a specific Template version. Template entity has the DoctrineExtension Loggable annotation. So I can revert an Agreement template to the specific version using the LogEntryRepository->revert() method. (I am using a postLoad listener to do that, so each time an agreement is retrieved, the right Template version is loaded for that Agreement).
If I get a controller action where an agreement is retrieved using a ParamConververter annotation, everything works ok and my agreement is retrieved with the right Template.
If I try to retrieve the very same agreement in the first line of the controller action using a query builder, I get the following exception
Notice: Trying to get property of non-object in /home/administrator{dir}/vendor/doctrine/orm/lib/Doctrine/ORM/Internal/Hydration/ObjectHydrator.php line 481
Any help would be appreciated.
Thanks.
Just copying the parts that are related to the problem:
Entities
/**
* Agreement
*
* #ORM\Table(name="agreement")
* #ORM\Entity
* #Gedmo\Loggable
*/
class Agreement
{
/**
* #var integer
* #ORM\Column(name="id", type="bigint", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $id;
/**
* #var integer
* #ORM\Column(name="template_version", type="bigint", nullable=false)
* #Gedmo\Versioned
*/
private $templateVersion;
/**
* #var \Template
* #ORM\ManyToOne(targetEntity="Template")
* #ORM\JoinColumn(name="template_id", referencedColumnName="id")
*/
private $template;
}
/*
* Template
*
* #ORM\Table(name="template")
* #ORM\Entity
* #ORM\ChangeTrackingPolicy("DEFERRED_EXPLICIT")
* #Gedmo\Loggable
*/
class Template
{
/**
* #var integer
* #ORM\Column(name="id", type="bigint", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $id;
/**
* #var string
* #ORM\Column(name="name", type="string", length=255, nullable=false)
* #Gedmo\Versioned
*/
private $name;
}
Doctrine Subscriber
*(services.yml)*
services:
ourdeal.listener.loggable:
class: App\Bundle\Listener\LoggableSubscriber
tags:
- { name: doctrine.event_subscriber }
class LoggableSubscriber implements EventSubscriber
{
public function getSubscribedEvents()
{
return array(
'prePersist',
'postLoad',
);
}
public function prePersist(LifecycleEventArgs $args)
*...Code omitted...*
public function postLoad(LifecycleEventArgs $args)
{
$entity = $args->getEntity();
$entityManager = $args->getEntityManager();
if ($entity instanceof Agreement)
{
$agreement = $entity;
$repo = $entityManager->getRepository('Gedmo\Loggable\Entity\LogEntry');
$repo->revert($agreement->getTemplate(), $agreement->getTemplateVersion());
}
}
}
Actions
With this action, I get the desired agreement without problems.
/**
* #Route("/agreement/send/{id}", name="agreement/send")
* #ParamConverter("agreement", class="Bundle:Agreement")
* #Template()
*/
public function sendAction(Request $request, Agreement $agreement) {
*...Code omitted...*
}
Using this code, I get the exception (the hardcoded id and this code is just for test)
/**
* #Route("/agreement/send", name="agreement/send")
* #Template()
*/
public function sendAction(Request $request) {
$em = $this->get('doctrine')->getManager();
$qb = $em->createQueryBuilder()->select('a')->from('AppBundle:Agreement', 'a')->where('a.id=1378');
$agreements = $qb->getQuery()->getResult();
}
use setParameter()
$em->createQueryBuilder()
->select('a')
->from('AppBundle:Agreement', 'a')
->where('a.id = :id')
->setParameter('id', $request->get('id'));
There is a known bug #52083 that affects PHP versions before 5.3.4, which fails randomly with "Notice: Trying to get property of non-object".
If that is your case, try upgrading PHP will solve your issue. Hope that helps

Symfony2 setting other rows to 0 after/before flush

Here's what I'm having trouble with.
I've a Table which contains a column called shown_on_homepage and only one row should be set to 1, the rest should all be set to 0. I'm trying to add a new row to the database and this one should be set to 1, setting the one that previously had a 1 to 0.
In MySQL I know this can be achieved by issuing an update before the insert:
UPDATE table_name SET shown_on_homepage = 0
Here's my Entity:
class FeaturedPerson {
/**
* #var integer
*
* #ORM\Column(name="id", type="integer", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="content", type="string", length=2500, nullable=false)
*/
private $content;
/**
* #var \DateTime
*
* #ORM\Column(name="date_updated", type="datetime")
*/
private $dateUpdated;
/**
* #var bool
*
* #ORM\Column(name="shown_on_homepage", type="boolean", nullable=false)
*/
private $isShownOnHomepage;
//...
public function getIsShownOnHomepage() {
return $this->isShownOnHomepage;
}
public function setIsShownOnHomepage($isShownOnHomepage) {
$this->isShownOnHomepage = $isShownOnHomepage;
return $this;
}
}
And for the Controller I've:
$featured = new FeaturedPerson();
$featured->setContent('Test content.');
$featured->setDateUpdated('01/02/2013.');
$featured->setIsShownOnHomepage(TRUE);
$em = $this->getDoctrine()->getManager();
$em->persist($featured);
$em->flush();
It does add the new row, but the one that had a shown_on_homepage set to 1 still has it. I've researched but I couldn't find a way to achieve this, I hope you can help me.
You could execute a query prior to your existing code in your controller:
$queryBuilder = $this->getDoctrine()->getRepository('YourBundleName:FeaturedPerson')->createQueryBuilder('qb');
$result = $queryBuilder->update('YourBundleName:FeaturedPerson', 'd')
->set('d.isShownOnHomepage', $queryBuilder->expr()->literal(0))
->where('d.isShownOnHomepage = :shown')
->setParameter('shown', 1)
->getQuery()
->execute();
Change 'YourBundleName' to your bundle name.

Symfony ONE-TO-ONE relation

I am new to symfony2 and have trouble to do a left join between 2 entities. I'm getting following error message, and don't know how to solve this problem:
[Semantical Error] line 0, col 69 near 'i': Error: Class
Bundle\Entity\Users has no association named user_id
Entity Users:
class Users
{
/**
* #ORM\Id
* #ORM\Column(name="user_id", type="string", length="16")
* #ORM\OneToOne(targetEntity="UsersInformation", mappedBy="Users")
*/
protected $user_id;
/**
* #ORM\Column(type="string", length="255")
*/
protected $username;
/**
* #ORM\Column(type="string", length="32")
*/
protected $password;
...
/**
* Set user_id
*
* #param string $userId
*/
public function setUserId($userId)
{
$this->user_id = $userId;
}
/**
* Get user_id
*
* #return string
*/
public function getUserId()
{
return $this->user_id;
}
...
}
Entity UsersInformation:
class UsersInformation
{
/**
* #ORM\Id
* #ORM\Column(type="string", length="16")
* #ORM\OneToOne(targetEntity="Users", inversedBy="UsersInformation")
* #ORM\JoinColumn(name="user_id", referencedColumnName="user_id")
*/
protected $user_id;
/**
* #ORM\Column(type="string", length="255")
*/
public $email;
/**
* #ORM\Column(type="string", length="1")
*/
public $gender;
/**
* #ORM\Column(type="string", length="255")
*/
public $company;
....
}
The UsersRepository looks like this:
public function getAllUsers($limit = null)
{
$qb = $this->createQueryBuilder('u')
->select('u, i')
->leftJoin('u.user_id', 'i');
if (false === is_null($limit))
$qb->setMaxResults($limit);
return $qb->getQuery()
->getResult();
}
What I'm doing wrong?
I think the querybuilder looks alright. Your problem is likely in the data structure.
The way you normally approach this is by setting up a property per relation. For your Users class it'd make sense to have an information or userInformation one for example.
Perhaps something like this helps?
class User
{
/**
* #ORM\Id
*/
protected $id;
/**
* #ORM\OneToOne(targetEntity="UserInformation")
*/
protected $information;
}
class UserInformation
{
/**
* #ORM\Id
*/
protected $id;
/**
* #ORM\OneToOne(targetEntity="User", inversedBy="information")
* #ORM\JoinColumn(name="user_id", referencedColumnName="id")
*/
protected $user;
}

Resources