im looking for way, how to convert query builder result into associative array. But what I need is including relation data from another table.
If I use getArrayResult() method, it gives me an array, but without foreign keys. And I need foreign keys included with nested array with data of associative db table.
EDIT:
Here is my code:
$qb = $this->_em->createQueryBuilder();
$qb->select('p');
$qb->from('XXX\MyBundle\Entity\Entity1', 'p');
$qb->leftJoin('p.FK1','u');
$qb->andWhere('u.Attr1 = :attr1');
$qb->setParameter('attr1', $appId);
$qb->andWhere('u.Attr2 IS NULL');
$qb->leftJoin('u.FK2', 'v');
$qb->andWhere('v.Attr3 = :attr3');
$qb->andWhere('v.Attr4 IS NULL');
$qb->setParameter('attr3', $userId);
$result = $qb->getQuery()->getArrayResult();
I need this conversion becouse of SOAP. It could not return complex object as nested objects of entities.
First, you need to write this function in your Entity1Repository.php
Since you're using the createQueryBuilder() method, you don't need to use select and from methods.
In your example, you're writing the joins, but you're not asking the query to return those joins.
Try this code :
<?php
namespace XXX\\MyBundle\Entity;
use Doctrine\ORM\EntityRepository;
class Entity1Repository extends EntityRepository
{
public function getEntityWithJoins()
{
return $this
->createQueryBuilder('p')
->addSelect('u')
->addSelect('v')
->leftJoin('p.FK1','u')
->andWhere('u.Attr1 = :attr1')
->setParameter('attr1', $appId)
->andWhere('u.Attr2 IS NULL')
->leftJoin('u.FK2', 'v')
->andWhere('v.Attr3 = :attr3')
->andWhere('v.Attr4 IS NULL')
->setParameter('attr3', $userId);
->getQuery()
->getArrayResult();
}
}
Related
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 have a table called List which i planned to be displayed into view with this command : $lists= List::with('user', 'product.photodb', 'tagCloud.tagDetail')->get();. But, i want the data displayed is only those that has TagID equal to the one user inputted. Those data can be retrieved from TagCloud table.
What i am currently doing is :
$clouds = TagCloud::select('contentID')
->where('tagDetailID', '=', $tagID)
->get();
$lists = List::with('user', 'product.photodb', 'tagCloud.tagDetail')
->where('id', '=', $clouds->contentID)
->get();
But when i tried to run it, it only return a null value, even though when i am doing return $clouds, it does returned the desired ID.
Where did i do wrong ? Any help is appreciated !
A couple of gotchas with your current solution.
Using get() returns an Illuminate\Database\Eloquent\Collection object. Hence you can't use $clouds->contentID directly since $clouds is a collection (or array if you prefer). See Collection Documentation.
where(...) expects the third parameter to be a string or integer, aka single value. Instead, you are passing a collection, which won't work.
The correct way is to use whereHas() which allows you to filter through an eager loaded relationship.
Final Code:
$lists = List::with('user', 'product.photodb', 'tagCloud.tagDetail')
->whereHas('tagCloud',function($query) use ($tagID) {
return $query->where('contentID','=',$tagID);
})
->get();
See WhereHas Documentation.
What you want is whereHas()
$list = List::with(...)
->whereHas('relation', function($q) use($id) {
return $q->where('id', $id);
})->get();
Apply Where condition in you tagCloud model method tagDetail
public function tagDetail(){
return $q->where('id', $id);
}
I'm building a very simple web app with Laravel.
I've built two separate Controllers, which each return two separate views, as follows:
ProfileController:
class ProfileController extends BaseController {
public function user($name)
{
$user = User::where('name', '=', $name);
if ($user->count())
{
$user = $user->first();
$workout = DB::table('workouts')->where('user_id', '=', $user->id)->get();
Return View::make('profile')
->with('user', $user)
->with('workout', $workout);
}
return App::abort(404);
}
}
WorkoutController:
class WorkoutController extends BaseController {
public function workout($name)
{
$workout = DB::table('workouts')->where('name', '=', $name)->first();
if ($workout)
{
Return View::make('add-exercise')
->with('workout', $workout);
}
return App::abort(404);
}
}
What is confusing me is what I had to do in order to pass a single workout object to each view. As you might have noticed the query builders for workout are different:
$workout = DB::table('workouts')->where('user_id', '=', $user->id)->get();
and
$workout = DB::table('workouts')->where('name', '=', $name)->first();
On the profile view, I get an object using the ->get(); method, but on the add-exercise view, I must use ->first(); or I will otherwise get an array with only one index, where I can then access the object, i.e. $workout[0]->name instead of $workout->name.
Why is this? Shouldn't I be able to use either get and/or first in both controllers and expect the same type of result from both since I want the same thing from the same table?
get() returns a collection of objects every time. That collection may have 0 or more objects in it, depending on the results of the query.
first() calls get() under the hood, but instead of returning the collection of results, it returns the first entry in the collection (if there is one).
Which method you use depends on what you need. Do you need the collection of all the results (use get()), or do you just want the first result in the collection (use first())?
Model::find(numeric); returns a object
Model::whereId(numeric)->first(); returns a object
Model::whereId(numeric)->get(); - returns a collection
Model::whereId(numeric); - returns a builder
How to merge this two queries ?
$data = DB::table('category_to_news')
->where('category_to_news.name', ucwords($category))
->remember(1440)
->count();
and
$data = DB::table('category_to_news')
->where('category_to_news.name', ucwords($category))
->remember(1440)
->get();
So, as far as I understand from your comment, you simply want to get all records from the table category_to_news and you want to know how many records are in there, right?
MySQL's count is an aggregate functions, which means: It takes a set of values, performs a calculation and returns a single value. If you put it into your names-query, you get the same value in each record. I'm not sure if that has anything to do with 'optimization'.
As already said, you simply run your query as usual:
$data = DB::table('category_to_news')
->where('name', ucwords($category))
->remember(1440)
->get(['title']);
$data is now of type Illuminate\Support\Collection which provides handy functions for collections, and one them is count() (not to be confused with the above mentioned aggregate function - you're back in PHP again, not MySQL).
So $data->count() gives you the number of items in the collection (which pretty much is an array on steroids) without even hitting the database.
Hi DB class dont return collection object it give error "call member function on array" but eloquent return collection object. for above code we can use collect helper function to make it collection instance then use count and other collection methods https://laravel.com/docs/5.1/collections#available-methods .
$data = DB::table('category_to_news')
->where('name', ucwords($category))
->remember(1440)
->get();
$data = collect($data);
$data->count();
You my get it using:
$data = DB::table('category_to_news')
->where('name', ucwords($category))
->remember(1440)
->get();
To get the count, try this:
$data->count();
Why you are using DB::table(...), instead you may use Eloquent model like this, create the model in your models directory:
class CategoryToNews extends Eloquent {
protected $table = 'category_to_news';
protected $primaryKey = 'id'; // if different than id then change it here
}
Now, you may easily use:
$data = CategoryToNews::whereName(ucwords($category))->get();
To get the count, use:
$data->count();
I am able to fetch my data from database by using this structure:
$user = $this->getDoctrine()
->getRepository('AcmeDemoBundle:Emails')
->find(8081);
When I do that, I am able to get my data like this:
$user->getColumnNameHere();
Basically I am able to use Entity Class.
But if I want to use QueryBuilder instead of find I am only getting associative arrays.
$product->createQueryBuilder('p')
->setMaxResults(1)
->where('p.idx = :idx')
->select('p.columnNameHere')
->setParameter('idx', 8081)
->orderBy('p.idx', 'DESC')
->getQuery();
$product = $query->getResult();
$product returnds as array. Is it possible to fetch it withj Entity Managaer Class? If yes, how?
I digg the documentation but it seems not possible or not exist in the doc or I'm just blind :)
Yes you can, usually using:
$repository
->createQueryBuilder('p')
->getQuery()
->execute()
;
This should return you an array of entities.
If you want to get a single entity result, use either getSingleResult or getOneOrNullResult:
$repository
->createQueryBuilder('p')
->getQuery()
->getOneOrNullResult()
;
Warning: These method can potentially throw NonUniqueResultException.
Edit: Ok, so the question was about partial objects: http://docs.doctrine-project.org/en/latest/reference/partial-objects.html
you can get an object instead of array by using "Partial Objects".
here is a tested example with DoctrineORM 2.2.2:
// create query builder
// $em is the EntityManager
$qb = $em->createQueryBuilder();
// specify the fields to fetch (unselected fields will have a null value)
$qb->select ('partial p.{id,pubDate,title,summary}')
->from ('Project\Entity\Post', 'p')
->where ('p.isActive = 1')
->orderBy ('p.pubDate', 'desc');
$q = $qb->getQuery();
$result = $q->getResult();
var_dump($result); // => object
If you wish to return an object from your original query:
$product->createQueryBuilder('p')
->setMaxResults(1)
->where('p.idx = :idx')
->select('p.columnNameHere')
->setParameter('idx', 8081)
->orderBy('p.idx', 'DESC')
->getQuery();
$product = $query->getResult();
Remove this line
->select('p.columnNameHere')
As soon as you use select, it will return an array...
getResult() method returns a collection (an array) of entities. Use getSingleResult() if you're going to fetch only one object.
EDIT:
Oh, I just noticed that you want to fetch a single field of a single object. Use getSingleScalarResult() as #Florian suggests.