symfony2 QueryBuilder with a json field - symfony

Sorry for my english.
I'm blocked to a point and I wish you help me.
I have a json field in my entity. I want, with querybuilder, get statut of profil1.
Example from my field in my table in the BDD : (saved like this)
{
"Profil1":{
"statut":"première visite",
"site":"site officiel"
},
"Profil2":{
"statut":"ancien",
"motif":"facebook"
}
}

Something like this:
$queryBuilder = $entityManager->createQueryBuilder()
->select('e')
->from('ACMEDemoBundle:YourEntity', 'e');
$result = $queryBuilder
->getQuery()->getResult();
foreach ($result as $entity)
{
$jsonObject = json_decode($entity->getJsonField()); //where jsonField is the name of the field containing the json
$profile1Statut = $jsonObject['Profil1']['statut'];
}
Probably you want to make some sanity checks also. And depending of the size of your table, it may be a little bit overkilling.

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.

Symfony2 dynamic queryBuilder

I'm making a tool in which a user can view data from an entity, where they can choose what data and how they see the records.
I created a form with two date fields (start and end) and a list of fields that correspond to data counts and sums of the entity.
My question is:
How I can create a dynamically QueryBuilder that allows me to add fields based on what the user wants to see?
EDIT for Symfony2 dynamic queryBuilder
public function reportData($fields, $dateStart, $dateFinish)
{
$em = $this->getEntityManager()
->getRepository('AcmeBundle:Entity');
$query = $em->createQueryBuilder('e');
foreach($fields as $field)
{
switch($field)
{
case 'totalResults':
$query->setect('SUM(e.id) AS '.$field);
break;
}
}
$query->addWhere('e.dateStart >= :dateStart');
$query->addWhere('e.dateFinish <= :dateFinish');
...
Something like this ? You store all your select queries in an array, then pass the array to the query builder after testing each of your fields.
public function reportData($fields, $dateStart, $dateFinish)
{
$em = $this->getEntityManager()
->getRepository('AcmeBundle:Entity');
$query = $em->createQueryBuilder('e');
$select_array = array();
foreach($fields as $field)
{
switch($field)
{
case 'totalResults':
$select_array[] = 'SUM(e.id) AS '.$field;
break;
}
}
$query->select($select_array);
$query->addWhere('e.dateStart >= :dateStart');
$query->addWhere('e.dateFinish <= :dateFinish');
....
Basically, you want to keep on adding the
Select Fields
based upon the conditions.
So, the solution is simple.
You can use,
$queryBuilder->addSelect();
See Doctrine Query Builder Documentation
I would do a regular full query then filter it into a not doctrine object (dao/dto) then display it.
This way you can do the complex and optimized query first, then filter the result on whatever you want, even if it's not related to the query itself

Symfony2 Doctrine2 use of partials

From reading the documentation and another stackoverflow post, I thought that if I only want to return a couple of columns data, the correct method in doctrine was to use a partial. (This is a read only query).
However the below code returns all 100 columns instead of the 3 I identified. Can someone explain why?
Thanks,
Manisha
public function showAction(Request $request)
{
if ($request->getMethod() == 'GET') {
$id = $request->get('locationid');
$kfType = $request->get('type');
$em = $this->getDoctrine()
->getManager();
$data = $em->createQueryBuilder()
->select ( array( 'partial d.{id, locationid, kfFyp}' ))
->from('DashDataBundle:Data', 'd')
->where('d.locationid = :locationid')
->setParameter('locationid', $id)
->setMaxResults(100)
->getQuery()
->getResult();
}
This query will return doctrine entities which have many fields. But then you use partial keywords this fields would be empty. Only specified fields would be filled with data.
If you doesnt want to hydrate objects you can get data in simple array if you specify it
->getResult(\Doctrine\ORM\Query::HYDRATE_ARRAY)

Symfony2 Doctrine Join Entity

I have a entity with the next join:
class blogComment
{
....
/**
* #ORM\OneToMany(targetEntity="BlogComment", mappedBy="replyTo")
*/
protected $replies;
....
}
Now I get successfully all the replies. But I only want to get: where active = true
How to do that?
Oke if you guys recommend to get the comments by query in the controller how to build a nested array to get result like this:
For solving the part where you only want active replies there are a couple of options:
1) Use some custom DQL in a repository:
$dql = 'SELECT bc FROM BlogComment bc WHERE bc.replyTo = :id AND bc.active = :active';
$q = $em->createQuery($dql)
->setParameters(array('id' => $id, 'active' => true));
2) Using ArrayCollection::filter() in the getter:
public function getReplies()
{
return $this->replies
->filter(function ($reply) {
return $reply->isActive();
})
->toArray();
}
3) Using ArrayCollection::matching() (Collection Criteria API) in the getter:
use Doctrine\Common\Collections\Criteria;
// ...
public function getReplies()
{
$criteria = new Criteria::create()
->where(Criteria::expr()->eq('active', true));
return $this->replies
->matching($criteria)
->toArray();
}
4) Use Filters. These can add where clauses to queries regardless of where that query is generated. Please see the docs.
If you want to be able to fetch an entire set of replies, nested and all, in a single query, you need to implement some kind of "tree" of "nested set" functionality. I'd advise you to look at the Tree behavior of l3pp4rd/DoctrineExtensions.
http://doctrine-orm.readthedocs.org/en/latest/reference/dql-doctrine-query-language.html
Wherever you are obtaining your blog comments to display them (probably on a controller), you need to customise your query so that only the active replies are extracted. Something like:
$query = $em->createQuery('SELECT b FROM blogComment b JOIN b.replies r WHERE r.active = :active');
$query->setParameter('active', true);
$blogComments = $query->getResult();
EDIT:
For your new requirement of nested replies, you would need to specify a relationship between a comment entity and its parent comment.

Query database and store results in array in drupal module

I have a table in my database called gsm_tariff. Basically I just want to run a simple select query
"SELECT * FROM {gsm_tariff} WHERE Country='Afghanistan'"
and store the results in an array. Can anyone help me with how to do this please? I know where to put the code and everything; I just need the code to do the query and store the results in an array.
$array = array();
$result = db_query('SELECT * FROM {gsm_tariff} WHERE Country = "%s"', 'Afghanistan');
while ($record = db_fetch_object($result)) {
$array[] = $record->(data to reference);
}
Note that I don't know the field you want to reference given the question, but it would be in the $record object.

Resources