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));
Related
I have this method in my PhotoalbumsModel
public function index_list()
{
$data = $this->find()
->contain(['Images' => function($q) {
$q->select([
'total' => $q->func()->count('image_id')
])
->group(['photoalbum_id']);
return $q;
}
]);
foreach ($data as $row)
{
$row->image_count = 0;
if (isset($row->images{0}->total))
{
$row->image_count = $row->images{0}->total;
}
unset($row->images);
}
return $data;
}
Which basicaly adds image_count to the rows.
In my controller I use:
<?php
class PhotoalbumsController extends AppController
{
public $paginate = [
'limit' => 2,
'order' => ['id' => 'desc']
];
public function index()
{
$photoalbums = $this->paginate($this->Photoalbums->index_list());
$this->set(compact('photoalbums'));
}
However, in my view image_count isn't passed. Without using the Paginator it is passed.
How can I fix this?
The paginator applies options to the query, such as the limit, which will cause the query to be marked as dirty, which in turn clears any possibly buffered resultsets, so what you are doing there is iterating over a to be dropped result set, and modifying objects (entities) that will descend into nowhere.
You shouldn't rely on buffered result sets at all, if you need to reliably modify the results of a query, then you should use a result formatter or map/reduce, which is both applied on the results everytime the query is being executed:
$query = $this
->find()
->contain([
'Images' => function($q) {
$q
->select([
'total' => $q->func()->count('image_id')
])
->group(['photoalbum_id']);
return $q;
}
])
->formatResults(function (\Cake\Collection\CollectionInterface $results) {
return $results->map(function ($row) {
$row['image_count'] = $row['images'][0]['total'];
return $row;
});
});
return $query;
That being said, you could also handle this directly on SQL level by joining the association instead of containing it, and selecting the column in the main query:
$query = $this->find();
$query
->select(['image_count' => $query->func()->count('Images.id')])
->enableAutoFields()
->leftJoinWith('Images')
->group('Photoalbums.id');
And there's of course also the counter cache behavior.
See also
Cookbook > Database Access & ORM > Query Builder > Adding Calculated Fields
Cookbook > Database Access & ORM > Retrieving Data & Results Sets > Modifying Results with Map/Reduce
Cookbook > Database Access & ORM > Query Builder > Using leftJoinWith
Cookbook > Database Access & ORM > Behaviors > CounterCache
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.
I am trying to loop in an array but when it comes to the query it gets only the first element, so a little help would be very important.
$data = Offers::whereIn('id_business', $business_id_array)
->where([
'visible' => 'yes',
'delete' => 'no'
])
->where('end_date', '>=', date('Y-m-d h:m:i'))
->orderBy('id', 'desc')
->get();
$data=array($data);
foreach($data as $key => $item) {
$offers = DB::select('the data i need to get WHERE o.`id` = ' . $item[$key]['id']);
}
and this is my problem in here, It gets only the id of the first element
o.`id` = ' . $item[$key]['id']
because you have return the view in side the foreach loop, so it only loop through the first item and return. What you can do with this case is
$data = Offers::whereIn('id_business', $business_id_array)...->get()->toArray();
$offers = array_map(function($item){
$offer = DB::select('the data i need to get WHERE o.`id` = ?', [$item->id]);
return $offer;
},$data);
return view(....,['offers' =>$offers]);
First, you do not need to cast the $data to an array - it will get returned as a collection, which you can iterate through like an array. So you'll be able to use something like this
$offers = Offers::whereIn('id_business', $business_id_array)...->get();
foreach ($offers as $offer) {
$moreData = DB::select('the data i need to get WHERE o.`id` = ?', [$offer->id]);
}
This looks like you are using the id from one table, to get the associated data from another table.
Should there not be a relationship in place, between the two tables?
The answer from #Chris G looks correct, maybe dd($offers) to be certain what is in there.
Mick
I have two queries running in my controller. I need a value from the first query to be passed into the second. I want the result of both these queries sent to my view.
public function jobs()
{
$query = DB::table("dbQuotes")
->leftJoin("dbACT", "dbQuotes.act_id", "=", "dbACT.ID")
->leftJoin("dbOpps", "dbQuotes.act_id", "=", "dbOpps.contactID")
->leftjoin('dbBids', 'dbQuotes.act_id','=',
DB::raw('dbBids.quote_id AND dbBids.user_id = '. Auth::user()->id))
->where("dbQuotes.active", "=", "1")
->select("dbQuotes.*", "dbACT.*", "dbBids.*",
(DB::raw('date_format(dbQuotes.posted_date, "%d/%m/%Y %H:%i") as posted_date')),
(DB::raw('date_format(dbOpps.expected_date, "%d/%m/%Y") as expected_date')))
->groupBy("dbQuotes.id")
->orderBy("posted_date", "desc")
->get();
$passinvaluehere = $query->dbQuotes.act_id
$bids = DB::table("dbBids")
->where("quote_id", "=", $passinvaluehere)
->get();
return view('jobs', ['query' => $query,'bids' => $bids]);
}
My query works and the view is established in the correct way if I replace the passed value with a number, i.e "8763". My question is how, within this function, can I pass the value/s of dbQuotes.act_id into this second query?
***UPDATED Code from answer: [error Call to a member function lists() on a non-object]
public function jobs()
{
$query = DB::table("dbQuotes")
->leftJoin("dbACT", "dbQuotes.act_id", "=", "dbACT.ID")
->leftJoin("dbOpps", "dbQuotes.act_id", "=", "dbOpps.contactID")
->leftJoin('dbBids', 'dbQuotes.act_id','=',
DB::raw('dbBids.quote_id AND dbBids.user_id = '. Auth::user()->id))
->where("dbQuotes.active", "=", "1")
->select("dbQuotes.*", "dbACT.*", "dbBids.*",
(DB::raw('date_format(dbQuotes.posted_date, "%d/%m/%Y %H:%i") as posted_date')),
(DB::raw('date_format(dbOpps.expected_date, "%d/%m/%Y") as expected_date')))
->groupBy("dbQuotes.id")
->orderBy("posted_date", "desc")
->get();
$act_id = $query->lists('act_id');
$bids = DB::table("dbBids")
->whereIn("quote_id", $act_id)
->get();
return view('jobs', ['query' => $query,'bids' => $bids]);
}
If you have multiple records (as per the ->get() method) you have two ways: either you loop over the Collection and make a query each iteration (bad) or you create an array of ids and use a whereIn in the second query (better):
$passinvaluehere = $query->lists('act_id');
// https://laravel.com/docs/5.2/queries#retrieving-results
// this creates and array of `act_id` s
$bids = DB::table("dbBids")
->whereIn("quote_id", $passinvaluehere)
->get();
// you now have a Collection of multiple $bids
If you expect only a single records from your first query, you need to change the fetcher method, using first() instead, or else take only the first element of your actual collection, something like first($query) or $query[0]
$query = DB::table("dbQuotes")
....
->first();
$passedvaluehere = $query->act_id;
I am having problem in getting data from doctrine object. When I use findOne(id) and try to access any variable like $result->getVariable() it works fine. But as soon as I use doctrine query builder and add some conditions, it says
Attempted to call method "getVariable" on class "Doctrine\ORM\QueryBuilder....
My Code is
foreach ($Ids as $Id) {
$result = $em->createQueryBuilder()->select("s")
->from("Entity", "s")
->where('s.id = :s_id')
->setParameters(array('s_id'=>$Id));
if($category)
{
$result->innerJoin('s.cat','c');
$result->where("c.primaryClassification = :category");
result->setParameter('category',$category);
}
}
The Code which is working is
foreach ($Ids as $Id) {
$em->getRepository("Entity")->findOneById($Id);
}
I think it is the difference in data returned because of different types of methods used.
Thanks in advance!
That's because the QueryBuilder is only for that, to build querys (BA-DUM-TSS).
What you need is to execute the query after you build it and set the parameter correctly for a =:
foreach ($Ids as $Id) {
$query[] = $em->createQueryBuilder()->select("s")
->from("Entity", "s")
->where('s.id = :s_id')
->setParameter('s_id', $Id))
->getQuery()
->getResult();
}
also if you are looking for an array of data, is BEST if you use the IN statement without the foreach and pass the array directly to the setParameter:
$result = $em->createQueryBuilder()->select("s")
->from("Entity", "s")
->where('s.id IN (:s_id)')
->setParameter('s_id', $Ids)
->getQuery
->getResult();
If you need more info on the query builder check the docs.