I am new by using Symfony and I am a bit confused concerning the structure. I made a custom query with the queryBuilder but I don't really know where to put this piece of code. It work inside the controller but I don't like to have interaction with db there. So I though to put it inside an entity repository but it's really limited and I am not able to use it for my case. This query make a request with join and filter by multiple column.
So where could I put this code?
Edit1:
$repository = $this->getDoctrine()->getRepository('EgCBGEBundle:portfoliohistory_pfh');
$queryBuilder = $repository->createQueryBuilder('pfh');
$queryBuilder->innerJoin('pfh.portfolio', 'pfo', \Doctrine\ORM\Query\Expr\Join::WITH, 'pfh.id_pfo = pfo.id_pfo');
$queryBuilder->where('pfh.scenario = :scenario')
->andWhere('pfh.measure_catalogue = :measureCatalogue')
->andWhere('pfh.portfolio IN ('.$subs.')')
->andWhere('pfh.date = :date')
->setParameter('scenario', $scenario)
->setParameter('measureCatalogue', $type)
->setParameter('date', $date)
->groupBy('pfh.portfolio, pfh.id') // , pfo.id
//->orderBy('pfo.id', 'ASC')
->setMaxResults(5);
return $queryBuilder->getQuery()->getResult();
Add it to your custom repository: http://docs.doctrine-project.org/en/2.0.x/reference/working-with-objects.html#custom-repositories
Class YourEntityRepository extends EntityRepository
{
public function findMyQuery($scenario, $type, $date){
$queryBuilder = $this->createQueryBuilder('pfh');
$queryBuilder->innerJoin('pfh.portfolio', 'pfo', \Doctrine\ORM\Query\Expr\Join::WITH, 'pfh.id_pfo = pfo.id_pfo');
$queryBuilder->where('pfh.scenario = :scenario')
->andWhere('pfh.measure_catalogue = :measureCatalogue')
->andWhere('pfh.portfolio IN ('.$subs.')')
->andWhere('pfh.date = :date')
->setParameter('scenario', $scenario)
->setParameter('measureCatalogue', $type)
->setParameter('date', $date)
->groupBy('pfh.portfolio, pfh.id') // , pfo.id
//->orderBy('pfo.id', 'ASC')
->setMaxResults(5);
return $queryBuilder->getQuery()->getResult();
}
And don't forget to include it in your entity:
/**
* #ORM\entity(repositoryClass="My\Bundle\Entity\YourEntityRepository ")
*/
In your controller
$results= $em->getRepository('My\Bundle\Entity\YourEntity')->findMyQuery($scenario, $type, $date);
You should put it in your repository
class YourEntityRepository extends EntityRepository
{
public function findItWithACustomQuery($some_params){
$queryBuilder = $this->createQueryBuilder('pfh');
$queryBuilder->innerJoin('pfh.portfolio', 'pfo', \Doctrine\ORM\Query\Expr\Join::WITH, 'pfh.id_pfo = pfo.id_pfo');
$queryBuilder->where('pfh.scenario = :scenario')
->andWhere('pfh.measure_catalogue = :measureCatalogue')
->andWhere('pfh.portfolio IN ('.$subs.')')
->andWhere('pfh.date = :date')
->setParameter('scenario', $scenario)
->setParameter('measureCatalogue', $type)
->setParameter('date', $date)
->groupBy('pfh.portfolio, pfh.id') // , pfo.id
//->orderBy('pfo.id', 'ASC')
->setMaxResults(5);
return $queryBuilder->getQuery()->getResult();
}
Then you just call it in your controller or service by
$em->getRepository('YourEntityBundle:YourEntity')->findItWithACustomQuery($params);
QueryBuilder is part of Doctrine. You can use it in your controller or in a custom class.
Here is a part of the official doc http://doctrine-orm.readthedocs.org/en/latest/reference/query-builder.html
http://www.doctrine-project.org/api/orm/2.4/class-Doctrine.ORM.QueryBuilder.html
And an example : http://drafts.easybib.com/post/44139111915/taiming-repository-classes-in-doctrine-with-the
Related
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
I'm using a method to find the records to change. Follow the code:
public function findId($id)
{
$subCategoria = $this->model::join(
'categoria', 'categoria.id', '=', 'sub_categoria.id_categoria')
->select(
'sub_categoria.id AS id_sub_categoria',
'sub_categoria.nome AS nome_sub_categoria',
'categoria.nome AS nome_categoria',
'categoria.id as id_categoria'
)
->where('sub_categoria.id', $id)
->where(
'sub_categoria.id_unidade_de_trabalho',
Auth::user()->id_unidade_de_trabalho
)
->where(
'categoria.id_unidade_de_trabalho',
Auth::user()->id_unidade_de_trabalho
)
->whereNull('sub_categoria.deleted_at')
->whereNull('categoria.deleted_at')
->first();
return $subCategoria;
}
My update method looks like this:
public function update(array $data, $id)
{
$model = $this->findId($id);
$model->nome = $data['nome'];
$model->id_categoria = $data['id_categoria'];
return $model->save();
}
Funny that when I use the find method, which is extended from Model, it works!
I'm working on an event booking system. When the user searches for a date range, I use a function inside my Event model that checks if the event is available. My search function currently works as follows:
$events = Event::where('name', 'LIKE', '%' . $request->get('term') . '%')
->where('accepted',1)
->orWhere('description', 'LIKE', '%'.$request->get('term').'%')
->orWhere('city', 'LIKE', '%'.$request->get('term').'%')->paginate(15);
$availableEvents = new Collection();
if ($request->get('from') !== '' AND $request->get('to') !== '') {
foreach($events as $key => $event) {
if ($event->is_available($request->get('from'), $request->get('to'))) {
$availableEvents->add($event);
}
}
}
else {
$availableEvents = $events;
}
return view('frontend.events.results', ['events' => $availableEvents, 'request' => $request]);
I can't check availability inside the query builder so I have to loop through. I'm using a Illuminate\Database\Eloquent\Collection because I can't remove events from the paginated thing I get from the query builder.
Is there some way to convert the Eloquent Collection to a paginated collection?
Thanks in advance!
P.S. I'm passing $request to the view to use appends() so I can retain the query string parameters during pagination.
EDIT: The is_available function
public function is_available($from, $to) {
$from = Carbon::createFromFormat('d-m-Y', $from);
$to = Carbon::createFromFormat('d-m-Y', $to);
foreach($this->not_availables as $notAvailable) {
$notAvailableFrom = Carbon::createFromFormat('Y-m-d', $notAvailable->from);
$notAvailableTo = Carbon::createFromFormat('Y-m-d', $notAvailable->to);
if ($from->gte($notAvailableFrom) OR $to->lte($notAvailableTo)) {
return false;
}
}
return true;
}
You can manually create a paginator
You could use Illuminate\Pagination\LengthAwarePaginator like this:
use \Illuminate\Pagination\LengthAwarePaginator;
...
$page = $request->get('page', 1);
$limit = 10;
$paginator = new LengthAwarePaginator(
$availableEvents->forPage($page, $limit), $availableEvents->count(), $limit, $page, ['path' => $request->path()]
);
Then pass the $paginator along with your view, instead of your $availableEvents. In your view you still have $events, you can render the pagination with $events->render(); and pass on the route parameters from $request as you normally would.
Our controllers in our symfony application often have to filter query results before handing the results over to the view template. What is the best way to filter those query results. At the moment we often have something like this:
public function indexAction()
{
$form = $this->getFilterForm();
$repository = $this->getDoctrine()->getRepository(...);
$queryBuilder = $repository->createQueryBuilder('q');
if ($name = $form->get('name')->getData()) {
$queryBuilder
->andWhere('q.name = :name')
->setParameter('name', $name);
}
if ($birthday = $form->get('birthday')->getData()) {
$queryBuilder
->andWhere('q.name = :name')
->setParameter('name', $birthday);
}
return array(
'result' => $queryBuilder->getQuery()->getResult()
);
}
In my opinion this should not be part of the controller. On the other hand I think that putting all of this in a repository class for that entity type could lead to many filter* methods for multiple concerns.
Does anyone have a best practice for that or any other clever idea where to put filter methods or how to handle filtering data?
Hi
I've got the following query but it doesn't seem to work.
$q = $this->em->createQueryBuilder()
->update('models\User', 'u')
->set('u.username', $username)
->set('u.email', $email)
->where('u.id = ?1')
->setParameter(1, $editId)
->getQuery();
$p = $q->execute();
This returns the following error message:
Fatal error: Uncaught exception
'Doctrine\ORM\Query\QueryException'
with message '[Semantical Error] line
0, col 38 near 'testusername WHERE':
Error: 'testusername' is not defined.'
in ...
I would be glad of any help
I think you need to use ->set() It's much safer to make all your values parameters:
$queryBuilder = $this->em->createQueryBuilder();
$query = $queryBuilder->update('models\User', 'u')
->set('u.username', ':userName')
->set('u.email', ':email')
->where('u.id = :editId')
->setParameter('userName', $userName)
->setParameter('email', $email)
->setParameter('editId', $editId)
->getQuery();
$result = $query->execute();
Let's say there is an administrator dashboard where users are listed with their id printed as a data attribute so it can be retrieved at some point via JavaScript.
An update could be executed this way …
class UserRepository extends \Doctrine\ORM\EntityRepository
{
public function updateUserStatus($userId, $newStatus)
{
return $this->createQueryBuilder('u')
->update()
->set('u.isActive', '?1')
->setParameter(1, $qb->expr()->literal($newStatus))
->where('u.id = ?2')
->setParameter(2, $qb->expr()->literal($userId))
->getQuery()
->getSingleScalarResult()
;
}
AJAX action handling:
# Post datas may be:
# handled with a specific custom formType — OR — retrieved from request object
$userId = (int)$request->request->get('userId');
$newStatus = (int)$request->request->get('newStatus');
$em = $this->getDoctrine()->getManager();
$r = $em->getRepository('NAMESPACE\User')
->updateUserStatus($userId, $newStatus);
if ( !empty($r) ){
# Row updated
}
Working example using Doctrine 2.5 (on top of Symfony3).
With a small change, it worked fine for me
$qb=$this->dm->createQueryBuilder('AppBundle:CSSDInstrument')
->update()
->field('status')->set($status)
->field('id')->equals($instrumentId)
->getQuery()
->execute();