Show multiple data from an Entity - symfony

I want to show the best 5 scores from each different Game I have. So I made this function :
public function records (){
$em = $this->getDoctrine()->getManager();
$games = $em->getRepository(Game::class)->findAll();
foreach($games as $g){
$records = new ArrayCollection;
$records = $em->getRepository(Game::class)->findAllRecords($g->getId());
}
return $this->render('game/records.html.twig', [
'games' => $games,
'records' => $records,
]);
}
Here is the repository function :
public function findAllRecords($id){
$qb = $this->createQueryBuilder('g');
$qb->select('g.name')
->innerJoin('g.Parties', 'p')
->innerJoin('p.playeds', 'y')
->innerJoin('y.joueur', 'j')
->addSelect('y.score')
->addSelect('j.nom, j.prenom')
->where('g.id = :id')
->setParameter('id', $id)
->orderBy('y.score', 'DESC')
->setMaxResults('5');
var_dump($qb->getDQL());
$query = $qb->getQuery();
return $query->getResult();
}
And finally the view :
{% for g in games %}
{{ g.name }}
<table class="table">
<tbody>
<tr>
<th>score</th>
</tr>
{% for r in records %}
<tr>
<td>{{ r.score }}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endfor %}
It doesn't completely works as I just get the data from the last game ID. How can I show the data for each game ?

foreach($games as $g){
$records = new ArrayCollection;
$records = $em->getRepository(Game::class)->findAllRecords($g->getId());
}
Here's your issue. This is always overwriting. You want to do something like:
$records = new ArrayCollection;
foreach($games as $g) {
$records[] = $em->......;
}
That should solve your issue

Related

sorting with KnpPaginator

I have an issue trying to make my sorting with KnpPaginator works. I followed many links and try a lot of iteration in my code, it can't seem to work properly. i'm missing something but can't locate it
The only thing that works at the moment si the table headers where i can click on it but nothing happens except refreshing the page and refreshing me back on pagination 1.
I'm working on symfony 2.3
Here is my bundle configuration
knp_paginator:
page_range: 5 # default page range used in pagination control
default_options:
page_name: page # page query parameter name
sort_field_name: sort # sort field query parameter name
sort_direction_name: direction # sort direction query parameter name
distinct: true # ensure distinct results, useful when ORM queries are using GROUP BY statements
template:
pagination: 'KnpPaginatorBundle:Pagination:twitter_bootstrap_v3_pagination.html.twig' # sliding pagination controls template
sortable: 'KnpPaginatorBundle:Pagination:sortable_link.html.twig' # sort link template
Here is my controller where I actually setted up Knp with the getRepository
private function resultsAction(Request $request, User $user, $type, $archive)
{
$em = $this->getDoctrine()->getManager();
$query = $em->getRepository("STUserBundle:Operation")->getQueryByTypeAndPro($type, $user, $archive);
$paginator = $this->get('knp_paginator');
$results = $paginator->paginate(
$query,
$request->query->getInt('page',1),
$request->query->getInt('limit',50)
);
return array("results" => $results, "archive" => $archive);
}
public function offreAction(Request $request, User $user, $archive = false)
{
return $this->resultsAction($request, $user, Operation::OFFRE_COMMERCIALE, $archive);
}
here is my repo where the query is done:
public function getQueryByTypeAndPro($type, User $user, $archive)
{
return $this->createQueryBuilder("opn")
->andWhere("opn.type = :type")
->setParameter("type", $type)
->andWhere("opn.resellerId = :reseller")
->setParameter("reseller", $user->getId())
->andWhere("opn.archive = :archive")
->setParameter('archive', $archive)
->orderBy("opn.dateCreation", "DESC")
->getQuery()
;
}
And here is my view where I try to make things work with Knp
<tr>
<th>{{ knp_pagination_sortable(results, 'general.vehicule.ref'|trans, 'opn.type') }}</th>
<th>{{ knp_pagination_sortable(results, 'general.vehicule.vehicule'|trans, 'opn.resellerId') }}</th>
<th>{{ knp_pagination_sortable(results, 'notifications.client'|trans, 'opn.??') }}</th>
<th>{{ knp_pagination_sortable(results, 'general.date'|trans, 'opn.??') }}</th>
<th>{{ knp_pagination_sortable(results, 'commerce.achat.encours.etat'|trans, 'opn.??') }}</th>
</tr>
And in my table, when I click on it refresh the page but doesn't sort it. I'm having a hard time understand how to make that work?
The place where I putted 'opn.??' its because I don't know what to put at that particular place, I don't seem to understand the query
I would like the last dated item to be first, but being able to sort it with Knp
Okay i succeeded in making that work, here is what I've done.
config.yml
knp_paginator:
page_range: 5 # default page range used in pagination control
default_options:
page_name: page # page query parameter name
sort_field_name: sort # sort field query parameter name
sort_direction_name: direction # sort direction query parameter name
distinct: false # ensure distinct results, useful when ORM queries are using GROUP BY statements
template:
pagination: 'KnpPaginatorBundle:Pagination:twitter_bootstrap_v3_pagination.html.twig' # sliding pagination controls template
sortable: 'KnpPaginatorBundle:Pagination:sortable_link.html.twig' # sort link template
repo
public function getQueryByTypeAndPro($type, User $user, $archive)
{
return $this->createQueryBuilder("opn")
->andWhere("opn.type = :type")
->setParameter("type", $type)
->andWhere("opn.resellerId = :reseller")
->setParameter("reseller", $user->getId())
->andWhere("opn.archive = :archive")
->setParameter('archive', $archive)
->orderBy("opn.dateCreation", "DESC")
->getQuery()
;
}
controller
private function resultsAction(Request $request, User $user, $type, $archive)
{
$em = $this->getDoctrine()->getManager();
$paginator = $this->get('knp_paginator');
$qb = $em->getRepository("STUserBundle:Operation")->getQueryByTypeAndPro($type, $user, $archive);
$results = $paginator->paginate(
$qb,
$request->query->get('page',1),
$request->query->get('limit',50),
[
'defaultSortFieldName' => 'opn.dateCreation',
'defaultSortDirection' => 'desc'
]
);
return array("results" => $results, "archive" => $archive);
}
and twig
<tr>
<th{% if results.isSorted('opn.id') %} class="sorted"{% endif %}>{{ knp_pagination_sortable(results, 'general.vehicule.ref'|trans, 'opn.id') }}</th>
<th{% if results.isSorted('opn.vehiculeMarque') %} class="sorted"{% endif %}>{{ knp_pagination_sortable(results, 'general.vehicule.vehicule'|trans, 'opn.vehiculeMarque') }}</th>
{% if typeOffre is defined and typeOffre == 'devisWeb' %}<th>Financement</th>{% endif %}
<th{% if results.isSorted('opn.clientNom') %} class="sorted"{% endif %}>{{ knp_pagination_sortable(results, 'notifications.client'|trans, 'opn.clientNom') }}</th>
<th{% if results.isSorted('opn.dateCreation') %} class="sorted"{% endif %}>{{ knp_pagination_sortable(results, 'general.date'|trans, 'opn.dateCreation') }}</th>
<th>{{ 'commerce.achat.encours.etat'|trans }}</th>
<th class="sorting_disabled">{{ 'commerce.achat.action'|trans }}</th>
<th class="sorting_disabled">{{ 'commerce.vente.operation.basculer'|trans }}</th>
</tr>
and so that works
remove ->orderBy("opn.dateCreation", "DESC"). KnpPaginator have special Listener and Walker that can modify your query with correct ORDER BY based on request and then eqecute an paginate it for you.
Config sortable look at here.
Translation look at here.

Symfony Native Query

I work on a project under symfony, when I want to calculate the average product by month and year (date) and as doctrine doesn't include the Month or YEAR functions I used native sql but it didn't show the results, it return empty array.
If someone can help me,Thank you.
Repository:`
public function MonthEfficience()
{
$rsm = new ResultSetMappingBuilder($this->getEntityManager());
$rsm->addRootEntityFromClassMetadata('GP\PlatformBundle\Entity\Efficience', 'e');
$rsm->addJoinedEntityFromClassMetadata('GP\PlatformBundle\Entity\collectif', 'c', 'e', 'collectif', array('id' => 'collectif_id'));
$sql = 'SELECT (AVG(e.produit_real/e.produit_plan)*100) as moyenne,
MONTH(e.date) as mois, YEAR(e.date) as annee FROM efficience e, collectif c
where e.collectif_id=c.id group by mois, annee';
$query = $this->_em->createNativeQuery($sql, $rsm);
$resultats = $query->getResult();
return $resultats;
}
Controller:
public function effmonthAction()
{
$em = $this->getDoctrine()->getManager()
->getRepository('GPPlatformBundle:Efficience');
$efficiences = $em->MonthEfficience();
return $this->render('GPPlatformBundle:App:effmonth.html.twig',
array('efficiences'=>$efficiences));
}
Twig :
<table id="example" class="display" cellspacing="0" width="100%">
<thead>
<tr>
<th>Annee</th>
<th>Mois</th>
<th>Moyenne</th>
</tr>
</thead>
<tbody>
{% for efficiences in efficiences %}
<tr>
<td>{{ efficiences.produitplan }}</td>
<td>{{ efficiences.produitreal }}</td>
<td>{{ efficiences.produitplan }}</td>
</tr>
{% endfor %}
</tbody>
</table>
Resultats:
empty array

Twig and Doctrine- Count each related entity and display in Twig loop

I have a one to many relationship in doctrine.I want to count each related field and display them in Twig for loop
so far
A Vp is related to Voters.Vp has many Voters and Voters has one Vp
I want to count each related Voters per Vp
public function getAllVp()
{
return $this
->createQueryBuilder('v')
->select('vp.id,COUNT(v.id) as num')
->from('Voters', 'v')
->join('v.Vp', 'vp')
->orderBy('v.id', 'ASC')
->getQuery()
->getResult()
;
}
I want this in Twig like
{% for vp in vps %}
{{ vp.firstname }}
{{ vp.num }}//number of voters
{% endfor %}
controller
$vice_president = $em->getRepository('Bundle:Vp')->getAllVp();
return $this->render('Bundle:Vp:all_vp.html.twig', array(
'vps' => $vice_president,
));
doctrine
fields:
firstname:
type: string
length: 255
lastname:
type: string
length: 255
photo:
type: string
length: 255
oneToMany:
voters:
targetEntity: Voters
mappedBy: vp
I got this error
[Semantical Error] line 0, col 94 near 'vp, Voters v': Error: Class Project\Bundle\DuterteBundle\Entity\Vp has no association named Vp
How to correctly achieve this in Doctrine?
Update
voters.orm.yml
manyToOne:
vp:
targetEntity: Vp
cascade: { }
mappedBy: null
inversedBy: voters
joinColumn:
name: vp_id
referencedColumnName: id
orphanRemoval: false
I can achieved this by simply calling the related 'voters' and add a filter in Twig.But my intention is to count the data in doctrine, reuse it in other templates or convert it to json for the future,e.g in Angular JS
{% if vp.voters|length > 0 %}
<tr {% if loop.index is odd %}class="color"{% endif %}>
<td>{{ vp.id }}</td>
<td>{{ vp.getFullName() }}</td>
<td>{{ vp.voters|length|number_format }}</td>
</tr>
{% endif %}
Above is a working code but I want to do the count in Doctrine , not in template
Expected result
id fullname counts
1 George Bush 45
2 ali gail 1999
4 Mae Young 45
......
First of all, you can remove mappedBy: null in your Voter mapping.
PHP oriented :
Ok you can try this PHP solution to add a new method in your entity Vp like :
public function getVotersCount(){
return count($this->voters);
}
And in your twig view you can do :
{{ vp.getVotersCount() }}
Doctrine oriented : (http://docs.doctrine-project.org/en/latest/reference/events.html#lifecycle-events)
In your Vp Entity orm mapping :
fields:
firstname:
type: string
length: 255
lastname:
type: string
length: 255
photo:
type: string
length: 255
oneToMany:
voters:
targetEntity: Voters
mappedBy: vp
lifecycleCallbacks:
postLoad: [ countVotersOnPostLoad ]
And also a new attribute, a getter and countVoters method :
protected $votersCount;
public function getVotersCount(){
return $this->votersCount;
}
public function countVotersOnPostLoad ()
{
$this->votersCount = count($this->voters);
}
And in your view, simply do :
{{ vp.votersCount }}
My work around for this is to create a service.
<?php
namespace Project\Bundle\DutBundle\Twig;
class AllVpExtension extends \Twig_Extension
{
protected $em;
public function __construct($em)
{
this->em = $em;
}
public function getFunctions()
{
return array(
//this is the name of the function you will use in twig
new \Twig_SimpleFunction('number_votes_vp', array($this, 'b'))
);
}
public function getName()
{
//return 'number_employees';
return 'vp_app_extension';
}
public function b($id)
{
$qb=$this->em->createQueryBuilder();
$qb->select('count(v.id)')
->from('DutBundle:Voters','v')
->join('v.vp','c')
->where('c.id = :x')
->setParameter('x',$id);
$count = $qb->getQuery()->getSingleScalarResult();
return $count;
}
}
Now in order to count each vp's related voters, I can call a service and send the result to twig
public function all_vpAction()
{
$em = $this->getDoctrine()->getManager();
$vice_president = $em->getRepository('DutBundle:Vp')->findAll();
//communicate to service container
$data = $this->container->get('duterte.twig.vp_app_extension');
$datas = array();
foreach ($vice_president as $value) {
$datas[] = array('id' => $value->getId(),'firstname' => $value->getFirstname() . ' ' . $value->getLastname(),'numbers' => (int)$data->b($value->getId()));
}
$vice = $datas;
return $this->render('DutBundle:Vp:all_vp.html.twig', array(
'vps' => $vice,
));
//or we can wrap this in json
$serializer = $this->container->get('jms_serializer');
$jsonContent= $serializer->serialize($vice,'json');
return $jsonContent;
}
With this set up, I can wrap this into json and and using custom twig filter, I can display data sorted either in Angular or in plain Twig template or both
By the way, my view
{% extends '::base.html.twig' %}
{% block body %}
{% block stylesheets %}
{{ parent() }}
<style type="text/css">
#img-responsive{
height: 320px;
/*width: 300px;*/
}
</style>
{% endblock %}
<div class="section-heading">
<h2>Best Tandem Of the Day</h2>
</div>
<div class="row">
<div class="col-sm-6 col-md-4">
<div class="thumbnail">
<img src="/img/dut.jpg" id="img-responsive">
<div class="caption">
<h3>President</h3>
</div>
</div>
</div>
<div class="col-sm-6 col-md-4">
<div class="thumbnail">
<img src="/img/unknown.jpg" id="img-responsive">
<div class="caption">
<h3>Vice-President</h3>
</div>
</div>
</div>
</div>
<hr />
<div ng-app="myApp" ng-controller="customersCtrl">
Search Here: <input type="text" placeholder="search" ng-model="searchMe"/><br />
<table class="table">
//names//
<thead>
<tr>
<th>Full Name</th>
<th>Middlename</th>
<th>Lastname</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="x in names">
<td>//x.id//</td>
<td>//x.firstname//</td>
<td>//x.numbers//</td>
</tr>
</tbody>
</table>
</div>
<div class="table-responsive">
<table class="table table-hover table-bordered table-condensed" id="table1">
<thead>
<tr>
<th>#</th>
<th>Bet</th>
<th>Votes</th>
<!--th>Photo</th-->
</tr>
</thead>
<tbody>
{% for v in vps | sortbyfield('numbers') %}
{% if v.numbers > 0 %}
<tr>
<td>{{ v.id }}</td>
<td>{{ v.firstname }}</td>
<td>{{ v.numbers }}</td>
</tr>
{% endif %}
{% endfor %}
</tbody>
</table>
</div>
{% endblock %}
{% block javascripts %}
{{ parent() }}
<script src="//code.angularjs.org/1.4.8/angular.js"></script>
<script>
var app = angular.module('myApp', []);
app.config(function($interpolateProvider) {
$interpolateProvider.startSymbol('//');
$interpolateProvider.endSymbol('//');
});
app.controller('customersCtrl',['$scope','$http',function($scope, $http) {
$http.get("{{ path('vp_president') }}")
.success(function (response) {
$scope.names= JSON.parse(response);
});
</script>
{% endblock %}

egeloen/ivory-google-map load only one map

I am using egeloen/ivory-google-map library to show map for each registered user. But in all user list only one map is showing.
This is my method:
public function findCompaniesAction() {
$em = $this->getDoctrine()->getManager();
$companies = $em->createQueryBuilder()
->select('b')
->from('RFQIronilBundle:User', 'b')
->where('b.acc_type = 1')
->getQuery()
->getResult();
foreach ($companies as $key => $company) {
$map = $this->get('ivory_google_map.map');
$map->setMapOption('mapTypeId', MapTypeId::ROADMAP);
$map->setMapOption('mapTypeId', 'roadmap');
$company->map = $map;
}
return $this->render('RFQIronilBundle:Default:find-companies.html.twig', array(
'companies' => $companies
));
}
and in my view I use:
{% for companies in companies %}
{{ google_map_container(companies.map) }}
{{ google_map_js(companies.map) }}
{% endfor %}
All is fine, but map is showing for only first user. What I have missed?
Try giving each map a unique container id. I use something like this:
$map->setHtmlContainerId('map_canvas_'.md5($address));
where $address is a simple address string.

Which is best paginator for in doctrine symfony2?

I have written custom queries in my repository class and they returns arrays then I do some processing on those arrays then displays to twig.
So please suggest the best pagination method to apply paging on this custom queries resulting in arrays.
I am new to symfony2, does default paging will work and how? I mean what syntax, please provide example.
You should try Knp Paginator. It is simple and customizable.
Simple code example (Doctrine MongoDB ODM):
// Pay attention: query, not result.
$query = $this->getRepositoryOfferKind()->createQueryBuilder()
->field('is_private')->equals(false)
->field('is_deleted')->notEqual(true)
->sort('updated_at', 'DESC')->getQuery();
$paginator = $this->get('knp_paginator');
$pagination = $paginator->paginate($query, $request->get('page', 1), 20);
/* #var $pagination SlidingPagination */
$pagination->setUsedRoute('admin_offer_kind_index');
$pagination->setPageRange(10);
return array(
'objects' => $pagination,
);
And twig:
<table>
<thead>
<tr>
<th>Title</th>
</tr>
</thead>
<tbody>
{% for object in objects %}
<tr>
<td>
{{ object.title }}
</td>
</tr>
{% else %}
<tr>
<td>No data</td>
</tr>
{% endfor %}
</tbody>
<tfoot>
<tr>
<td>
{{ knp_pagination_render(objects) }}
</td>
</tr>
</tfoot>
</table>
You can try this native solution
public function getPagination($someValue, int $page = 1, $limit = 20, $sort = "createdAt", $sortOrder = 'DESC')
{
$qb = $this->createQueryBuilder();
$qb->field('some_filed')->equals($someValue);
// and so on
return $qb->sort($sort, $sortOrder)
->skip(($page - 1) * $limit)
->limit($limit)
->getQuery()->toArray();
}

Resources