I'm wondering how can I rewrite the following User model eloquent business logic to be a bit more DRY. I'm passing three parameters to the model, where all of them are optional, to narrow down the DB search. I'm sure there has to be a elegant way to do this, but it is beyond me at the moment.
public function guests_age($location_id, $year, $gender)
{
if($location_id && $year && $gender)
{
return Guest::select('age')
->where('location_id', '=', $location)
->where('created_at', '=', $year)
->where('gender', '=', $gender)
->get();
}
elseif($location_id && $year && !$gender)
{
return Guest::select('age')
->where('location_id', '=', $location)
->where('created_at', '=', $year)
->get();
}
elseif($location_id && !$year && !$gender)
{
return Guest::select('age')
->where('location_id', '=', $location)
->get();
}
... and so on to cover all cases...
}
Thanks for any help.
try this method
public function guests_age($location_id, $year, $gender)
{
$this->qry = Guest::select('age');
if($location_id)
{
$this->qry->where('location_id', '=', $location);
}
if($year)
{
$this->qry->->where('created_at', '=', $year)
}
if($gender)
{
$this->qry->where('gender', '=', $gender)
}
return $this->qry->get()
... and so on to cover all cases...
}
public function guests_age($args = array())
{
$columns = array('location_id', 'created_at', 'gender');
$query = Guest::select('age');
foreach($columns as $column)
{
if(!empty($args[$column]))
$query = $query->where($column, $args[$column]);
}
return $query->get();
}
//usage:
guests_age(array('location_id' => '1'));
guests_age(array('location_id' => '1', 'gender' => 'm'));
//etc..
Related
The following example will give me all users that are older than $age and have the gender $gender:
public function get_users_older_than(int $age = null, string $gender = null) {
$users = User::query()
->where('age', '>', $age)
->where('gender', $gender)
->get();
return $users;
}
Is there a way to use the where clause only if age or gender is present in a more eloquent and shorter way then:
public function get_users_older_than(int $age = null, string $gender = null) {
$users = User::query();
if ($age) {
$users = $users->where('age', '>', $age):
}
if ($gender) {
$users = $users->where('gender', $gender):
}
$users = $users->get();
return $users;
}
With that, I could avoid to create and use the extra function and just have one single arrow connected line of code.
A shorter way to do that would be this:
$users = User::where(function ($q) use($age, $gender) {
if ($age) {
$q->where('age', '>', $age);
}
if ($gender) {
$q->where('gender', $gender);
}
})->get();
But just so you know, shorter code does not guarantee more efficiency.
There is also a conditional clauses function when.
Based on what you have, that could look like:
public function get_users_older_than(int $age = null, string $gender = null) {
$users = User::query();
$users->when($age, function ($query, $age) {
$query->where('age', '>', $age);
})->when($gender, function ($query, $gender) {
$query->where('gender', $gender);
})->get();
return $users;
}
what am i doing wrong? pagination isn't working and i'm not getting any error. next button isn't working. is there a solution to this?
class PostsIndex extends Component
public function render()
{
$statuses = Status::all()->pluck('id', 'name');
$schools = School::all();
return view('livewire.posts-index', [
'posts' => Post::with('user', 'school', 'status')
->when($this->status && $this->status !== 'All', function ($query) use ($statuses) {
return $query->where('status_id', $statuses->get($this->status));
})->when($this->school && $this->school !== 'All Schools', function ($query) use ($schools) {
return $query->where('school_id', $schools->pluck('id', 'name')->get($this->school));
})->when($this->filter && $this->filter === 'Top Exp', function ($query) {
return $query->orderByDesc('votes_count');
})->when($this->filter && $this->filter === 'My Exp', function ($query) {
return $query->where('user_id', auth()->id());
})->when($this->filter && $this->filter === 'Spam Posts', function ($query) {
return $query->where('spam_reports', '>', 0)->orderByDesc('spam_reports');
})->when(strlen($this->search) >= 3, function ($query) {
return $query->where('body', 'like', '%'.$this->search.'%');
})
->addSelect(['voted_by_user' => Vote::select('id')
->where('user_id', auth()->id())
->whereColumn('post_id', 'posts.id')
])
->withCount('votes')
->withCount('comments')
->orderBy('id', 'desc')
->simplePaginate(10)
->withQueryString(),
'schools' => $schools,
]);
}
}
i have tried my possible best could not get it to work
Try to add the link {{ $schools->links() }} in the posts-index file
I want to order a query in laravel ways depending on certain factors. One of which would be a related table.
So right now my query goes like this:
$products = Product::where("price", "<=", $maxBudget)
and I know that I can add a function to my where clause like so
->where(function ($q) use($mature) {
if ($mature == "1") {
$q->where('mature', 1)->orWhere('mature', 0);
} else {
$q->where('mature', 0);
}
})
however I want to make a function for my order as well. Something like this (I know this is wrong, this is just an example):
->orderBy(function ($q) use($orderBy) {
if ($orderBy == "price_low") {
$q->orderBy('price', 'desc');
} elseif ($orderBy == "price_high") {
$q->orderBy('price', 'asc');
} elseif ($orderBy == "rating") {
$q->orderBy( $product->user->getAvgStarRating(), 'desc')
} else {
$q->orderBy('created_at', 'desc');
}
})
The $q->orderBy( $product->user->getAvgStarRating(), 'desc') is obviously wrong, $product isn't even defined, but you get the idea. In this scenario, I'd like to order my query based off the average rating of the creator of the product.
So my questions are: How do I make it so that I can add a function of some kind to my ordering, and how can I order a query based off related tables?
Define a user relationship (if haven't already):
public function user() {
return $this->belongsTo(User::class);
}
Then you can use a modified withCount():
Product::withCount(['user' => function($query) {
$query->select('avgStarRating');
}])->orderBy('user_count', 'desc');
You can also use a simple JOIN:
Product::select('products.*')
->join('users', 'users.id', 'products.user_id')
->orderBy('users.avgStarRating', 'desc');
can you try this
$products = Product::where("price", "<=", $maxBudget)
->where(function ($q) use($mature) {
if ($mature == "1") {
$q->where('mature', 1)->orWhere('mature', 0);
} else {
$q->where('mature', 0);
}
})
->orderBy(function ($q) use($orderBy) {
if ($orderBy == "price_low") {
$q->orderBy('price', 'desc');
} elseif ($orderBy == "price_high") {
$q->orderBy('price', 'asc');
} elseif ($orderBy == "rating") {
$q->join('users', 'users.id', '=','products.user_id')->orderBy('users.avgStarRating', 'desc')
} else {
$q->orderBy('created_at', 'desc');
}
})->get();
So I have two functions named 'search' and 'pdfview'.
Every time I use the search function, I want to pass a query where it selects certain data to the pdfview function.
Here's my search function:
public function search(Request $request)
{
if ($request->period == 'Daily') {
$datefrom = Carbon::now()->startOfDay();
$dateto = Carbon::now()->endOfDay();
}
elseif ($request->period == 'Weekly') {
$datefrom = Carbon::now()->startOfWeek();
$dateto = Carbon::now()->endOfWeek();
}
elseif ($request->period == 'Monthly') {
$datefrom = Carbon::now()->startOfMonth();
$dateto = Carbon::now()->endOfMonth();
}
elseif ($request->period == 'Yearly') {
$datefrom = Carbon::now()->startOfYear();
$dateto = Carbon::now()->endOfYear();
}
else {
$datefrom = Carbon::parse($request->datefrom);
$dateto = Carbon::parse($request->dateto);
}
$solditems = DB::table('orders')
// ->join('orders', 'receipts.receipt_id', '=', 'orders.receipt_id')
->whereDate('orders.created_at', '>=', $datefrom)
->whereDate('orders.created_at', '<=', $dateto)
->where('status','=', 'served')
->select('orders.*', DB::raw('SUM(subtotal) as subtotal'), DB::raw('SUM(qty) as qty'))
->groupBy('item_id')
->orderBy('created_at', 'dsc')
->get();
return view('salesreports.sellingitems.index', compact('solditems'));
}
And here's my pdfview function:
public function pdfview(Request $request)
{
$solditems = DB::table('orders')
->where('status', 'served')
->select('orders.*', DB::raw('SUM(subtotal) as subtotal'), DB::raw('SUM(qty) as qty'))
->groupBy('item_id')
->orderBy('qty', 'dsc')
->get();
view()->share('solditems', $solditems);
if ($request->has('download')) {
$pdf = PDF::loadView('salesreports.sellingitems.pdf');
return $pdf->download('sellingitems-' . Carbon::now() . '.pdf');
}
return view('salesreports.sellingitems.pdf');
}
As you can see, the pdfview function has a default query for the $solditems. But I wanted that variable to come from my search function.
UPDATE: I managed to solve the problem using session.
Here's how you store with session:
session()->put('period', 'Daily');
and this is how you retrieve with session:
$period = $request->session()->get('period', 'default');
public function getSolditems()
{
if (!isset($this->solditems)) {
$solditems = DB::table('orders')
// ->join('orders', 'receipts.receipt_id', '=', 'orders.receipt_id')
->whereDate('orders.created_at','>=', $datefrom)
->whereDate('orders.created_at', '<=', $dateto)
->where('status','=', 'served')
->select('orders.*', DB::raw('SUM(subtotal) as subtotal'), DB::raw('SUM(qty) as qty'))
->groupBy('item_id')
->orderBy('created_at','dsc')
->get();
$this->solditems = $solditems;
} else {
$solditems = $this->solditems;
}
return $solditems;
}
public function search(Request $request)
{
....
$solditems = getSolditems();
....
}
public function pdfview(Request $request)
{
....
$solditems = getSolditems();
....
}
I think you can use $request->merge() method to pass $solditems data to pdfview() method from search()
public function search(Request $request)
{
....
$request->merge(['solditems'=>$solditems]);
$this->pdfview()
}
public function pdfview(Request $request)
{
$solditems = $request->get('solditems');
....
}
based on the example from here https://scotch.io/tutorials/simple-and-easy-laravel-routing#blog-pages-with-categories-route-parameters
I want to show entries for specific categories.
By calling this Route:
Route::get('menues/{city?}', 'PagesController#menue');
I want to show all entries for a specific city.
This is my Controller:
public function menue($city = null) {
if ($city) {
$restaurants = User::with(['articles' => function ($q){
$q->nowpublished();
}])->where('city', '=', $city)->get();
} else {
$restaurants = User::with(['articles' => function ($q){
$q->nowpublished();
}])->where('city', '!=', $city)->get();
}
return view('pages.menues')
->withRestaurants($restaurants)
->withCity($city);
}
The only thing that doesn't work is, by calling a url with a {city} that doesn't exist in the DB I want to display all entries.
With the code above this doesn't happen. I get a blank page.
How can I fix this? My guess was that the code inside my else statement displays all entries, but this isn't the case.
Do the following:
public function menue($city = null) {
$restaurants = User::with(['articles' => function ($q){
$q->nowpublished();
}]);
if(if(!is_null($city) && !is_null(City::where('name', $city)->first())) {
$restaurants->where('city', '=', $city);
}
$restaurants = $restaurants->get();
return view('pages.menues')
->withRestaurants($restaurants)
->withCity($city);
}
->where('city', '!=', $city) is the problem. If you want to get all articles, remove the condition.
Change the condition to:
if(!is_null($city) && !is_null(City::where('name', $city)->first())
Use Requests $request
public function menue(Request $request) {
if ($request->has('city')) {
I would do something like:
public function menue($city = null) {
if ($city) {
$restaurants = User::with(['articles' => function ($q){
$q->nowpublished();
}])->where('city', '=', $city)->get();
if (restaurants->count() == 0) {
$restaurants = User::with(['articles' => function ($q){
$q->nowpublished();
}])->get();
}
} else {
$restaurants = User::with(['articles' => function ($q){
$q->nowpublished();
}])->where('city', '!=', $city)->get();
}
return view('pages.menues')
->withRestaurants($restaurants)
->withCity($city);
}