For this question I have 3 entities in my DB :
Case to Line : 1 Case to Many Lines (1 case have n lines)
Line to Loan : 1 Line to Many Loans (1 line have n loans)
I want in my controller to get a Case(Dosier) by ID, then to foreach lines, and then to foreach every loan.
So, with every loan object I want to perform some calculations and collect all this data.
How can I access the loan object, to make next things like ($loan->getCapital(), $loan->getDuration() for my calculations?
I tried in this way :
/**
* #Route("/", name="homepage")
*/
public function indexAction(Request $request)
{
$user = $this->getUser();
$dosiers = $this->getDoctrine()
->getRepository('AppBundle:Dosier')
->createQueryBuilder('e')
->select('e')
->where('e.userId = :id')
->andwhere('e.isActive = 1')
->orderBy('e.id', 'DESC')
->setParameters(array('id'=> $user))
->getQuery()
->getResult();
foreach ($line as $dosiers->getLines()) {
foreach ($loan as $line->getLoans()) {
echo $loan->getName();
}
}
return $this->render('AppBundle:default:index.html.twig', array(
'dosiers' => $dosiers
));
}//indexAction
But it gives me error :
Compile Error: Can't use method return value in write context
Ah, I find a solution :
This code :
$dosiers = $this->getDoctrine()
->getRepository('AppBundle:Dosier')
->createQueryBuilder('e')
->select('e')
->where('e.userId = :id')
->andwhere('e.isActive = 1')
->orderBy('e.id', 'DESC')
->setParameters(array('id'=> $user))
->getQuery()
->getResult();
returns an array of objects that match that conditions, instead returning one object.
So, I changed the query for test in :
$dosiers = $em->getRepository('AppBundle:Dosier')->findOneBy(array('id' => 15));
and the loop to :
foreach ($dosiers->getLines() as $line) {
foreach ($line->getLoans() as $loan) {
echo $loan->getName();
}
}
and now it works. Next, need just to add a new parameter to the action, $id, and instead of constant '15' in query to put $id.
Related
I wrote some complex api to return results from stdClass objects in my controller.
That part works fine.
Then, in my service I wrote a query builder that needs to restrict results to 6 months period.
That works too when dump().
Problem arises when I try to pull my results through function within query builder.
It throws:
Object of class stdClass could not be converted to string.
My Controller:
$getResults = $this->getAllNames()->getContent();
$pullResults = json_decode($getResults);
$results = $pullResults->data->items;
// restricted to 6 month period
$this->get('my.service')->getDateRange($results); --->this part throws error
$rows = [];
$rows[] = array(
"First Name",
"Last Name"
);
foreach ($results as $row) {
$rows[] = array(
$row->firstName,
$row->lastName
);
}
My Service:
public function getDateRange($results)
{
return $this->getNamesRepository()
->createQueryBuilder('t')
->where('t.created >= :end')
->andWhere('t.id >= :id')
->setParameter('end', new \DateTime('-6 month'))
->setParameter('id', $results)
->orderBy('t.id', 'desc')
->getQuery()
->getArrayResult();
}
If your $results variable is array than it could not work like above,
It would like below,
$qb->add('where', $qb->expr()->in('id', $results));
I have a function. It has method chaining that needs to be performed.
public function someFunction()
{
$query=$this->model;
$query->select($columns)
->skip($request->get('start') * $request->get('length'))
->take($request->get('length'))
->orderBy(
$request->get('sort_column'),
$request->get('sort_direction')
)
->get();
//Some other task
}
It was working fine but I need a slight modification in that function what I want is I want to pass a join in that function for method chaining.
public function someFunction($join_as_parameter)
{
$query=$this->model;
$query->select($columns)
//Join should be executed here as a parameter in method chaning .
->skip($request->get('start') * $request->get('length'))
->take($request->get('length'))
->orderBy(
$request->get('sort_column'),
$request->get('sort_direction')
)
->get();
//Some other task
}
So that final function execution will be like this
public function someFunction($join_as_parameter)
{
$query=$this->model;
$query->select($columns)
->join('table','sometable.id', '=', 'other_table')
->skip($request->get('start') * $request->get('length'))
->take($request->get('length'))
->orderBy(
$request->get('sort_column'),
$request->get('sort_direction')
)
->get();
//Some other task
}
Is there any way to do this? Any help would be appreciated. Thanks.
This way you can achieve what you need.
use DB;
use Closure;
use Illuminate\Database\Query\JoinClause;
public function someFunction(Closure $join_clauser)
{
//create Query Builder object
$query = DB::query();
//Add the `$join` object to the table joins for this query
$join_as_parameter = call_user_func($join_closure, $query);
$query->joins = array_merge((array) $query->joins, [$join_as_parameter]);
$query->select($columns)
->skip($request->get('start') * $request->get('length'))
->take($request->get('length'))
->orderBy(
$request->get('sort_column'),
$request->get('sort_direction')
)
->get();
//Some other task
}
//create Query Builder object
$query = DB::query();
And execute the functions as,
someFunction(function($query){
// return JoinClause object with joining conditions
return (new JoinClause($query, 'inner', 'table'))
->on('table.id', '=', 'othe_table.table_id');
});
Furthermore, you can modify this to pass array of joins to add multiple joins your the query.
To use this with eloquent models, replace
$query = DB::query();
with
$query = Model::query()->getQuery();
NOTE : ->getQuery() is used to retrieve the Query\Builder object since JoinClause expects it as the first param.
I am trying to implement a filtering method for some products.
This is the route:
Route::get('/TVs/{type?}/{producer?}', 'Product\AllProducts#getTVs')->where(['type' => '4kTV|curved|lcd|oled|plasma'], ['producer'=>'Samsung'])->name('TVs');
And this is the controller function:
public function getTVs($type = null, $producer = null)
{
$products = DB::table('products')->paginate(16);
if($type!=null) {
$products = Product::where('type', $type)->paginate(16);
}
if($producer!=null) {
$products = Product::where('description','like', '%'.$producer.'%')->paginate(16);
}
return view('product.TVs', ['products' => $products]);
}
If I select the type, the page refreshes and shows the results. Then if i enter the producer, again it works. How can i make the route in such a way, that the order of the optional parameters does not matter and i can filter the results no matter the order ?
Chain your queries; right now, you're running 3 queries, with ->paginate() being a closure and triggering a DB call. Try this:
$baseQuery = DB::table("products");
if($type){
$baseQuery->where("type", "=", $type);
}
if($producer){
$baseQuery->where("description", "like", "%".$producer."%");
}
$products = $baseQuery->paginate(16);
return view("products.TVs"->with(["products" => $products]);
As you can see, we add ->where clauses as required based on the input, and only run a single ->paginate() right before the return. Not this is additive searching, so it's WHERE ... AND ... and not WHERE ... OR ...; extra logic would be required for that.
How can I rewrite this code in order to get last inserted record from the table?
$repository = $entityManager->getRepository('AdminBundle:MyTable');
$product = $repository->find($id);
I tried something like
$repository->findBy(array('id','DESC')->setMaxResults(1);
But it did not work for me.
You could get the latest record by using findBy() with order by, limit and offset parameters
$results = $repository->findBy(array(),array('id'=>'DESC'),1,0);
First argument is for filter criteria
Second argument takes order by criteria
Third argument is for limit
Fourth argument sets offset
Note it will return you the results set as array of objects so you can get single object from result as $results[0]
FindBy() Examples
Instead of hacking code where you want to use it, you can also create a repository method and call it when necessary.
/**
* Repository method for finding the newest inserted
* entry inside the database. Will return the latest
* entry when one is existent, otherwise will return
* null.
*
* #return MyTable|null
*/
public function findLastInserted()
{
return $this
->createQueryBuilder("e")
->orderBy("id", "DESC")
->setMaxResults(1)
->getQuery()
->getOneOrNullResult();
}
References:
https://symfony.com/doc/current/doctrine.html#querying-for-objects-the-repository
After looking for one I decided to try it myself, I think it was much less verbose:
$myRepository->findOneBy([], ['id' => 'DESC']);
Please try the below one
$repository = $entityManager->getRepository('AdminBundle:MyTable');
$repository->setMaxResults(1)->orderBy('id', 'DESC');
$results = $repository->getQuery()->getSingleResult();
Reference:
https://undebugable.wordpress.com/2016/01/27/symfony2-querybuilder-find-first-and-find-last-record-in-table/
You can add these functions to your repository:
public function getLastRow(): ?YourEntity
{
return $this->findOneBy([], ['id' => 'DESC']);
}
public function getLastId(): int
{
$lastRow = $this->getLastRow();
return $lastRow ? $lastRow->getId() : 0;
}
You can be collected by getting the id of the inserted object
$em->persist($entity);
$em->flush();
$entity->getId();
OR
$entitymanager->getRepository("entity")->findBy([],["id"=>desc])->getId();
I would like create my own method findBy().
I have two entities: Film and Genre. The purpose of this custom findBy() method is :
join the Film entity with the Genre entity, to retrieve all my films
and the associated genres,
keeping the parameters of the basic method which are: $criteria,
$orderBy , $limit and $offset.
Indeed, I use those parameters to make a paging.
Previously I made a custom findAll method with the join between the two entities :
<?php
public function myFindAll()
{
$films = $this->createQueryBuilder('f')
// leftJoin because I need all the genre
->leftJoin('f.genres', 'g')
->addSelect('g.label')
->groupBy('f.id')
->getQuery()
->getArrayResult();
// $genres contains all the genres and the associated movies
return ($films);
}
I don't know how to include the rest of parameters.
How about slice() ?
$genders = $em->getRepository('models\Gender')->findAll()->slice($offset, $lenght);
Also, you can make use of your function like:
public function myFindAll($criteria, $orderBy, $limit, $offset)
{
$films = $this->createQueryBuilder('f')
// leftJoin because I need all the genre
->leftJoin('f.genres', 'g')
->addSelect('g.label')
->groupBy('f.id')
->add('orderBy', "f.{$orderBy} ASC")
->getQuery()
->getArrayResult()
->slice($offset, $limit);
// $films contains all the genres and the associated movies
return ($films);
}
EDIT:
The slice() function acts as pagination function:
$page1 = $films->slice(0, 15); // retrieve films from 0 to 15 position
$page2 = $films->slice(10, 7); // retrieve films from 10 to 17 position
Now, if you want to use some criterias values you can make something like this:
public function myFindAll($criteria, $orderBy, $limit, $offset)
{
$films = $this->createQueryBuilder('f');
foreach($criteria as $column => $value)
$films->where($column, $value);
$films
->leftJoin('f.genres', 'g')
->addSelect('g.label')
->groupBy('f.id')
->add('orderBy', "{$orderBy[0]} {$orderBy[1]}");
->getQuery()
->getArrayResult()
->slice($offset, $limit);
// $genres contains all the genres and the associated movies
return ($films);
}
I am not sure if where function will override the previous conditions, but at least it can lead you to find the correct query
setFirstResult() and setMaxResult()
Also, there is another option that you can use:
public function myFindAll($criteria, $orderBy, $limit, $offset)
{
$films = $this->createQueryBuilder('f');
foreach($criteria as $column => $value)
$films->where($column, $value);
$films
->leftJoin('f.genres', 'g')
->addSelect('g.label')
->groupBy('f.id')
->add('orderBy', "f.{$orderBy[0]} {$orderBy[1]}")
->setFirstResult($offset)
->setMaxResults($limit)
->getQuery()
->getArrayResult();
// $genres contains all the genres and the associated movies
return ($films);
}