Query Builder / DQL not working with INNER JOIN - Syntax Issue - doctrine

I know I have a syntax isse here however I cant figure it out. I'm trying to do a SELECT and INNER JOIN of 5 tables but Symfony is complaining about the Entities in the JOIN are used before being defined.
Actual error is as follows: [Semantical Error] line 0, col 121 near 'I ON C.id = ': Error: Identification Variable MySiteBundle:Items used in join path expression but was not defined before.
Here is the PHP code.
Note: I have shortened this query to two columns, two tables, and one join to keep the question simple and show my point. The actual query is much longer and is producing the same error.
$em = $this->getDoctrine()->getEntityManager();
$query = $em->createQuery(
'select C.name as CName, I.id as IId
FROM MySiteBundle:Categories C
INNER JOIN MySiteBundle:Items I ON C.id = I.category_id');
$result = $query->getResult();
Update
As suggested I've done away with the DQL code and am using Query Builder code. I'm getting a very similiar error which says 'Categories c': Error: Class 'Categories' is not defined. My QB code is below.
$em = $this->getDoctrine()->getEntityManager();
$qb = $em->createQueryBuilder()
->select('c.name, i.id, i.image, i.name, i.description, m.id, m.quantity, m.value, m.qty_received, m.custom_image, m.custom_name, m.custom_description, u.user1fname, u.user1lname, u.user2fname, u.user2lname')
->from('Categories', 'c')
->innerJoin('Items', 'i', 'ON', 'c.id = i.category_id')
->innerJoin('MemberItems', 'm', 'ON', 'i.id = m.item_id')
->innerJoin('User', 'u', 'ON', 'm.memberinfo_id = u.id')
->where('u.id = ?', $slug)
->orderBy('c.id', 'ASC')
->getQuery();
$memberItems = $qb->getResult();
Any suggestions?

Louis posted while I was typing. Oh well.
DQL takes care of the join details for you based on your associations. In general, you only need to spell out the FROM class name. Something like:
'select C.name as CName, I.id as IId
FROM MySiteBundle:Categories C
INNER JOIN C.items');
And definitively use query builder.
=============================================================================
Here is an example of using query builder in Symfony 2.
public function getAccounts($params = array())
{
// Build query
$em = $this->getEntityManager();
$qb = $em->createQueryBuilder();
$qb->addSelect('account');
$qb->addSelect('accountPerson');
$qb->addSelect('person');
$qb->addSelect('registeredPerson');
$qb->addSelect('projectPerson');
$qb->from('ZaysoCoreBundle:Account','account');
$qb->leftJoin('account.accountPersons', 'accountPerson');
$qb->leftJoin('accountPerson.person', 'person');
$qb->leftJoin('person.registeredPersons','registeredPerson');
$qb->leftJoin('person.projects', 'projectPerson');
$qb->leftJoin('projectPerson.project', 'project');
if (isset($params['accountId']))
{
$qb->andWhere($qb->expr()->in('account.id',$params['accountId']));
}
if (isset($params['projectId']))
{
$qb->andWhere($qb->expr()->in('project.id',$params['projectId']));
}
if (isset($params['aysoid']))
{
$qb->andWhere($qb->expr()->eq('registeredPerson.regKey',$qb->expr()->literal($params['aysoid'])));
}
$query = $qb->getQuery();
//die('DQL ' . $query->getSQL());
return $query->getResult();
}

DQL does not use joins like that. They are a bit simplified. However I also found them to be underdocumented.
$em = $this->getDoctrine()->getEntityManager();
$query = $em->createQuery(
'select C.name as CName, I.id as IId
FROM MySiteBundle:Categories C
INNER JOIN C.items I');
$result = $query->getResult();
The actual relation used depends on your model.
I normally use the query builder.
$em = $this->getEntityManager();
$request = $em->getRepository('MySiteBundle:Categories');
$qb = $request->createQueryBuilder('C');
$query = $qb
->select('C.name, I.id')
->innerJoin('C.items', 'I')
->getQuery();

You may have to check your annotations or yml file to make sure you have your mapping setup correctly for OneToMany, ManyToMany, and ManyToOne.
In your MemberItems Controller or MemberItems Repository put this:
$em = $this->getDoctrine()->getEntityManager();
$qb = $em->createQueryBuilder()
->select('c.name, i.id, i.image, i.name, i.description, m.id, m.quantity, m.value, m.qty_received, m.custom_image, m.custom_name, m.custom_description, u.user1fname, u.user1lname, u.user2fname, u.user2lname')
->from('m')
->innerJoin('m.memberinfo_id', 'u')
->innerJoin('m.item_id', 'i')
->innerJoin('i.category_id', 'c')
->where(
->where('u.id = ?', $slug)
->orderBy('c.id', 'ASC')
->getQuery();
$memberItems = $qb->getResult();

Related

how to convert sql to query builder laravel

Can anyone help me out to convert this SQL to query builder!
SELECT topwords.*,
mw.word AS my_word
FROM topwords
LEFT JOIN (SELECT DISTINCT words.word
FROM definition_word
JOIN words
ON words.id = definition_word.word_id
WHERE definition_word.user_id = $user) AS mw
ON topwords.word = mw.word
I have a problem with how to use a subquery in leftjoin!
I tried something like this but it has error!
See error as image
DB::table('topwords')
->leftJoin(DB::raw("SELECT DISTINCT
words.word
FROM definition_word
JOIN words ON words.id = definition_word.word_id
WHERE definition_word.user_id = $user as mw"),"topwords.word", "=", "mw.word" )
->select(
"topwords.*",
"mw.word AS my_word"
)->orderBy('id','desc')->paginate(15);
you can use Join Sub query official document subquery-joins
$mw = DB::table('words')
->select('DISTINCT words.word')
->join('definition_word', function($join) use ($user)
{
$join->on('wordss.id', '=', 'definition_word.word_id')
->where('definition_word.user_id', $user);
});
$topwords = DB::table('topwords')
->joinSub($mw, 'mw',function ($join) {
$join->on('topwords.word', '=', 'mw.word');
})
->select('topwords.*','mw.word AS my_word')
->orderBy('id','desc')
->paginate(15);
You have this error because of paginate and aggregation
Try to make custom pagination, using LengthAwarePaginator
Here is example: Laracast
So you need to make something like this:
$query = DB::table('topwords')
->leftJoin(DB::raw("SELECT DISTINCT
words.word
FROM definition_word
JOIN words ON words.id = definition_word.word_id
WHERE definition_word.user_id = $user as mw"),"topwords.word", "=", "mw.word" )
->select(
"topwords.*",
"mw.word AS my_word"
);
$paginator = new LengthAwarePaginator($query->get(), $query->count(), $request->input('per_page', 15), $request->input('page', 1));
And then you can use it in the collection

AND, OR use In Join query in Codeigniter

How to use Below query in Codeigniter
SELECT * FROM (post) JOIN user ON user.user_id=post.user_id JOIN friend ON (friend.user_id=post.user_id AND friend.friendship_id=1) OR (friend.user_id=1 ANDfriend.friendship_id=post.user_id) WHERE post.type = 'friend' ORDER BY postid desc
You can use this.
$this->db->query(your query);
like this code.
$sql = "SELECT * FROM table WHERE user_id = 1";
$this->db->query($sql);
try this
$query = $this->db
->select('*')
->from('post')
->join('user', 'user.user_id = post.user_id')
->join('friend', 'friend.user_id = (post.user_id AND friend.friendship_id=1) OR (friend.user_id = 1 AND friend.friendship_id = post.user_id)')
->where('post.type', 'friend')
->order_by('postid','DESC')
->get();
$arrResult = $query->result();

ConfigServiceProvider in Laravel 5 doesn't pass the correct values to Controllers/Views

I run a query in the ConfigServiceProvider to set count values that I want to use throughout the application.
public function boot() {
$query = "SELECT count(*) FROM property_in_property_category INNER JOIN property ON property_in_property_category.property_id = property.id INNER JOIN business ON property.business_id = business.id WHERE property_in_property_category.property_category_id = 1 AND property.active = 1 AND business.isActive = 1";
$sale = DB::select($query);
foreach($sale as $object) {
$sale_array[] = (array) $object;
}
$query = "SELECT count(*) FROM property_in_property_category INNER JOIN property ON property_in_property_category.property_id = property.id INNER JOIN business ON property.business_id = business.id WHERE property_in_property_category.property_category_id = 2 AND property.active = 1 AND business.isActive = 1";
$rent = DB::select($query);
foreach($rent as $object) {
$rent_array[] = (array) $object;
}
config([
'for-sale' => $sale_array[0]['count(*)'],
'for-rent' => $rent_array[0]['count(*)']
]);
}
When I run the queries in phpMyAdmin I get the correct values like 413 and 227 back.
But when I call these values in a view using config('for-sale') and config('for-rent'), the values are incorrect, like 446 and 239. This is on a live Linux server. When running on local (Windows) it gives me the correct values.
First I thought this may have to do with casing of names, but as the query runs well in phpMyAdmin and there is no casing in the rest of the code this is not a possibility

Laravel pagination not working with group by clause

It seems Laravel pagination does not working properly with group by clause. For example:
$users = Subject::select(DB::raw('subjects.*, count(user_subjects.id) as total_users'))
->join('user_subjects', 'user_subjects.subject_id', '=', 'subjects.id')
->whereNull('user_subjects.deleted_at')
->groupBy('subjects.id')
->orderBy('subjects.updated_at', 'desc')
->paginate(25);
Produced
select subjects.*, count(user_subjects.id) as total_users
from `subjects` inner join `user_subjects` on `user_subjects`.`subject_id` = `subjects`.`id`
where `subjects`.`deleted_at` is null and `user_subjects`.`deleted_at` is null
group by `subjects`.`id`
order by `subjects`.`updated_at` desc
note that, there is no limit clause on the query.
Working fine if no group by clause in the query:
$users = Subject::select(DB::raw('subjects.*, count(user_subjects.id) as total_users'))
->join('user_subjects', 'user_subjects.subject_id', '=', 'subjects.id')
->whereNull('user_subjects.deleted_at')
->orderBy('subjects.updated_at', 'desc')
->paginate(25);
produced the following query:
select subjects.*, count(user_subjects.id) as total_users from `subjects`
inner join `user_subjects` on `user_subjects`.`subject_id` = `subjects`.`id`
where `subjects`.`deleted_at` is null and `user_subjects`.`deleted_at` is null
order by `subjects`.`updated_at` desc
limit 25 offset 0
does anyone has any idea how can i fix this?
Check the documentation
https://laravel.com/docs/5.2/pagination
Currently, pagination operations that use a groupBy statement cannot
be executed efficiently by Laravel. If you need to use a groupBy with
a paginated result set, it is recommended that you query the database
and create a paginator manually.
I know it is an old question, by I am sharing my solution for future reference.
I managed to write a function based on this link which does the heavy job of determining the pagination of a complex query. Just pass the 'QueryBuilder' and it will return the paginated object/collection.
Additionally, this procedure can track and maintain the other parameters except for page=.
public function mergeQueryPaginate(\Illuminate\Database\Eloquent\Builder $query): \Illuminate\Pagination\LengthAwarePaginator
{
$raw_query = $query;
$totalCount = $raw_query->get()->count();
$perPage = request('per-page', 10);
$page = request('page', 1);
$skip = $perPage * ($page - 1);
$raw_query = $raw_query->take($perPage)->skip($skip);
$parameters = request()->getQueryString();
$parameters = preg_replace('/&page(=[^&]*)?|^page(=[^&]*)?&?/', '', $parameters);
$path = url(request()->getPathInfo() . '?' . $parameters);
$rows = $raw_query->get();
$paginator = new LengthAwarePaginator($rows, $totalCount, $perPage, $page);
$paginator = $paginator->withPath($path);
return $paginator;
}
This works for me in laravel 5.2
Select(\DB::RAW("assignment_descendant_child.assignment_descendant_child_id, assignment_descendant_child.assignment_descendant_child_name, COUNT(assignment_descendant.assignment_descendant_id) as xNum"))
->leftJoin(
'assignment_descendant',
'assignment_descendant.assignment_descendant_child_id',
'=',
'assignment_descendant_child.assignment_descendant_child_id'
)
->orderBy('assignment_descendant_child_name')
->groupBy('assignment_descendant_child.assignment_descendant_child_id')
->paginate(\Config::get('constants.paginate_org_index'))
create a database view namedvw_anything. MySql query will be like
create view vw_anything as select subjects.*, count(user_subjects.id) as total_users from subjects inner join user_subjects on user_subjects.subject_id = subjects.id
where subjects.deleted_at is null and user_subjects.deleted_at is null group by subjects.id;
Now create a new model named UserSubModel for this view, protected $table = 'vw_anything';
Now your paginate query will be like UserSubModel::orderBy('subjects.updated_at', 'desc')->paginate(25);
.
To answer this questioin Laravel Pagination group by year and month only
View query will be :
create view vw_anything as select gallery.*, DATE_FORMAT(created_at, "%Y-%m") as tanggal,count(created_at) as jumlah from gallery group by tanggal;
Let you model is VwModel then your paginate query will be
VwModel::where('type','Foto')->orderBy('tanggal','desc')->paginate(2);
This works if you want to group by and paginate.
$code = DB::table('sources')
->select(DB::raw('sources.id_code,sources.title,avg(point) point'))
->join('rating','sources.id_code','rating.id_code')
->groupBy('sources.id_code')
->groupBy('sources.title')
->groupBy('sources.language')
->groupBy('sources.visited')
->paginate(5);

doctrine 2 querybuilder with set parameters not working

this is my query:
public function getDetails($userid, $orderby, $sort){
$query = $this->_em->createQueryBuilder()
->select('u')
->from('\Entities\Users', 'u')
->where('u.userid= ?1')
->orderBy('u.?3', '?3')
->setParameter(1, $userid)
->setParameter(2, $orderby)
->setParameter(3, $sort)
->getQuery()
->getResult();
}
it keeps erroring: Message: [Semantical Error] line 0, col 83 near '?3 DESC': Error: '?3' is not defined.
how do i get the orderby from the properties in that function to the query?
You can't use placeholders for dinamical build of DQL query. You'll have to code it by your own:
$sortBy = in_array($sortBy, array(...)) ? $sortBy : 'id';
$sortDir = $sortDir == 'ASC' ? 'ASC' : 'DESC';
$this->em->createQueryBuilder()
...
->orderBy('u.' . $sortBy, $sortDir)
You cant bind parameters to QueryBuilder, only to Query, so just swap lines, first get query out of builder, then fill it with parameters and get result.
$query = $this->_em->createQueryBuilder()
->select('u')
->from('\Entities\Users', 'u')
->where('u.userid= ?1')
->orderBy('u.?3', '?3')
->orderBy('u.'.$orderBy, $sort)
->getQuery()
->setParameter(1, $userid)
->getResult();
}
In doctrine 2.4 its fixed, and you can bind parameters to QueryBuilder.
Update: i've missed moment with placeholder in field name, SQL do not support such constructions.

Resources