Running the following query in Symfony2 - symfony

I am trying to run a query as follows in Symfony:
SELECT * FROM company
WHERE name LIKE '%$search%'
ORDER BY CASE WHEN name LIKE '$search%' THEN 1
WHEN name LIKE '%$search' THEN 2
WHEN name LIKE '%$search%' THEN 3
END
LIMIT 0,10
There seems to be a lot of the limitations with createQuery() and findBy() I was wondering if there was a way to query the DB in such a way with Symfony2?
Note, the company table is also set up as an entity.
This is what I tried which doesn't accomplish my whole query:
$this->getDoctrine()
->getRepository('testMyBundle:Company')
->findBy(array(),array(),10,($current-1)*$numItemsPerPage);
I appreciate any suggestions, thanks in advance!

I don't like solutions like that, but should working:
// CompanyRepository.php
public function getSth() {
$query = 'your sql query here';
$em = $this->getEntityManager();
$connection = $em->getConnection();
$stmt = $connection->prepare($query);
$stmt->execute();
return $stmt->fetchAll();
}
And in your controller:
$this->getDoctrine()
->getRepository('testMyBundle:Company')->getSth();

This DQL should work:
$query = $this->getDoctrine()
->createQuery('
SELECT c
FROM testMyBundle:Company c
WHERE c.name LIKE :search
ORDER BY CASE WHEN c.name LIKE :search THEN 1
WHEN c.name LIKE :search THEN 2
WHEN c.name LIKE :search THEN 3
END
')
->setParameter('search', '%search%')
->setMaxResults(10)
->setFirstResult(0)
->execute()
;

Related

Symfony / Doctrine findBy

Hove to create custom Repository function who query by json field. I have params column in my database who look like this:
"params": {
"product": "stopper",
"itemIdentifier": ""
}
I want to query record by product value. In this case stopper term.
You can achieve this with a classic example :
In your repository :
For one result
public function findOneProduct($value): ?Params
{
return $this->createQueryBuilder('p')
->andWhere('p.product = :val')
->setParameter('val', $value)
->getQuery()
->getOneOrNullResult()
;
}
For multiple result
public function findParamsByProduct($value): ?Params
{
return $this->createQueryBuilder('p')
->andWhere('p.product = :val')
->setParameter('val', $value)
->orderBy(/*some field */)
->setMaxResults(/*if needed*/)
->getQuery()
->getResults()
;
}
In your controller:
$stoppers = $entityManager->getRepository(Params::class)->findParamsByProduct('stopper');
If I understood your question correctly, you have a table with a column named params. And inside this mysql column, you store JSON text.
And then you want to query that table and filter by looking into the JSON in your column.
This can be a bit tedious and was also highly discouraged in the past (prior to the JSON Type in Mysql 5.7.8).
Best practices would be to have a NoSQL DB such as MongoDB which is actual JSON stored in a collection(table).
Anyways, there is a solution for you.
Taking into account #AppyGG explained how to make a custom repository function.
First of all, we have to make a query using pure SQL.
It can be done two ways:
1.Return arrays containing your data.
$conn = $this->getEntityManager()->getConnection();
$sql = '
SELECT * FROM product p
WHERE p.price > :price
ORDER BY p.price ASC
';
$stmt = $conn->prepare($sql);
$stmt->execute(['price' => $price]);
// returns an array of arrays (i.e. a raw data set)
return $stmt->fetchAll();
2.Return hydrated Entities
use Doctrine\ORM\Query\ResultSetMappingBuilder;
$rsm = new ResultSetMappingBuilder($entityManager);
$rsm->addRootEntityFromClassMetadata('MyProject\Product', 'p');
$sql = '
SELECT * FROM product p
WHERE p.price > :price
ORDER BY p.price ASC
';
$nql = $this->_em->createNativeQuery( $sql, $rsm );
$nql->setParameter('price', $price);
//Return loaded entities
return $nql->getResult();
Now, knowing how to make make a MySQL query with doctrine, we want to select results filtered in JSON data.
I'm am referencing this beautiful stackoverflow which explains it all:
How to search JSON data in MySQL?
The easiest solution proposed in there requires at least MySQL 5.7.8
Your MySQL query would be as follow:
//With $entity->getParams() == '{"params": {"product":"stopper", "itemIdentifier":""}}'
$conn = $this->getEntityManager()->getConnection();
$sql = '
SELECT * FROM Entity e
WHERE JSON_EXTRACT(e.params, "$.params.product") = :product
';
//Or Like this if the column is of Type JSON in MySQL(Not doctrine, yes check MySQL).
$sql = '
SELECT * FROM Entity e
WHERE e.params->"$.params.product" = :product
';
$stmt = $conn->prepare($sql);
$statement->bindValue("product","stopper");
$stmt->execute();
return $statement->fetchAll();
Hope this helps!
P.S: Note that my example uses a column named 'params' with a Json containing also a named attribute 'params', this can be confusing. The intended purpose is to show how to do multiple level filtering.

How to execute a pre-saved dql string

let's say for some reason I have a DQL string saved somewhere (in the DB) along with the necessary parameters, can I set it in a queryBuilder object and execute it?
I expected to be able to so something like
$builder = $entityManager->createQueryBuilder();
$query = $builder->getQuery()
->setDQL($stringDql)
->setParameters($arrayParams);
return $query->iterate();
The Entity manager has ::createQuery(string $dql); Where there string of DQL comes from it would not care.
$dql = 'SELECT u FROM MyProject\Model\User u WHERE u.age > 20';
// $dql = $this->getQueryFromDatabase();
$query = $em->createQuery($dql);

Doctrine query: delete with limit

I am trying to delete only x objects with a delete query from Doctrine. And since there is no LIMIT in doctrine, we should use $query->setMaxResults($limit) instead. I am using Symfony2.
However it does not work with the following query (with or without $query->setMaxResults($limit), it delete everything instead of deleting the $limit first entities).
$limit = 10;
$query = $entityManager->createQuery(
'DELETE FROM MyProject\Bundle\MyBundle\Entity\MyEntity myEntity
WHERE myEntity.cost = 50'
)
$query->setMaxResults($limit);
$query->execute();
One solution that works is to use native SQL with Doctrine like this (instead of DQL).
$limit = 10;
$sql = 'DELETE FROM my_entity
WHERE cost = 50
LIMIT ' . $limit;
$stmt = $entityManager->getConnection()->prepare($sql);
$stmt->execute();
setMaxResults works only in some cases. Doctrine seems to ignore it if it's not managed.
check the Doctrine doc : https://www.doctrine-project.org/projects/doctrine1/en/latest/manual/dql-doctrine-query-language.html#driver-portability
If it does not work, try in native SQL, like the other solution posted.
Use a sub query so you can use setMaxResults
$qb = $this->em->getRepository(MyClass::class)->createQueryBuilder('x');
$subQb = $this->em->getRepository(MyClass::class)->createQueryBuilder('x_sub');
// We can not use "setMaxResults" on delete query so we need a sub query
$subQb
->select('x_sub.id')
// ... your where clauses
->setMaxResults(500)
;
$qb
->delete()
->andWhere($qb->expr()->in('x.id', ':ids'))
->setParameter('ids', $subQb->getQuery()->getResult())
;

How to write DQL query innner join to avoid lazy loading?

My code:
$entityManager = $this->getDoctrine()->getEntityManager();
$result = $entityManager->createQueryBuilder()
->select('c')
->from('BlogHomepageBundle:Comment', 'c')
->innerJoin('BlogHomepageBundle:Post', 'po', 'WITH', 'c.postFk = po.postId')
->getQuery()->getResult();
foreach ($result as $c) {
//additional sql query
echo $c->getPostFk()->getName();
}
It works just fine, but when Im trying to get postFk ( post relate to comment one-to-many relation) I'm getting additional query to db ( lazy loading). Can I avoid this situtation to get all data in one DQL query ? Simple to performe sql query
select c.*, p.* from comment as c inner join post as p on c.post_fk = p.post_id
I want to use DQL ( not raw sql ).
EDIT
I would like to have Objects and access to them like in foreach loop / not scalar data.
You need to specifically select a property or a join to avoid lazy loading :
->select('c', 'po')
http://www.doctrine-project.org/blog/doctrine-lazy-loading.html
I think I found solution #Rpg600 thanks for help.
This is code:
$entityManager = $this->getDoctrine()->getEntityManager();
$result = $entityManager->createQueryBuilder()
->select('c', 'po')
->from('BlogHomepageBundle:Comment', 'c')
->innerJoin('c.postFk', 'po', 'WITH', 'c.postFk = po.postId')
->getQuery()
->getResult();
foreach ($result as $c) {
echo $c->getContent();
echo $c->getPostFk()->getName();
}

Doctrine - how select fields to return from the query (in Symfony2)

So imagine a basic query:
$em = $this->getDoctrine()->getManager();
$query = $em->createQuery(
'SELECT x FROM MyBundle:MyEntity x'
);
$result = $query->getResult();
How do I select which fields to return? I was a bit thrown at the SELECT part as this is very different from SQL's SELECT (fields) from table. In fact it looks a bit odd to me, why not just do this similar to SQL?
SELECT field1, field2 FROM MyBundle:MyEntity
Anyway, how would I limit to a set list of fields?
You have to use Doctrine partial object:
$q = $em->createQuery("select partial u.{id,name} from MyApp\Domain\User u");

Resources