Doctrine 2: Separate chain calls in QueryBuilder - symfony

What is the approach to separate the querybuilder if I have some condition that I want to check.
What I want to get is something like this:
public function getProfilePhotoByUserId($userId, $checkApproved = false)
{
$profile = $this->createQueryBuilder('p')
->where('p.user = :userId')
->andWhere('p.profile = 1')
->setParameter('userId', $userId);
if($checkApproved) $profile->andWhere('p.approved = 1');
$profile->getQuery();
return $profile->getOneOrNullResult(Query::HYDRATE_ARRAY);
}
However this shows error on getOneOrNullResult:
"Method not found in querybuilder"

getQuery() return a Doctrine\ORM\Query object.
$query = $profile->getQuery();
return query->getOneOrNullResult(Query::HYDRATE_ARRAY);
or
return $profile->getQuery()->getOneOrNullResult(Query::HYDRATE_ARRAY);

Related

Symfony - How to use LIKE with COALESCE in a Doctrine request?

I have some trouble with LIKE and COALESCE in a Doctrine request (not 100% sure that the trouble is there).
I would like to search inside a database with a filter that match only if exist, and only with a part of the value (for example find 'abc' with the filter set to 'ab').
This request works fine :
public function findUsers($entreprise, $filtres)
{
$filtre_name = $filtres['name'];
return $this->createQueryBuilder('users')
->where('users.entreprise = :entreprise')
->andWhere('users.name = COALESCE(:filtre_name, users.name)')
->setParameter('entreprise', $entreprise)
->setParameter('filtre_name', $filtre_name)
->orderBy('users.name', 'ASC')
->getQuery()
->getResult();
}
It return all the users of the company "entreprise" where "filtre_name" match (if not null) with "name" in the database. (If "filtre_name" is null, then the where match for all the database thanks to COALESCE).
I would like now to do the same thing but with "LIKE" instead of "=" because for now the name has to match perfectly and I would like a match for "abc" with only "ab" inside the filter for example.
public function findUsers($entreprise, $filtres)
{
$filtre_name = $filtres['name'];
return $this->createQueryBuilder('users')
->where('users.entreprise = :entreprise')
->andWhere('users.name LIKE COALESCE(:filtre_name, users.name)')
->setParameter('entreprise', $entreprise)
->setParameter('filtre_name', '%'.$filtre_name.'%')
->orderBy('users.name', 'ASC')
->getQuery()
->getResult();
}
The result is an error : "Warning: Undefined property: Doctrine\ORM\Query\AST\CoalesceExpression::$type".
I have find a solution. I build my queryBuilder with parameter only if they are not Null. So I remove COALESCE and now I can use LIKE.
public function findUsers($entreprise, $filtres)
{
$filtre_nom = $filtres['nom'];
$filtre_gestionnaire = $filtres['gestionnaire'];
$qb = $this ->createQueryBuilder('users');
$qb ->where('users.entreprise = :entreprise')
->setParameter('entreprise', $entreprise);
if ($filtre_nom != Null) {
$qb ->andWhere('users.nom LIKE :filtre_nom')
->setParameter('filtre_nom', '%'.$filtre_nom.'%');
}
if ($filtre_gestionnaire != Null) {
$qb ->andWhere('users.gestionnaire LIKE :filtre_gestionnaire')
->setParameter('filtre_gestionnaire', '%'.$filtre_gestionnaire.'%');
}
$qb->addorderBy('users.nom', 'ASC');
return $qb ->getQuery()
->getResult();
}

Foreach on getRepository Symfony 3

On my controler I get some results from database
$commandes = $em->getRepository('SWPlatformBundle:Vente')->getCommandesAFacturer($client[0]->getId());
with this SQL
public function getCommandesAFacturer($id) {
$qb = $this->createQueryBuilder('v')
->select("c.id, c.montantTTC, c.horodatageCreation, SUM(v.prixTotalVente) AS sansFrais")
->leftJoin('v.commande', 'c')
->where('c.facture IS NULL')
->andwhere('c.commercant = :commercantId')
->setParameter('commercantId', $id)
->groupBy('c.id');
return $qb
->getQuery()
->getResult();
}
And I would like to sum the sansFrais value of my request but I don't reach the sansFrais Value.
I've tried like this, but it doesn't work :
foreach($commandes as $commande){
$montantHTCollecte += $commande['sansFrais'];
}
Thanks for your help !

Symfony call get by Name from variable

I would like to call a getter with the stored fieldname from the database.
For example, there are some fieldnames store like ['id','email','name'].
$array=Array('id','email','name');
Normally, I will call ->getId() or ->getEmail()....
In this case, I have no chance to handle things like this. Is there any possibility to get the variable as part of the get Command like...
foreach ($array as $item){
$value[]=$repository->get$item();
}
Can I use the magic Method in someway? this is a bit confusing....
Symfony offers a special PropertyAccessor you could use:
use Symfony\Component\PropertyAccess\PropertyAccess;
$accessor = PropertyAccess::createPropertyAccessor();
class Person
{
private $firstName = 'Wouter';
public function getFirstName()
{
return $this->firstName;
}
}
$person = new Person();
var_dump($accessor->getValue($person, 'first_name')); // 'Wouter'
http://symfony.com/doc/current/components/property_access/introduction.html#using-getters
You can do it like this :
// For example, to get getId()
$reflectionMethod = new ReflectionMethod('AppBundle\Entity\YourEntity','get'.$soft[0]);
$i[] = $reflectionMethod->invoke($yourObject);
With $yourObject being the object of which you want to get the id from.
EDIT : Don't forget the use to add :
use ReflectionMethod;
Hope this helps.
<?php
// You can get Getter method like this
use Doctrine\Common\Inflector\Inflector;
$array = ['id', 'email', 'name'];
$value = [];
foreach ($array as $item){
$method = Inflector::classify('get_'.$item);
// Call it
if (method_exists($repository, $method))
$value[] = $repository->$method();
}

Symfony2 Doctrine Raw SQL Stored Procedure Loop through multiple result sets

I have managed to execute raw SQL (ie no ResultSetMapping) and can call and execute an MSSQL Stored Procedure.
The code I have is as follows:
$em = $this->get('doctrine')->getManager();
$stmt = $em
->getConnection()
->prepare('EXEC someSP :id,null,:uid');
$stmt->bindValue('id', '629674');
$stmt->bindValue('uid', '217');
$stmt->execute();
$results = $stmt->fetchAll();
No that works fine; however the issue i have is if the SP returns more than one result set the above only returns the first result set. Is there any way to loop through and get each result set?
I had to deal with the similar issue and this is what I came up with. This function is from the class that extends Doctrine\ORM\EntityRepository so I have access to the _em property in general case you can use $this->get('doctrine')->getManager(); to get entity manager.
protected function execMultiSetQuery($query, $params, $connection = 'default') {
// Init
$conn = $this->_em
->getConnection($connection)
->getWrappedConnection();
// Processing
if ($conn instanceof \Doctrine\DBAL\Driver\PDOConnection) {
$stmt = $conn->prepare($query);
$stmt->execute($params);
// Loop through the row sets
$results = array();
do {
try {
$results[] = $stmt->fetch(\PDO::FETCH_ASSOC);
}
catch (\Exception $e) {}
} while($stmt->nextRowset());
$stmt->closeCursor(); // Clean up
return $results;
}
else {
return false;
}
}
OK I was able to do this but i had to create my own wrapper around the connection:
Its a work around at best but the code basically creates a new PDO connection using the DBAL params in conf.yml. it them prepares and executes the statement and returns all the result sets.
code is free to use here:
https://github.com/scott-davidjones/Symfony2DBALSPWrapper
You can try and itterate over each set 1 by one. But really fetchAll should do the same as below, cant hurt to try though...
$em = $this->get('doctrine')->getManager();
$stmt = $em
->getConnection()
->prepare('EXEC someSP :id,null,:uid');
$stmt->bindValue('id', '629674');
$stmt->bindValue('uid', '217');
$stmt->execute();
do{
$results[] = $stmt->fetchAll()
} while($stmt->nextRowset());

unique slugs with multi entities in symfony2

I have a small symfony2 application where a user can create pages. Each page should be accessible via the route /{user_slug}/{page_slug}. I have the entities user and page and I use the sluggable behavior for both entities. In order to find the correct page the combination of user_slug and page_slug has to be unique.
What is the best way to check that the combination of user_slug and page_slug is uniqe?
Try this in your prepository:
public function findByUsernameAndSlug($username, $slug)
{
$em = $this->getEntityManager();
$query = $em->createQuery("
SELECT g
FROM Acme\PagesBundle\Entity\Page p
JOIN p.owner u
WHERE u.username = :username
AND p.slug = :slug
")
->setParameter('username', $username)
->setParameter('slug', $slug);
foreach ($query->getResult() as $goal) {
return $goal;
}
return null;
}
Before you persist the entity in your service-layer check whether given combination of user and page slug are unique, if not modify the page slug (append -2 or something like that) or throw an exception:
public function persistPage(Page $page) {
$userSlug = $page->getUser()->getSlug();
$pageSlug = $page->getSlug();
if ($this->pagesRepository->findOneBySlugs($userSlug, $pageSlug) != null) {
// given combination already exists
throw new NonUniqueNameException(..);
// or modify the slug
$page->setSlug($page->getSlug() . '-2');
return $this->persistPage($page);
}
return $this->em->persist($page);
}
// PagesRepository::findOneBySlugs($userSlug, $pageSlug)
public function findOneBySlugs($userSlug, $pageSlug) {
$query = $this->em->createQueryBuilder('p')
->addSelect('u')
->join('p.user', 'u')
->where('p.slug = :pageSlug')
->where('u.slug = :userSlug;)
->getQuery();
$query->setParameters(combine('userSlug', 'pageSlug'));
return $query->getSingleResult();
}

Resources