Get custom getter property into QueryBuilder object? - symfony

I have the following QueryBuilder snippet working as expected:
$restaurants = $qb->select('r.id, r.name, r.addressGpsLat, r.addressGpsLng, r.addressZip, r.addressCity')
->from('BackendBundle:Restaurant', 'r')
->orderBy('r.name', 'ASC');
In our Restaurant entity we calculate ratings based on a relation, which looks like this:
public function getRating()
{
$rating = 0;
$votes = count($this->votes);
foreach ($this->votes as $vote) {
$rating += $vote->getRating();
}
if ($votes == 0) {
return null;
}
return number_format(($rating / $votes), 2, ',', '.');
}
So my question: is there a way I get the result of the getRating() property into my QueryBuilder object? We need it to be a seperate attribute in our JSON response. E.g. { …, "rating":2.2, …}
Any advice on this? Thanks!

Related

How to sum the contents of a document field with symfony query builder?

I am just trying to get the total value of one of the fields of my documents but it's not working. What am I missing?
#ProductRepository
public function countTotalValue()
{
return $this->createQueryBuilder('a')
->select('SUM(a.price)')
->getQuery()
->getSingleScalarResult()
;
}
I discovered it!
public function countTotalValue()
{
$array = $this->createQueryBuilder()
->select('price')
->hydrate(false)
->getQuery()
->execute()
->toArray()
;
$array = array_column($array, 'price');
return (array_sum($array));
}
It was returning a complex array, I had to stripe it before make the sum.

SilverStripe convertDataObjectSet is stripping additional properties

I am attempting to add the 'AbsoluteLink' property to each DataObject in a DataList and then convert the list to JSON with JSONDataFormatter::convertDataObjectSet().
I have the following function:
public function json() {
$data = ResourceCentreArticlePage::get()->filter('ShowInMenus', '1')->filter('ShowInSearch', '1')->sort('Created', 'DESC');
$pageArray = new ArrayList();
foreach ($data as $page) {
$page->AbsoluteLink = $page->AbsoluteLink();
$pageArray->push($page);
}
// If I dump out the content of $pageArray here the object has the AbsoluteLink property
$jsonFormatter = new JSONDataFormatter();
$jsonData = $jsonFormatter->convertDataObjectSet($pageArray);
// If I dump out the content of $jsonData here there is no AbsoluteLink property
$this->response->addHeader("Content-type", "application/json");
return $jsonData;
}
The problem:
The AbsoluteLink property is removed after running the $pageArray through the convertDataObjectSet method.
What am I missing?
Using $jsonFormatter->setCustomAddFields(); will help here.
Add the following to the Page class:
public function getMyAbsoluteLink() {
return $this->AbsoluteLink();
}
For example to the Page.php:
class Page extends SiteTree {
public function getMyAbsoluteLink() {
return $this->AbsoluteLink();
}
}
And use that "magic field" like this:
public function json() {
$pages = Page::get()
->filter('ShowInMenus', '1')
->filter('ShowInSearch', '1')
->sort('Created', 'DESC');
$jsonFormatter = new JSONDataFormatter();
// add your custom field
$jsonFormatter->setCustomAddFields(["MyAbsoluteLink"]);
$jsonData = $jsonFormatter->convertDataObjectSet(
$pages
);
return $jsonData;
}
Note the $jsonFormatter->setCustomAddFields(["MyAbsoluteLink"]); and I removed the array manipulation.
Also I removed your array manipulation. How the convertDataobjectSet function works it seems you can't amend the objects before it runs.

Symfony2, Doctrine2, left join (dql) and its result

So we have such dql
$oQuery = $this->createQueryBuilder('assets')
->addSelect('flags')
->addSelect('types')
->addSelect('groups')
->leftJoin('Site\MainBundle\Entity\123\invFlags', 'flags', Join::WITH, 'assets.flag = flags.flagID')
->leftJoin('Site\MainBundle\Entity\123\invTypes', 'types', Join::WITH, 'assets.typeID = types.typeID')
->leftJoin('Site\MainBundle\Entity\123\invGroups', 'groups', Join::WITH, 'types.groupID = groups.groupID');
if (!empty($aFilter)) {
$bFirst = true;
foreach ($aFilter as $sKey => $sValue) {
if ($bFirst) {
$oQuery->where($oQuery->expr()->eq('assets.' . $sKey, $sValue));
$bFirst = false;
continue;
} else {
if ($sValue === null) {
$oQuery->andWhere($oQuery->expr()->isNull('assets.' . $sKey));
}
}
}
}
return $oQuery->getQuery()->getResult();
We call it from repository and have result... BUT. In sql query ($oQuery->getQuery()->getSQL()) I see all columns and proper left join I need, but NOT in result. Why it happens? When I return '->getScalarResult()' I receive all needed data but like array and with prefix of tables
array(38) {
["assets_id"]=>string(4) "4558"
["assets_characterID"]=>string(8) "90206263"
["assets_parentItemID"]=>NULL
Can I anyhow get simple 'combined' object' with all get methods?
ADD:
Forgot to say that there are no relations in entities.

symfony 2 doctrine $query->getArrayResult() how to remove selected key->values from result

As I don't want id values from a select with createQuery, but the select command doesn't allow omitting id (primary key) from the actual query (using "partial") I need to remove the id's from the result from getArrayResult()
I made this small recursive key remover static class:
class arrayTool
{
public static function cleanup($array, $deleteKeys)
{
foreach($array as $key => $value )
{
if(is_array( $value))
{
$array[$key] = self::cleanup($array[$key], $deleteKeys);
} else {
if (in_array($key, $deleteKeys)) unset($array[$key]);
}
}
return $array;
}
}
Which is called by an array containing one or more keys to be removed from the result, of any array depth:
$array = arrayTool::cleanup($array, array('id', 'id2'));

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