I need help to turn some raw SQL into Eloquent code - php

As the title says, I'm having trouble turning my SQL code into Eloquent.
Here's the raw SQL:
select * from `students`
where (
select status_student.id from `status_student`
WHERE
status_student.id = (SELECT MAX(status_student.id) from `status_student`
WHERE
status_student.student_id = students.id)
AND
status_student.status_id = 6
)
IS NOT NULL;
and here's the code so far:
$status = $this->request->get('status');
if ($status !== "0") {
dd($query = Student::where(function($q) use($status){
$q->where('status_student.id', function($q2) use ($status) {
$q2->selectRaw('MAX(status_student.id)')
->where('status_student.student_id', '=', 'students.id')
->where('status_student.status_id', '=', $status);
});
})->toSql());
}
which translates into SQL:
"select * from `students` where (`status_student`.`id` = (select MAX(status_student.id) where `status_student`.`student_id` = ? and `status_student`.`status_id` = ?))
so it's not working properly yet.
I'm having trouble introducing that IS NOT NULL clause and doing
select status_student.id from 'status_student'
instead of just
status_student.id =
How should I modify my code to get the desired SQL?
Thanks.

$status = request()->get('status');
if ($status !== "0") {
dd($query = Student::where(function($q) use($status){
$q->where([['status_student.id' => function($q2) use ($status) {
$q2->selectRaw('MAX(status_student.id)')
->where('status_student.student_id', '=', 'students.id')
->where('status_student.status_id', '=', $status);
}],
['status_student.id', '<>', null]
]);
})->toSql());
}
Generated SQL query:
SELECT *
FROM `students`
WHERE (((`status_student`.`student_id` = ?
AND `status_student`.`status_id` IS NULL)
AND `status_student`.`id` IS NOT NULL))
Not sure if I understanded you correctly but I assume you just didn't get the syntax right

try this one:
$status = $this->request->get('status');
if ($status !== "0") {
// log the queries:
\DB::enableQueryLog();
$query = Student::with([
'statusStudent' => function($q1) use($status) {
$q1->where('status_student.id', function($q2) use ($status) {
$q2->selectRaw('MAX(status_student.id)')
->where('status_student.student_id', '=', 'students.id')
->where('status_student.status_id', '=', $status);
});
}
])
->get();
$pureQuery = \DB::getQueryLog();
dd($pureQuery);
}
If you would like to join in eloquent, you must use with() or load() to do that.

Related

Sympfony Request (AndWhere, OrWhere) with conditions

I have 2 DQL queries
I want the user (with a select form) to be able to select:
1 filter at a time. Either party or city
or
several filters at the same time: party + city ... then others afterwards.
In summary :
In my database there are Party and City. With a form of select. The user must be able to choose the filters he wants. If he chose a particular Party without specifying the city, this will display all the Party in all the City. He can also choose a city, in which case he will have all the party of the chosen city. or 3rd case, he chose an Party + a City.
When one works the other is not.
I think I have a problem with my conditions and operators.
I read that using the orWhere () was bad practice.
Thanking you in advance.
public function searchByParty($party, $city)
{
$query = $this->createQueryBuilder('s');
$query = $query
->select( 'party', 'city', 's')
->join ('s.party', 'party ')
->join ('s.city', 'city');
if (!empty($party) === !empty($city)) {
$query = $query
->andWhere('party .id = :sport')
->andWhere('city.id = :city')
->setParameter('party ', $party )
->setParameter('city', $city);
}
if (!empty($party) && !empty($city)) {
$query = $query
->orWhere('party.id = :party')
->orWhere('city.id = :city')
->setParameter('party', $party )
->setParameter('city', $city);
}
return $query->getQuery()->getResult();
You have a logical issue. Your first if checks whether the existence of $party and $city is equivalent, which is true if and only if both exists or both does not exist. It does not make sense to check for their value if they both do not exist. The second if checks whether neither is defined. In that case it does not make sense to check the value against them. Fix:
public function searchByParty($party, $city) {
$query = $this->createQueryBuilder('s');
$query = $query
->select( 'party', 'city', 's')
->join ('s.party', 'party ')
->join ('s.city', 'city');
if (!empty($party)) {
$query = $query
->andWhere('party .id = :sport')
->setParameter('party ', $party )
}
if (!empty($city)) {
$query = $query
->andWhere('city.id = :city')
->setParameter('city', $city);
}
return $query->getQuery()->getResult();
}
EDIT: if you want to check whether any of them matches, then use orWhere:
public function searchByParty($party, $city) {
$query = $this->createQueryBuilder('s');
$query = $query
->select( 'party', 'city', 's')
->join ('s.party', 'party ')
->join ('s.city', 'city');
if (!empty($party)) {
$query = $query
->orWhere('party .id = :sport')
->setParameter('party ', $party )
}
if (!empty($city)) {
$query = $query
->orWhere('city.id = :city')
->setParameter('city', $city);
}
return $query->getQuery()->getResult();
}
Solution :
public function searchBySession($party, $city)
{
$query = $this->createQueryBuilder('s');
$query = $query
->select( 's');
if($party){
$query = $query
->join ('s.party', 'party')
->addSelect('party')
->andWhere('party.id = :party')
->setParameter('party', $party)
;
}
if($city){
$query = $query
->join ('s.city', 'city')
->addSelect('city')
->andWhere('city.id = :city')
->setParameter('city', $city)
;
}
return $query->getQuery()->getResult();
}
Thanks you

How to add an extra row to each object returned from a Laravel database call?

I am new to PHP and new to Laravel. I'm taking over an old project.
We had this code and it was working fine:
public function getList(Request $request)
{
$apiFormat = array();
try
{
$perPage = Input::get('page_size', 10);
$filters = $request->input();
$postRepo = new PostRepo();
$user = $_SESSION["user"];
$listPost = $postRepo->getlist($user->id, $perPage, 0);
$apiFormat['status'] =\Config::get('constants.api.STATUS_OK');
$apiFormat['message'] = \Config::get('constants.api.SUCCESS');
$apiFormat['data'] = $listPost;
} catch (\Exception $ex) {
$apiFormat['status'] =
\Config::get('constants.api.STATUS_ERROR');
$apiFormat['message'] = $ex->getMessage();
}
return response()->json($apiFormat);
}
This returned 10 items that would show up on our newsfeed.
This line:
$listPost = $postRepo->getlist($user->id, $perPage, 0);
Did a database call like this:
$sqlCheckHasLike = "SELECT count(*) > 0 FROM `likes` WHERE `post_id` = `posts`.`id` and `user_id` = '".$user_id."'";
$query = DB::table('posts')
->select('posts.*',DB::raw("($sqlCheckHasLike) as is_like"), 'users.full_name', 'users.avatar', DB::raw("post_categories.name as post_categories_name"))
->leftJoin('users', 'posts.user_id', '=', 'users.id')
->leftJoin('post_categories', 'post_categories.id', '=', 'posts.post_category_id')
->where('posts.status',$post_status)
->where('users.status', 1)
->where(function ($query) use ($user_id, $list_user) {
$query->whereIn('user_id', $list_user)
->orwhere('user_id', $user_id);
})
->orderBy('created_at', 'desc')->paginate($pageSize);
return $query;
However, we've just added comments to each item in the newsfeed. That code is handled elsewhere, but here I want to find, given a post.id, how many comments belong to it? This needs to be included in the response.
Replacing the first method, I tried this:
try {
$perPage = Input::get('page_size', 10);
$filters = $request->input();
$postRepo = new PostRepo();
$user = $_SESSION["user"];
$listPost = $postRepo->getlist($user->id, $perPage, 0);
$array_of_rows = [];
foreach ($listPost as $lp) {
$row_as_array = (array) $lp;
$post_id = $lp->id;
$query = "select count(id) as how_many from comments where
post_id = '". $post_id ."'";
$result_array = DB::select($query);
$result_obj = $result_array[0];
$how_many = $result_obj->how_many;
$row_as_array['how_many_comments'] = $how_many;
$array_of_rows[] = $row_as_array;
}
$merged_list_post = (object) $array_of_rows;
file_put_contents("/var/log/api_debugging", "\ncomment count:\n",
FILE_APPEND | LOCK_EX);
file_put_contents("/var/log/api_debugging",
print_r($merged_list_post, true), FILE_APPEND | LOCK_EX);
$apiFormat['status'] = \Config::get('constants.api.STATUS_OK');
$apiFormat['message'] = \Config::get('constants.api.SUCCESS');
$apiFormat['data'] = $merged_list_post;
} catch (\Exception $ex) {
$apiFormat['status']=\Config::get('constants.api.STATUS_ERROR');
$apiFormat['message'] = $ex->getMessage();
}
This does not throw an error (there are no Exceptions) but it changed the returned data, such that the apps which consume this feed no longer get what they need.
Is there an official approach in Laravel that makes it easy to do several database queries, and combine that data at a per inner object level? I'd like to avoid returning an object that is of a different type than the one in the original example.
You could just modify the original query (I've just included the first few lines here) to JOIN the comments table and get the count:
$query = DB::table('posts')
->select('posts.*',DB::raw("($sqlCheckHasLike) as is_like"), 'users.full_name', 'users.avatar', DB::raw("post_categories.name as post_categories_name"), DB::raw("count(comments.id) as how_many"))
->leftJoin('users', 'posts.user_id', '=', 'users.id')
->leftJoin('post_categories', 'post_categories.id', '=', 'posts.post_category_id')
->leftJoin('comments', 'comments.post_id', '=', 'posts.id')
You will also need to add a groupBy clause:
->groupBy('posts.id')
prior to the orderBy.

SQL: Query returns 1 using count

I have a query in PHP(MySQL). I am fetching records from a table and returning them to a datatable.
The problem is it always returns 1 when I use count() with the query.
However, if I count the elements of the array, then the result is as expected. It returns all 8 records.
Following is my code:
public function job_order_detail_del($arr=array()) {
$count = 0;
$start = isset($arr['start'])?$arr['start']:0;
$length = isset($arr['length'])?$arr['length']:0;
$search = isset($arr['search'])?$arr['search']:'';
$orderBy = isset($arr['orderBy'])?$arr['orderBy']:'';
$orderDir = isset($arr['orderDir'])?$arr['orderDir']:'';
$aufnr = isset($arr['aufnr'])?$arr['aufnr']:0;
$aufpl = isset($arr['aufpl'])?$arr['aufpl']:0;
$type = isset($arr['type'])?$arr['type']:'';
$whr = array('h.stats' => '', 'h.bukrs' => Session::get('company'), 'h.delstats' => '');
if ($aufnr > 0)
$whr['a.aufnr'] = $aufnr;
if ($aufpl > 0)
$whr['a.aufpl'] = $aufpl;
$a = DB::table('zpp_afpo_h as h')
->leftjoin('zpp_afpo as a ', function($join) {
$join->on('a.aufnr', '=', 'h.aufnr')
->where('a.bukrs', '=', Session::get('company'))
->where('a.stats', '=', '');
})
->leftjoin('zpp_afvc as b ', function($join) {
$join->on('a.aufnr', '=', 'b.aufnr')
->on('a.aufpl', '=', 'b.aufpl')
->where('b.bukrs', '=', Session::get('company'))
->where('b.stats', '=', '');
})
->leftjoin('zpp_afru as c ', function($join) use($type) {
$join->on('c.aufnr', '=', 'b.aufnr')
->on('c.rueck', '=', 'b.rueck');
})
->where('c.type', '=', $type)
->where('c.bukrs', '=', Session::get('company'))
->where('c.stats', '=', '')
->where('c.delstats', '=', '')
->select('h.idat2', 'a.matnr', 'b.arbpl', 'a.gamng as total', 'b.rueck', 'h.priority', 'b.vornr', 'b.prev_startper', 'b.scrap', 'h.dispatch_date', 'h.order_start_dt', 'h.requirement_dt', 'h.ktxt', 'c.rmzhl', 'c.budat', 'c.aufnr', 'c.rework_lmnga', DB::raw('sum(c.lmnga) as sum_cnfrm'));
if ($aufnr == '') {
$a->where('h.idat2', '=', '0000:00:00');
}
$a->where($whr)
->groupby('b.rueck')
->groupby('c.rmzhl')
->groupby('c.counter');
if($orderBy!=''){
$a->orderBy($orderBy,$orderDir);
}
if($search!=''){
$dt_srch = implode('-',array_reverse(explode('-',$search)));
$a->where(function($query) use ($search,$dt_srch){
$query->where('c.aufnr','LIKE','%'.$search.'%')
->orWhere('a.matnr','LIKE','%'.$search.'%')
->orWhere('c.budat','LIKE','%'.$dt_srch.'%')
->orWhere('b.arbpl','LIKE','%'.$search.'%')
->orWhere('a.gamng','LIKE','%'.$search.'%');
});
}
if($length>0){
$get_rec = $a->skip($start)->take($length)->get();
}else{
$get_rec = $a->get();
$count = count($get_rec);
// $count = $a->count(); //Problem is here
return $count;
}
$arr = array();
foreach($get_rec as $l){
if($length>0 || Input::get('open') == 1 || Input::get('open') == 2){
$arr = DB::table('maras')
->where('matnr','=',$l->matnr)
->where('bukrs','=',Session::get('company'))
->where('stats','=','')
->where('delstats','=','')
->select(DB::raw('GROUP_CONCAT(distinct(matnr)) as mat'),DB::raw('GROUP_CONCAT(distinct(mdesc)) as mat_desc'))
->groupby('matnr')
->first();
$l->matnr = $arr->mat;
$l->mat_desc = $arr->mat_desc;
}
}
return $get_rec;
}
Please let me know the problem. Thanks in advance.
You are using count on groupBy element and count is returning only the grouped count. That's why it is returning only single row or 1. You could count the returned collections in this case like-
$count = $get_rec->count();

Laravel: Join Closure Inside where closure. Eloquent

I'm trying to select some registries in my "properties" table using a filter search function.
In my controller I receive the filters and process them with an advanced where, inside it I need to look registries related by other table when the filter "room" is used. For this I'm trying to do a join inside the where closure, but the join is not working at all, the search is done ignoring the join.
Controller:
$filter_type= Input::has('filter_type') ? Input::get('filter_type') : NULL;
$filter_val= Input::has('filter_val') ? Input::get('filter_val') : NULL;
$state= NULL;
$sub_category= NULL;
$cat_operation= NULL;
$room= NULL;
if($filter_type == 'state'){
$state = $filter_val;
}
if($filter_type == 'sub_category'){
$sub_category = $filter_val;
}
if($filter_type == 'cat_operation'){
$cat_operation = $filter_val;
}
if($filter_type == 'room'){
$room = $filter_val;
}
$properties = Property::where(function($query) use ($state, $sub_category, $cat_operation, $room){
if (isset($state)){
$query->where('state_id', $state);
}
if (isset($sub_category)){
$query->where('sub_category_id', $sub_category);
}
if (isset($cat_operation)){
$query->where('cat_operation_id', $cat_operation);
}
if(isset($room)){
$query->join('properties_control', function($join) use ($room)
{
if($room == 5){
$join->on('properties.id', '=', 'properties_control.property_id')
->where('properties_control.category_feature_item_id', '=', 75)
->where('properties_control.category_feature_item_value', '>=', $room);
}else{
$join->on('properties.id', '=', 'properties_control.property_id')
->where('properties_control.category_feature_item_id', '=', 75)
->where('properties_control.category_feature_item_value', '=', $room);
}
});
}
})->paginate(20);
The join statement is not running at all.
It's possible include a join closure in a where closure like I am trying to do here? There is another way to accomplish this?
The main reason why your join closure is not working, is because it is enclosed in an advanced where closure.
Here's the laravel (right) way to write the code above:
$filter_type= Input::get('filter_type',null);
$filter_val= Input::get('filter_val',null);
//Start the query builder
$queryProperties = Property::newQuery();
//Switch on type of filter we received
switch($filter_type)
{
case 'state'
$queryProperties->where('state_id',$filter_val);
break;
case 'sub_category':
$queryProperties->where('sub_category_id', $filter_val);
break;
case 'cat_operation':
$queryProperties->where('cat_operation_id', $filter_val);
break;
case 'room':
$queryProperties->join('properties_control', function($join) use ($filter_val)
{
if($room == 5){
$join->on('properties.id', '=', 'properties_control.property_id')
->where('properties_control.category_feature_item_id', '=', 75)
->where('properties_control.category_feature_item_value', '>=', $filter_val);
}else{
$join->on('properties.id', '=', 'properties_control.property_id')
->where('properties_control.category_feature_item_id', '=', 75)
->where('properties_control.category_feature_item_value', '=', $filter_val);
}
});
break;
}
$properties = $queryProperties->paginate(20);

Set Parameter with TableGateway Select Function show error undefined variable

i create a function in my model like :
public function getAllMenuByOnlyActionPage($actionlot){
$act = trim($actionlot);
$result = $this->tableGateway->select(function (Select $select) {
$select->where(array('status != ?' => 13))
->where(array('action' => $act))
->order('id ASC');
});
$results = array();
foreach ($result as $row) {
$results[] = $row;
}
return $results;
}
When i try to execute then its show me Notice: Undefined variable: act. I already see this link ZF2 tableGateway select but i want to set parameter for this function. Thanks
Try
$result = $this->tableGateway->select(function (Select $select) use ($act) {
$select->where(array('status != ?' => 13))
->where(array('action' => $act))
->order('id ASC');
});

Categories