Query at Sonata Admin - php

I'm using Sonata to make a backoffice and at configureFormFields, I want do a query to return some values. The query is well done and returns values when I use var_dump, but at the form I always get "Class does not exist". Can you help me?
Here is the code:
protected function configureFormFields(FormMapper $formMapper)
{
/* #var $queryBuilder \Doctrine\ORM\QueryBuilder */
$queryBuilder = $this->getModelManager()
->getEntityManager('EBCoreKernelBundle:Campaign\Campaign')
->createQueryBuilder();
$queryBuilder->select('cmp.id, cmp.name')
->from('EBCoreKernelBundle:Campaign\Campaign', 'cmp');
/* #var $templateList Template[] */
$templateList = $queryBuilder->getQuery()->execute();
var_dump($templateList);
$formMapper
->add('name','sonata_type_model', array('required' => true, 'query' => $queryBuilder));
}

$entity = new \Nnx\AbpBundle\Entity\Truc();
$query = $this->modelManager->getEntityManager($entity)->createQuery('SELECT t FROM Nnx\AbpBundle\Entity\Truc t ORDER BY t.lib ASC')->execute();

As documentation:
https://sonata-project.org/bundles/admin/master/doc/reference/form_types.html
query defaults to null. You can set this to a QueryBuilder instance in
order to define a custom query for retrieving the available options.
So, let's give it a query builder:
$queryBuilder = $this->getModelManager()
->getEntityManager(Category::class)
->createQueryBuilder('c')
->select('c')
->from('AppBundle:Category', 'c')
->orderBy('c.title', 'ASC')
;
$formMapper->add('toto', ModelType::class, array(
'query' => $queryBuilder
))

Related

QueryBuilder with a relationship in Symfony

I'm coding in Symfony a search bar working with a query builder for an entity named "Structure" which is related to an entity "Partenaire" (OneToMany), it's working great but the problem is that it shows all the structures and I need to display only the structures related to the Partenaire. If someone can help me to solve this issue, thank you.
PartenaireController.php:
#[Route('/{id}', name: 'app_partenaire_show', methods: ['GET', 'POST'])]
public function show(Partenaire $partenaire, EntityManagerInterface $entityManager, PartenaireRepository $partenaireRepository,Request $request, PartenairePermissionRepository $partenairePermissionRepository, StructureRepository $structureRepository): Response
{
$getEmail = $this->getUser()->getEmail();
$partenaireId = $entityManager->getRepository(Partenaire::class)->findOneBy([
'id' => $request->get('id')
]);
$search2 = $structureRepository->findOneBySomeField2(
$request->query->get('q')
);
return $this->render('partenaire/show.html.twig', [
'partenaire' => $partenaire,
'permission'=>$partenairePermissionRepository->findBy(
['partenaire' => $partenaireId],
),
'structures'=>$search2, // show all the structures
/* 'structures'=>$structureRepository->findBy( // show the structure linked to the partenaire but doesn't work with the search
['partenaire' => $partenaireId],
[],
),*/
'email'=>$getEmail,
]);
}
StructureRepository.php :
public function findOneBySomeField2(string $search2 = null): array
{
$queryBuilder = $this->createQueryBuilder('q')
->orderBy('q.id' , 'ASC');
if ($search2) {
$queryBuilder->andWhere('q.Adresse LIKE :search')
->setParameter('search', '%'.$search2.'%');
}
return $queryBuilder->getQuery()
->getResult()
;
}
as it's a One To Many relation, you should join the right table and add a where statement in your structure query like :
public function findByPartenaireWithFilter(Partenaire $partenaire, string $search2 = null): array
{
$queryBuilder = $this->createQueryBuilder('q')
->leftJoin('q.partenaire','p')
->where('p.partenaire.id = :partenaireId')
->setParameter('partenaireId', $partenaire->getId())
->orderBy('q.id' , 'ASC');
if (null !== $search2) {
$queryBuilder->andWhere('q.Adresse LIKE :search')
->setParameter('search', '%'.$search2.'%');
}
return $queryBuilder
->getQuery()
->getResult();
}
You need to limit your results to the desired Partenaire by adding a condition. You can achieve this by simply passing another argument to the repository function.
I've removed the commented code in the controller and the loading of the Partenaire entity, as it should be already loaded thanks to the magic of param converters.
#[Route('/{id}', name: 'app_partenaire_show', methods: ['GET', 'POST'])]
public function show(Partenaire $partenaire, EntityManagerInterface $entityManager, Request $request, PartenairePermissionRepository $partenairePermissionRepository, StructureRepository $structureRepository): Response
{
$getEmail = $this->getUser()->getEmail();
// The Partenaire should already be loaded
$result = $structureRepository->findByPartenaireWithFilter(
$partenaire,
$request->query->get('q')
);
return $this->render('partenaire/show.html.twig', [
'partenaire' => $partenaire,
'permission' => $partenairePermissionRepository->findBy(
['partenaire' => $partenaireId],
),
'structures' => $search2, // show all the structures
'email' => $getEmail,
]);
}
As for the repository, it's pretty straightforward: pass the loaded partenaire and add a where clause.
public function findByPartenaireWithFilter(Partenaire $partenaire, string $search2 = null): array
{
$queryBuilder = $this->createQueryBuilder('q')
->where('q.partenaire = :partenaire')
->setParameter('partenaire', $partenaire)
->orderBy('q.id' , 'ASC');
if (null !== $search2) {
$queryBuilder->andWhere('q.Adresse LIKE :search')
->setParameter('search', '%'.$search2.'%');
}
return $queryBuilder
->getQuery()
->getResult();
}
As for the permissions key in the controller, I think what you are trying to do, I'd recommend looking into security voters.

Symfony 4 - populate array with the users of type ROLE_FITTER

Symfony 4 app using FOSUserBundle.
Trying to list users with a particular role (ROLE_FITTER) in a dropdown menu using jquery/ajax.
I'm trying to add an Action in my APIController that will get the list of users with role ROLE_FITTER and return a JSON array with them in it - so can then populate the dropdown with list of these users.
I have tried to pull together some different examples, but not sure how to correctly build the query:
namespace App\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
class APIController extends AbstractController
{
/**
* Returns a JSON string of the Fitters with their id.
*
* #Route(/profile/booking/new/fitters)
* #param Request $request
* #return JsonResponse
*/
public function listFitters(Request $request)
{
// Get Entity manager and repository
$em= $this->getDoctrine()->getManager();
$qb = $em->createQueryBuilder();
$qb->select('u')
->from('userBundle:User', 'u')
->where('u.id = :user')
->andWhere('u.roles LIKE :roles')
->setParameter('user', $id)
->setParameter('roles', '%"' . $role . '"%');
$user = $qb->getQuery()->getResult();
// Serialize into an array the data that we need, in this case only name and id
$responseArray = array();
foreach ($users as $user) {
$responseArray[] = array(
"id" => $user->getId(),
"name" => $user->getName()
);
}
// Return array for dropdown
return new JsonResponse($responseArray);
}
}
How do I populate this array with the users of type ROLE_FITTER?
Well using serialized strings in sql is never a good idea, no idea why such a popular bundle would do that, but it is what it is.
Your query as written checks for a user with specific id, and role. but you never provide the id or role!.
I dont think you want to query by id, so the correct query should be something like this:
public function listFitters(Request $request)
{
// Get Entity manager and repository
$em= $this->getDoctrine()->getManager();
$qb = $em->createQueryBuilder();
//set required role
$role = 'ROLE_FITTER';
$qb->select('u')
->from('userBundle:User', 'u')
->where('u.roles LIKE :roles')
->setParameter('roles', '%"' . $role . '"%');
$user = $qb->getQuery()->getResult();
// Serialize into an array the data that we need, in this case only name and id
$responseArray = array();
foreach ($users as $user) {
$responseArray[] = array(
"id" => $user->getId(),
"name" => $user->getName()
);
}
// Return array for dropdown
return new JsonResponse($responseArray);
}
Probably you should only select the fields you want (id, name) and avoid the array building loop, but i am not particularly familiar with symfony / doctrine so not sure of the correct syntax

research in the DB by the start of the name symfony

I would need a little help. I'm trying to implement a search bar with symfony, this search bar in the database. What I can do but the problem is that I absolutely have to put the full name to find the person (s) corresponds to that name. Except that I would like to be able to retrieve all the people starting with the beginning of the name I entered. For example :
I type "dub" and I find: "Dubois", "Dubost", "Dubububu", ....
public function searchAction (Request $request)
{
$defaultData = array('search' => 'Type your search here');
$form = $this->createFormBuilder()
->add('search', TextType::class, array('label'=>'Surname ?','required'=>true))
->add('send', SubmitType::class)
->getForm();
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$data = $form->getData();
$repository = $this
->getDoctrine()
->getManager()
->getRepository('PegasusWebBundle:Clients')
;
//$clients = $repository->findBySurname($form->get('search')->getData()); // Method 1
$clients = $repository->myFindname($form->get('search')->getData()); // Method 2 with Repository
return $this->render('PegasusWebBundle:Default:searchresult.html.twig',array(
'clients'=> $clients ));
}
else
return $this->render('PegasusWebBundle:Default:search.html.twig', array(
'form' => $form->createView(),
));
}
The repository for the method 2
`class ClientsRepository extends \Doctrine\ORM\EntityRepository
{
public function myFindname($name)
{
// Method 2
$qb = $this->createQueryBuilder('a');
$qb->where(
$qb->expr()->like('a.surname' ,':surname'))
->setParameter('surname', $name);
return $qb
->getQuery()
->getResult();
}
}`
Try adding the wildchar eg:
$query = $repo->createQueryBuilder('a')
->where('a.surname LIKE :surname')
->setParameter('surname', '%'.$name.'%')
->getQuery();
Try adding a SQL wildcard character (%) after the surname value.
Also See this as reference.

Symfony submit a search form with categories and region

I got a search form in page's header that must to submit to my SearchController and be handeld by searchAction in case of the user input only the query string.
This form got the ability to search in selected category and country region.
So the user can make the search in all category and all region or select category and all region or select category and region
How I can handle this? I've made the controller action that actually work when i put the data in url.
Here is my search class using QueryBuilder:
class SearchController extends Controller
{
/**
* #Route("cerca/{query}", name="search")
*/
public function searchAction(Request $request,$query)
{
$results = $this->getDoctrine()
->getRepository('AppBundle:Ads')
->createQueryBuilder('p')
->where("p.name LIKE '%$query%'")
->getQuery()
->getResult(\Doctrine\ORM\Query::HYDRATE_ARRAY);
return $this->render('search\search.html.twig', [
//'pagination'=>$pagination,
'query' => $query,
'region' => 'Italia',
'results' => $results,
]);
}
/**
* #Route("cerca/{region}/{query}", name="search_regioni")
*/
public function searchRegionAction($region,$query)
{
$results = $this->getDoctrine()
->getRepository('AppBundle:Ads')
->createQueryBuilder('p')
->where("p.name LIKE '%$query%'")
->andWhere("p.region Like '%$region%'")
->getQuery()
->getResult(\Doctrine\ORM\Query::HYDRATE_ARRAY);
$region = ucfirst($region);
return $this->render('search/search.html.twig', [
'region' => $region,
'query' => $query,
]);
}
/**
* #Route("cerca/{category}/{query}", name="search_categorie")
*/
public function searchCategoryAction($category,$query)
{
$results = $this->getDoctrine()
->getRepository('AppBundle:Ads')
->createQueryBuilder('p')
->where("p.name LIKE '%$query%'")
->andWhere("p.region Like '%$region%'")
->getQuery()
->getResult(\Doctrine\ORM\Query::HYDRATE_ARRAY);
$category = ucfirst($category);
return $this->render('search/search.html.twig', [
'region' => 'Italia',
'category' => $category,
'query' => $query,
]);
}
/**
* #Route("cerca/{category}/{region}/{query}", name="search_categorie_regioni")
*/
public function searchCategoryRegionAction($category,$region,$query)
{
$results = $this->getDoctrine()
->getRepository('AppBundle:Ads')
->createQueryBuilder('p')
->where("p.name LIKE '%$query%'")
->andWhere("p.region LIKE '%$region%'")
->andWhere("p.category LIKE '%$category%'")
->getQuery()
->getResult(\Doctrine\ORM\Query::HYDRATE_ARRAY);
$category = ucfirst($category);
$region = ucfirst($region);
return $this->render('search/search.html.twig', [
'region' => $region,
'category' => $category,
'query' => $query,
]);
}
}
How I can make the form submit to this controller? How to handle the different cases?
I think my logic is wrong too, symfony don't know if I search for a category or country region, how can I improve this?
I think instead of having different actions you should submit the data and store it in a ValueObject, e.g. a Search object:
class Search {
public $query;
public $category;
public $region;
}
You could also create a SearchType that binds a form to the value object and provides some validation and constraints, e.g. create a ChoiceLoader that loads the available categories from a database and checks that the selected one is valid. After submitting and validating the form input you retrieve the search object from the form and use it to build your Doctrine-Query. In case region is empty, e.g. not selected you just omit it from the query like this:
/** #var Search $search **/
$search = $form->getData();
$queryBuilder = $this->getDoctrine()
->getRepository('AppBundle:Ads')
->createQueryBuilder('p')
$queryBuilder->where($queryBuilder->expr()->like('p.name', "%{$search->query}%");
if (null != $search->region) {
$queryBuilder->andWhere('region = :region')
->setParameter('region', $search->region);
}
$results = $queryBuilder->createQuery()->getResults();
Some things to note:
Do not just inject the variables into the where-clauses. This is a security problem. You should use parameters and the expression builder to safeguard against SQL injection.
You can chain clauses in the query builder (like you do above) or split them up, like I do in the if condition.
Since the form is already connected to the Search-object the fields should be pre-filled with the last inserted values, so you don't have to pass around the input separately.
I'm not 100% sure the LIKE-expression will work as expected. It can be somewhat tricky. You should search for how to use it properly.

How to get group from user in SonataUserBundle?

I'm using symfony 2.2.3 and sonata admin in dev-master.
I would like a custom field to show users from a specific group.
I've not found how to make the relation with Sonata User entity and Sonata Group entity.
The doctrine schema create 3 tables : fos_user_user, fos_user_group and the relation table fos_user_user_group.
I've a form with a field like that in my Admin class :
->add('coach', 'entity', array(
'class' => 'ApplicationSonataUserBundle:User',
'empty_value' => 'Choisissez un coach',
'property' => 'username',
'query_builder' => function(\Application\Sonata\UserBundle\Entity\UserRepository $er) {
return $er->getCoachs();
},
))
And my function getCoachs() in UserRepository:
public function getCoachs()
{
$em = $this->getEntityManager();
$qb = $em->createQueryBuilder(array('u', 'g'))
->select('u.username, g.id')
->from('ApplicationSonataUserBundle:User', 'u')
->innerJoin('ApplicationSonataUserBundle:Group', 'g', 'WITH','g.id = u.group_id')
->where('g.id = :id')
->setParameter('id', 1);
return $qb;
}
I know that the query doesn't work because the innerJoin isn't correct.
My user entity and group entity just extends BaseUser and GroupUser with an id.
Someone know the right query ?
Thank you.
EDIT :
Ok i've found the solution for the query :
public function getCoachs()
{
$em = $this->getEntityManager();
$qb = $em->createQueryBuilder('u')
->select('u.username')
->from('ApplicationSonataUserBundle:User', 'u')
->innerJoin('u.groups', 'g')
->where('g = :id')
->setParameter('id', 1);
return $qb;
}
However, i've this error :
Expected argument of type "object or array", "string" given
I don't understand because I return my function getCoachs() which return a query builder...
No idea ?
Ok I've found the solution !
My query is :
public function getCoachs()
{
$em = $this->getEntityManager();
$qb = $em->createQueryBuilder('u')
->select('u') // and not u.username
->from('ApplicationSonataUserBundle:User', 'u')
->innerJoin('u.groups', 'g')
->where('g = :id')
->setParameter('id', 1);
return $qb;
}
In fact, I returned values of a specific column (username) but you have to return the object User.

Categories