I have an entity "Vehicules" that have ManyToOne relation with the entity "User". So each User hav one or more vehicules. I'm trying to count the number of vehicules foreach user and trying to show it in a table .
this is a part of my entity Vehicule
/**
* #ORM\ManyToOne(targetEntity="OC\UserBundle\Entity\User")
* #ORM\JoinColumn(name="User_id", referencedColumnName="id", onDelete="CASCADE")
*/
protected $direction;
this is the function in which i want to count the number of vehicules foreach user (direction) and show it in a table
public function afficheAction() {
$em = $this->getDoctrine();
$demandes = $em->getRepository('DemandevehBundle:Demande')->findAll();
// trying to count the number of vehicules foreach direction
$vehicules = $this->getDoctrine()->getRepository('CarPfeBundle:Vehicule')->findAll();
foreach($vehicules as $vehicule) {
$qb = $vehicule->createQueryBuilder('v');
$qb->select('count(v.id)');
$qb->where('v.direction = ?1');
$qb->setParameter('1', $vehicule->getId());
$query = $qb->getQuery();
$result = $query->getSingleScalarResult();
return $result;
}
// fin
return $this->render('DemandevehBundle:Demande:affiche.html.twig', array('demandes' => $demandes
,'result' => $result));
}
I get this error
Attempted to call method "createQueryBuilder" on class "Car\PfeBundle\Entity\Vehicule".
I feel that my function make no sense that's why i get this error. Any help please ?
Is possible to create a query builder on an entity manager instead of an entity. So you use the relative manager of the class so try this:
$qb = $this->getDoctrine()
->getRepository('CarPfeBundle:Vehicule')
->createQueryBuilder('v');
instead of this:
$qb = $vehicule->createQueryBuilder('v');
Hope this help
Related
Maybe I don't understand this idea but I'm starting create my first test app that use api platform.
I have custom action for my search:
/**
* #Route(
* path="/api/pharmacies/search",
* name="pharmacy_search",
* defaults={
* "_api_resource_class"=Pharmacy::class,
* "_api_collection_operation_name"="search"
* }
* )
* #param Request $request
*
* #return Paginator
*/
public function search(Request $request)
{
$query = SearchQuery::createFromRequest($request);
return $this->pharmacyRepository->search($query);
}
and method in the repository:
public function search(SearchQuery $searchQuery: Paginator
{
$firstResult = ($searchQuery->getPage() - 1) * self::ITEMS_PER_PAGE;
$qb = $this->createQueryBuilder('p')
/...
->setFirstResult($firstResult)
->setMaxResults(self::ITEMS_PER_PAGE);
$doctrinePaginator = new DoctrinePaginator($qb, false);
return new Paginator($doctrinePaginator);
}
And it works fine but this action doesn't need all field form the entity and relations to other tables. Currently this action creates 22 queries. I'd like create query in the DBAL/QueryBuilder and return pagination object with DTO.
public function search(SearchQuery $searchQuery)
{
.../
$qb = $this->createQueryBuilder('p')
->select('p.id')
->addSelect('p.name')/....
$rows = $qb->getQuery()->getArrayResult();
foreach ($rows as $row){
$data[] = new SearchPharmacy($row['id'], $row['name']);
}
return $data;
}
The above code will work but if the response isn't Pagination object and I don't have hydra:totalItems, hydra:next etc in the response.
In theory I can use DataTransformer and transform entity to DTO, but this way can't allow simplify database queries.
Can I achieve this?
I don't know how to use dbal query and mapped the result on a DTO, but I know how to add custom select, return it like a scalar:
public function search(SearchQuery $searchQuery): Paginator
{
$firstResult = ($searchQuery->getPage() - 1) * self::ITEMS_PER_PAGE;
$qb = $this->createQueryBuilder('p')
->select('p.id')
->addSelect('p.name')
->where('p.name LIKE :search')
->setParameter('search', "%" . $searchQuery->getSearch() . "%");
$query = $qb->getQuery()->setFirstResult($firstResult)
->setMaxResults(self::ITEMS_PER_PAGE);
$doctrinePaginator = new DoctrinePaginator($query, false);
$doctrinePaginator->setUseOutputWalkers(false);
return new Paginator($doctrinePaginator);
}
It finally I have 2 light queries, selected field from entity and Pagination.
Sources:
https://github.com/APY/APYDataGridBundle/issues/931
https://www.doctrine-project.org/projects/doctrine-orm/en/2.8/cookbook/dql-custom-walkers.html
How to show two tables data from my controller.
Here is my controller's code.
class TestController extends Controller
{
public function showAction(Request $request)
{
$em = $this->getDoctrine()->getManager();
$teacher = $this->getDoctrine()->getRepository(Teacher::class);
$query = $em
->createQueryBuilder('t')
->from('AppBundle:Teacher','t')
->Join('AppBundle:Student','s')
->where('t.id=id and s.tid=tid')
->getQuery()
->getResult();
}
}
When print_r it's showing only one table data.
Please help
Please check below mentioned solution.
$query = $em
->createQueryBuilder('t.*,s.*')
->from('AppBundle:Teacher','t')
->Join('AppBundle:Student','s')
->where('t.id=id and s.tid=tid')
->getQuery()
->getResult();
}
Let me know if it not works.
I assume that you have defined a relationship between Teacher and Student in your entities. In this case you can get the Student objects by calling $teacher->getStudents() (assuming that you have defined such a method in your Teacher entity class). See Doctrine documentation about association mapping
Example for a One-To-Many relationship:
<?php
use Doctrine\Common\Collections\ArrayCollection;
/** #Entity */
class Teacher
{
// ...
/**
* One Teacher has Many Students.
* #OneToMany(targetEntity="Student", mappedBy="teacher")
*/
private $students;
// ...
public function __construct() {
$this->students = new ArrayCollection();
}
}
/** #Entity */
class Student
{
// ...
/**
* Many Students have One Teacher.
* #ManyToOne(targetEntity="Teacher", inversedBy="students")
* #JoinColumn(name="teacher_id", referencedColumnName="id")
*/
private $teacher;
// ...
}
In the QueryBuilder object you can avoid the need of additional queries on $teacher->getStudents() calls by adding something like that:
$query = $em
->createQueryBuilder('t')
->from('AppBundle:Teacher','t')
->join('AppBundle:Student','s')
->select(array('t', 's'))
->where('t.id=id and s.tid=tid')
->getQuery()
->getResult();
}
If there is a relationship defined between Teacher and Student in your entities as mentioned above you can even simplify the join:
$query = $em
->createQueryBuilder('t')
->from('AppBundle:Teacher','t')
->join('t.students', 's')
->select(array('t', 's'))
->getQuery()
->getResult();
}
Furthmore you do not need to call the from() method if you create the QueryBuilder object via the TeacherRepository object:
$query = $teacher
->createQueryBuilder('t')
->join('t.students', 's')
->select(array('t', 's'))
->getQuery()
->getResult();
}
$query = $em
->createQueryBuilder('t')
->add('select', 't,s')
->from('AppBundle:Teacher', 't')
->Join('AppBundle:Student', 's')
->where('t.id = s.tid')
->getQuery()
->getResult();
it working perfect.
First we select all from Teachers table, then join students. Assume that your relationship name in Teachers model is student. In repository file:
public function getWithStudents() {
return $this->createQueryBuilder('t')
->Join('t.student', 's')
->addSelect('s')
->getQuery()->getArrayResult();
}
Then in controller call it:
$teachersWithStudents = $teacher->getWithStudents();
Or in this case you can just
$teachersWithStudents = $teacher->getStudents();
Suppose you have two tables.comment table and article table and You want to fetch comments on each article
$commentContent = $em
// automatically knows to select Comment
// the "c" is an alias you'll use in the rest of the query
->createQueryBuilder('c')
->select('c.message, c.name')////Fields required to display
->from('AppBundle:Comment','c')
->join('AppBundle:Article','a')
->where('c.idArticle=a.id and c.publish_mainPage = 1')
->orderBy('c.idArticle', 'DESC')
->getQuery()
->getResult();
var_dump($commentContent);
I'm making a website for performance monitoring.
I have 2 tables:
Users table linked in one-to-Many with performances
Performances table linked in Many-to-one with users table
I just wanna get the last weight which is not null in my table performances and display it in twig
database screenshot
For exemple in this database, the result would be : 80
I tried with queries but I get an arror message so I don't know how to do
Thanks in advance for your help !
I hope this could helps you.
I suppose you have a repository class for your Performance entity. I would use this kind of code for a Symfony3 application
<?php
namespace AppBundle\Repository; //replace AppBundle by the name of your bundle
use Doctrine\ORM\Tools\Pagination\Paginator;
/**
* PerformanceRepository
*
* This class was generated by the Doctrine ORM. Add your own custom
* repository methods below.
*/
class PerformanceRepository extends \Doctrine\ORM\EntityRepository
{
public function getLastWeigth()
{
$qb = $this->getEntityManager()->createQueryBuilder()
->select('p')
->from($this->_entityName, 'p')
->expr()->isNotNull('p.weight')
->orderBy('p.date', 'desc')
->setMaxResults(1);
$query = $qb->getQuery();
$result = $query->getSingleResult();
return $result;
}
}
Edit: here is an Exemple of use in the controller in a Symfony 3 application:
<?php
namespace AppBundle\Controller\Performance;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use AppBundle\Repository\PerformanceRepository;
class PerformanceController extends Controller
{
public function lastWeightAction()
{
$repo = $this->getDoctrine()->getManager()->getRepository('AppBundle:Performance');
$lastPerformance = $repo->getLastWeigth();
//some other code
}
}
Edit2:
If you need to get the last weight by a user Id:
class PerformanceRepository extends \Doctrine\ORM\EntityRepository
{
public function getLastWeigth($userId)
{
$qb = $this->getEntityManager()->createQueryBuilder()
->select('p')
->from($this->_entityName, 'p')
->join('p.user', 'u')
->where('u.id = :userId')
->expr()->isNotNull('p.weight')
->orderBy('p.date', 'desc')
->setMaxResults(1);
->setParameter(':userId', $userId);
$query = $qb->getQuery();
$result = $query->getSingleResult();
return $result;
}
}
I created a repository for my Articles entity and I'm trying to get all values ordered by ID DESC. But, I'll get everytime values ordered by id ASC. Here is my ArticleRepository.php:
<?php
namespace Acme\BlogBundle\Entity;
use Doctrine\ORM\EntityRepository;
class ArticleRepository extends EntityRepository
{
public function findAll()
{
return $this->findBy(array(), array('id' => 'DESC'));
}
public function findOneBySlug($slug)
{
$query = $this->getEntityManager()
->createQuery('
SELECT p FROM AcmePagesBundle:Article a
WHERE a.slug = :slug
')
->setParameter('slug', $slug);
try {
return $query->getSingleResult();
} catch (\Doctrine\ORM\NoResultException $e) {
return false;
}
}
}
Any ideas?
The Syntax looks good. This should provide a set of well ordered articles.
First, make sure the #Entity annotation is set with the right Repository class within the Article Entity,
/**
* #ORM\Entity(repositoryClass="...");
*/
class Article
{
// ...
}
Also, if you want to use native helpers, you've just to call findBy from the ArticleRepository within your controller,
$articles = $this->get('doctrine')
->getRepository('YourBundle:Article')
->findBy(array(), array('id' => 'DESC'));
You don't need to create a query in ArticleRepostory.php for that
In your controller you can just do:
$entities = $em->getRepository('YourBundle:Article')->findBy(array(), array( 'id' => 'DESC' ));
->findBy(array(), array( 'id' => 'DESC' )); // Order Works
->findAll(array(), array( 'id' => 'DESC' )); // Order doesn't work
This should be work:
public function findAll()
{
$em = $this->getEntityManager();
$query = $em->createQuery('
SELECT *
FROM AcmePagesBundle:Article a
ORDER BY a.id DESC
');
return $query->getResult();
}
I would tend to do this in my repository (to allow for using the same select DQL in different methods in the repository - especially when you have lots of fetch-joins to include):
class FooRepository extends EntityRepository
{
/**
* Get the DQL to select Foos with all joins
*
* #return string
*/
public function getSelectDql()
{
$dql = '
SELECT f
FROM Entity:Foo f
';
return $dql;
}
/**
* Fetch all foos, ordered
*
* #return array
*/
public function fetchAllOrdered()
{
$dql = sprintf(
'%s %s',
$this->getSelectDql(),
'ORDER BY f.id DESC'
);
return $this->getEntityManager()
->createQuery($dql)
->getResult();
}
}
This should make your repository quite flexible, allow different ordering in different methods (if you need to order them differently) and keep all DB-related code out of your controller.
Symfony 3.3 find by order working example.
From your controller:
public function indexAction(){
$entityManager = $this->getDoctrine()->getManager();
$categoryRepository = $entityManager->getRepository(ProductCategory::class);
$items = $categoryRepository->findBy(array(), array('id' => 'DESC'));
....
}
I am using the FOS bundle and I want to retrieve all users with a given ROLE from the database.
What is the best way to do this?
Just add this in your UserRepository or replace $this->_entityName by YourUserBundle:User:
/**
* #param string $role
*
* #return array
*/
public function findByRole($role)
{
$qb = $this->_em->createQueryBuilder();
$qb->select('u')
->from($this->_entityName, 'u')
->where('u.roles LIKE :roles')
->setParameter('roles', '%"'.$role.'"%');
return $qb->getQuery()->getResult();
}
If you are using FOSUser Groups you should use:
/**
* #param string $role
*
* #return array
*/
public function findByRole($role)
{
$qb = $this->_em->createQueryBuilder();
$qb->select('u')
->from($this->_entityName, 'u')
->leftJoin('u.groups', 'g')
->where($qb->expr()->orX(
$qb->expr()->like('u.roles', ':roles'),
$qb->expr()->like('g.roles', ':roles')
))
->setParameter('roles', '%"'.$role.'"%');
return $qb->getQuery()->getResult();
}
Well, if there is no better solution, I think I will go to a DQL query:
$query = $this->getDoctrine()->getEntityManager()
->createQuery(
'SELECT u FROM MyBundle:User u WHERE u.roles LIKE :role'
)->setParameter('role', '%"ROLE_MY_ADMIN"%');
$users = $query->getResult();
If you have this requirement and your user list will be extensive, you will have problems with performance. I think you should not store the roles in a field as a serialized array. You should create an entity roles and many to many relationship with the users table.
As #Tirithen states, the problem is that you will not get the users that have an implicit role due to role hierarchy. But there is a way to work around that!
The Symfony security component provides a service that gives us all child roles for a specific parent roles. We can create a service that does almost the same thing, only it gives us all parent roles for a given child role.
Create a new service:
namespace Foo\BarBundle\Role;
use Symfony\Component\Security\Core\Role\RoleHierarchy;
use Symfony\Component\Security\Core\Role\Role;
/**
* ReversedRoleHierarchy defines a reversed role hierarchy.
*/
class ReversedRoleHierarchy extends RoleHierarchy
{
/**
* Constructor.
*
* #param array $hierarchy An array defining the hierarchy
*/
public function __construct(array $hierarchy)
{
// Reverse the role hierarchy.
$reversed = [];
foreach ($hierarchy as $main => $roles) {
foreach ($roles as $role) {
$reversed[$role][] = $main;
}
}
// Use the original algorithm to build the role map.
parent::__construct($reversed);
}
/**
* Helper function to get an array of strings
*
* #param array $roleNames An array of string role names
*
* #return array An array of string role names
*/
public function getParentRoles(array $roleNames)
{
$roles = [];
foreach ($roleNames as $roleName) {
$roles[] = new Role($roleName);
}
$results = [];
foreach ($this->getReachableRoles($roles) as $parent) {
$results[] = $parent->getRole();
}
return $results;
}
}
Define your service for instance in yaml and inject the role hierarchy into it:
# Provide a service that gives you all parent roles for a given role.
foo.bar.reversed_role_hierarchy:
class: Foo\BarBundle\Role\ReversedRoleHierarchy
arguments: ["%security.role_hierarchy.roles%"]
Now you are ready to use the class in your own service. By calling $injectedService->getParentRoles(['ROLE_YOUR_ROLE']); you will get an array containing all parent roles that will lead to the 'ROLE_YOUR_ROLE' permission. Query for users that have one or more of those roles... profit!
For instance, when you use MongoDB you can add a method to your user document repository:
/**
* Find all users with a specific role.
*/
public function fetchByRoles($roles = [])
{
return $this->createQueryBuilder('u')
->field('roles')->in($roles)
->sort('email', 'asc');
}
I'm not into Doctrine ORM but I'm sure it won't be so different.
You can use just this on your DQL:
SELECT u FROM YourFavouriteBundle:User u WHERE u.roles [NOT] LIKE '%ROLE_YOUR_ROLE%'
Of course with QueryBuilder it's more elegant:
// $role = 'ROLE_YOUR_ROLE';
$qb->where('u.roles [NOT] LIKE :role')
->setParameter('role', "%$role%");
Finally i solved it, following is an exact solution:
public function searchUsers($formData)
{
$em = $this->getEntityManager();
$usersRepository = $em->getRepository('ModelBundle:User');
$qb = $usersRepository->createQueryBuilder('r');
foreach ($formData as $field => $value) {
if($field == "roles"){
$qb->andWhere(":value_$field MEMBER OF r.roles")->setParameter("value_$field", $value);
}else{
$qb->andWhere("r.$field = :value_$field")->setParameter("value_$field", $value);
}
}
return $qb->getQuery()->getResult();
}
Cheers!
In case you need to filter users by role using a DQL filter in a YAML file (In EasyAdminBundle for instance)
entities:
Admin:
class: App\Entity\User
list:
dql_filter: "entity.roles LIKE '%%ROLE_ADMIN%%'"
Here I give an alternative solution :
I find users of roles for a given array
In controller I call the function like that
$users = $userRepository->findUsersOfRoles(['ROLE_ADMIN', 'ROLE_SUPER_USER']);
Then in my repository I make a loop to generate condition and set the parameters :
public function findUsersOfRoles($roles)
{
$condition = 'u.roles LIKE :roles0';
foreach ($roles as $key => $role){
if ($key !== 0){
$condition .= " OR u.roles LIKE :roles".$key;
}
}
$query = $this->createQueryBuilder('u')
->where($condition);
foreach ($roles as $key => $role){
$query ->setParameter('roles'.$key, '%"'.$role.'"%');
}
return $query->getQuery() ->getResult();
}