I want to initialize a collection that I will get from a table but if I use whereMonth on that collection it says that whereMonth does not exist.
I've used whereHas instead of initializing a collection but this becomes a very long code that could still possibly be reduced to a more efficient one.
$makati = [];
$cebu = [];
$davao = [];
for($x = 1; $x <= 12; $x++){
$makati[$x-1] = student::with('branch', 'program')
->whereHas('branch', function($query){
$query->where('name', '!=', 'Language Only');
})
->whereHas('branch', function($query) {
$query->where('name', 'Makati');
})->whereMonth('date_of_signup', $x)->whereYear('date_of_signup', '2019')->count();
}
This is working perfectly fine, but see that I will do the same code for the arrays $cebu and $davao.
$student = student::with('branch', 'program')->whereYear('date_of_signup', '2019')->get();
$student = $student->where('program.name', '!=', 'Language Only');
$makati = [];
$cebu = [];
$davao = [];
for($x = 1; $x <= 12; $x++){
$makati[$x-1] = $student->whereMonth('date_of_signup', $x);
info($makati);
}
I've tried this one but this is where the whereMonth error occurs.
the first code actually works but I want to make a shorter and efficient code.
$student = student::with('branch', 'program')->whereYear('date_of_signup', '2019');
$student = $student->where('program.name', '!=', 'Language Only');
$makati = [];
$cebu = [];
$davao = [];
for($x = 1; $x <= 12; $x++){
$makati[$x-1] = $student->whereMonth('date_of_signup', $x)->get();
info($makati);
}
Am thinking the whereMonth() method doesn't work on a gotten collection instance but on a query builder instance, so getting the collection makes the method inaccessible. like the code I have copied above, do not get until you are done using all the query builders. I hope this helps.
whereMonth('x', 1) is a shortcut that generates the SQL WHERE MONTH(x)=1 . SQL queries aren't generally mapped to the collection even though there is effort made to match collection methods to query builder methods as much as possible. The workaround is:
$student = student::with('branch', 'program')->whereYear('date_of_signup', '2019')->get();
$student = $student->where('program.name', '!=', 'Language Only');
$makati = [];
$cebu = [];
$davao = [];
for($x = 1; $x <= 12; $x++){
$makati[$x-1] = $student->filter(function ($value) use ($x) {
return $value->date_of_signup->month == $x;
});
info($makati);
}
This assumes that date_of_signup is properly casted to a date when retrieved using the $dates property in the model.
This is done in your student model:
class student extends Model {
protected $casts = [ 'date_of_signup' => 'date' ];
// rest of model
}
As a sidenote, it's probably more efficient if you do:
$student = student::with('branch', 'program')
->whereYear('date_of_signup', '2019')
->whereHas('program' => function ($query) {
$query->where('name', '!=', 'Language Only');
})
->get();
which will filter the results using an SQL query instead of getting everything and then filtering on the collection
Related
I cant orderBy points. Points is accessor.
Controller:
$volunteers = $this->volunteerFilter();
$volunteers = $volunteers->orderBy('points')->paginate(10);
Volunteers Model:
public function siteActivities()
{
return $this->belongsToMany(VolunteerEvent::class, 'volunteer_event_user', 'volunteer_id', 'volunteer_event_id')
->withPivot('data', 'point', 'point_reason');
}
public function getPointsAttribute(){
$totalPoint = 0;
$volunteerPoints = $this->siteActivities->pluck('pivot.point', 'id')->toArray() ?? [];
foreach ($volunteerPoints as $item) {
$totalPoint += $item;
}
return $totalPoint;
}
But I try to sortyByDesc('points') in view it works but doesn't work true. Because paginate(10) is limit(10). So it doesn't sort for all data, sort only 10 data.
Then I try to use datatable/yajra. It works very well but I have much data. so the problem came out
Error code: Out of Memory
You could aggregate the column directly in the query
$volunteers = $this->volunteerFilter();
$volunteers = $volunteers->selectRaw('SUM(pivot.points) AS points)')->orderByDesc('points')->paginate(10);
I'd like to ask whether is possible to use where method on multiple collections at once.. better to say, is possible to symplify this code somehow, please? Thank you so much.
$posts_per_weeks = array();
for($i = 10; $i > 0; $i--) {
$my_posts = $user->posts()
->where('created_at', '>', Carbon::now()->subWeek($i))
->where('created_at', '<=', Carbon::now()->subWeek($i-1))
->count();
$all_posts = Post::all()
->where('created_at', '>', Carbon::now()->subWeek($i))
->where('created_at', '<=', Carbon::now()->subWeek($i-1))
->count();
array_push($posts_per_weeks, [$my_posts, $all_posts - $my_posts]);
}
Method posts() looks like this:
public function posts()
{
if($this->hasAnyRole('broker|super-agent')) {
$posts = $this->teams()->get()->map(function ($team) {
return $team->posts->all();
});
if($this->hasRole('broker')) {
$posts->push($this->hasMany('App\Post', 'broker_id')->get());
}
return $posts->collapse()->unique();
} elseif($this->hasRole('admin')) {
return Post::all();
} else {
return $this->hasMany('App\Post', 'agent_id')->get();
}
}
You can use groupByto group the results
$maxWeeksBack = 10;
$myPostCount = $user->posts()->where('created_at', '>', Carbon::now()->subWeek($maxWeeksBack))
->select('id', DB::raw('count(*) as total'))
->groupBy(DB::raw('WEEK(created_at)'))
->get();
$postCount = Post::where('created_at', '>', Carbon::now()->subWeek($maxWeeksBack))
->select('id', DB::raw('count(*) as total'))
->groupBy(DB::raw('WEEK(created_at)'))
->get();
This returns the count of posts and myposts as an array, sorted by week. You would need to merge the two arrays to have your array, but this is a much cleaner approach to get the count of the posts.
DISCLAMER: Haven't tested it live, but it should work
You could use QueryScopes.
Post.php
class Post
{
public function scopeFromWeek($query, $week) {
return $builder->where('created_at', '>', Carbon::now()->subWeek($week))
->where('created_at', '<=', Carbon::now()->subWeek($week-1));
}
}
In your controller (or wherever you use this code)
$posts_per_weeks = [];
for($i = 10; $i > 0; $i--) {
$my_posts = $user->posts()->fromWeek($i)->count();
$all_posts = Post::fromWeek($i)->count();
array_push($posts_per_weeks, [$my_posts, $all_posts - $my_posts]);
}
I have an array that comes to controller's action.
$arrOfTags = $request['position'];
That array looks like :
['manager', 'consultant'];
Next, I am querying the DB for CV's where position is one of these.
$query = Cv::query();
$query->whereIn('position', $arrOfTags);
...
->get();
Now the question :
If $request['position'] = ['manager','consultant']; and whereIn clause finds result just for position = 'consultant' and none for 'manager', how can I programmatically discover that results are found for 'consultant' and/or didn't found for 'manager' ?
EDIT
All my query's code :
$arrOfTags = explode(',', $request['position']);
$query = Cv::query();
$query->whereIn('position', $arrOfTags)
if($request['salary']) {
$query->whereIn('salary', $request['salary']);
}
if($request['skill']) {
$query->join('skills', 'cvs.id', '=', 'skills.cv_id')
->join('allskills', 'skills.allskills_id', '=', 'allskills.id')
->select('cvs.*', 'allskills.name AS skillName')
->whereIn('skills.allskills_id', $request['skill']);
}
if($request['language']) {
$query->join('languages', 'cvs.id', '=', 'languages.cv_id')
->join('alllanguages', 'languages.alllanguages_id', '=', 'alllanguages.id')
->select('cvs.*', 'alllanguages.name as languageName')
->whereIn('languages.alllanguages_id', $request['language']);
}
$cvs = $query->distinct()->get();
Imagine that $arrOfTags values are ['manager', 'consultant', 'sales']
I want somehow to discover that results was found for position =
manager and consultant, and didn't found for position = 'sales'
You can load the data from DB:
$cvs = CV::....;
And then use the partition() method:
list($manager, $consultant) = $cvs->partition(function ($i) {
return $i['position'] === 'manager';
});
Or the where() method:
$manager = $cvs->where('position', 'manager');
$consultant = $cvs->where('position', 'consultant');
Both partition() and where() will not execute any additional queries to DB.
You can do this way too:
$managers = $collection->search(function ($item, $key) {
return $item['position'] === "manager";
});
$consultants = $collection->search(function ($item, $key) {
return $$item['position'] === "consultant";
});
You could use count().
if(($query->count)==($query->where('position','consultant')->count())){
///all are coming for position=consultants
}
Or you could use groupBY-
$query = $query->groupBy('position')->toArray();
And retrieve by-
$consultants = $query['consultant'];
I wonder if Laravel have any helper to modify a collection.
What I need to do is to make a query with paginate() then check if the logged in users ID match the sender or receiver and based on that add a new value to the output:
$userId = Auth::guard('api')->user()->user_id;
$allMessages = Conversation::join('users as sender', 'conversations.sender_id', '=', 'sender.user_id')
->join('users as reciver', 'conversations.recipient_id', '=', 'reciver.user_id')
->where('sender_id',$userId)->orWhere('recipient_id',$userId)
->orderBy('last_updated', 'desc')
->select('subject','sender_id','recipient_id', 'sender_unread', 'recipient_unread', 'last_updated', 'reciver.username as receivername', 'sender.username as sendername')
->paginate(20);
Now I want to do something like:
if ($allMessages->sender_id == $userId) {
// add new value to output
newField = $allMessages->sendername
} else {
// add new value to output
newField = $allMessages->receivername
}
Then send the data with the new value added
return response()->json(['messages' => $allMessages], 200);
Is this possible?
You're better off using the Collection class's built-in functions for this. For example, the map function would be perfect.
https://laravel.com/docs/5.3/collections#method-map
$allMessages = $allMessages->map(function ($message, $key) use($userId) {
if ($message->sender_id == $userId) {
$message->display_name = $message->receivername;
} else {
$message->display_name = $message->sendername;
}
return $message;
});
Solved by adding:
foreach ($allMessages as $message) {
if ($message->sender_id == $userId) {
$message->display_name = $message->receivername;
} else {
$message->display_name = $message->sendername;
}
}
You can surely use the laravel's LengthAwarePaginator.
Along with total count of collection you also need to pass the slice of collection's data that needs to be displayed on each page.
$total_count = $allMessages->count();
$per_page = 2;
$current_page = request()->get('page') ?? 1;
$options = [
'path' => request()->url(),
'query' => request()->query(),
];
Suppose you want 2 results per page then calculate the offset first
$offset = ($current_page - 1) * $per_page;
Now slice the collection to get per page data
$per_page_data = $collection->slice($offset, $per_page);
$paginated_data = new LengthAwarePaginator($per_page_data, $total_count, $per_page, $current_page, $options);
$paginated_data will have only limited number of items declared by $per_page variable.
If you want next two slice of data then pass api_request?page="2" as your url.
As I don't know which Laravel version you're using, taking Laravel 5.2 let me give you a smarter way to deal with this (if I get your problem correctly).
You can use Laravel's LengthAwarePaginatior(API Docs).
Don't use paginate method when you are bulding your query, instead of that use simple get method to get simple collection.
$userId = Auth::guard('api')->user()->user_id;
$allMessages = Conversation::join('users as sender', 'conversations.sender_id', '=', 'sender.user_id')
->join('users as reciver', 'conversations.recipient_id', '=', 'reciver.user_id')
->where('sender_id',$userId)->orWhere('recipient_id',$userId)
->orderBy('last_updated', 'desc')
->select('subject','sender_id','recipient_id','sender_unread','recipient_unread','last_updated','reciver.username as receivername','sender.username as sendername')
->get();
Now you can populate extra items into that collection based on your certain conditions like this.
if ($allMessages->sender_id == $userId ) {
// add new value to collection
} else {
// add new value to collection
}
Now use LengthAwarePaginator, to convert that populated collection into a paginated collection.
$total_count = $allMessages->count();
$limit = 20;
$current_page = request()->get('page');
$options = [
'path' => request()->url(),
'query' => request()->query(),
];
$paginated_collection = new LengthAwarePaginator($allMessages, $total_count, $limit, $current_page, $options);
The variable $paginated_collection now can be used to be sent in response. Hope this helps you to deal with your problem.
I'm trying to build a query based on URL parameters. When the Controller is loaded I need to check which parameters have been provided and build a query from them. It's working with static values, but isn't working with conditional statements. Is my laravel syntax correct?
class OrdenesController extends BaseController {
public function showOrdenes($action)
{
$my_id = Auth::user()->id;
$my_cod = Auth::user()->codprov;
switch ($action)
{
case 'list':
$rows = DB::table('ordens')->count();
if(Input::get("jtSorting"))
{
$search = explode(" ", Input::get("jtSorting"));
$numorden= Input::get("nro_orden");
$filtros =explode(" ", $filtros);
$data = DB::table("ordens")
->select(array('*', DB::raw('SUM(cant_pend) as cant_pend'), DB::raw('SUM(importe) as importe')))
->where('cod_prov', '=', $my_cod)
->where('nro_orden', '=', $numorden)///work
---------- ////no work
if (Input::has('nro_orden')) {
->where('nro_orden', '=', $numorden)
}
---------- /// no work
->groupBy('nro_orden')
->skip(Input::get("jtStartIndex"))
->take(Input::get("jtPageSize"))
->orderBy($search[0], $search[1])
->get();
}
return Response::json(
array(
"Result" => "OK",
"TotalRecordCount" => $rows,
"Records" => $data
)
);
break;
};
}
}
You are missing the variables, no? You haven't told PHP what variable/object to do the where() to in your condition. The magic of Laravel's Eloquent (and a lot of other libraries) is that when you call its methods, it returns itself (the object) back so you can make another method call to it right away.
So when you do this:
$data = DB::table("ordens")
->select(...)
->where(...);
is the same as:
$data = DB::table("ordens");
$data = $data->select(...);
$data = $data->where(...);
But you are trying to do ->where(...) right away after if condition. You need to tell PHP which object/variable you are trying to call the method from. Like this:
$num = Input::get("nro_orden");
$data = DB::table("ordens")
->select(array('*', DB::raw('SUM(cant_pend) as cant_pend'), DB::raw('SUM(importe) as importe')))
->where('cod_prov', '=', $my_cod);
if (Input::has('nro_orden')) {
$data = $data->where('nro_orden', '=', $num);
}
$data = $data->groupBy('nro_orden')
->skip(Input::get("jtStartIndex"))
->take(Input::get("jtPageSize"))
->orderBy($search[0], $search[1])
->get();