Pass Eloquent\Builder as parameter - php

Probably it's an easy answer, but I don't find it!
I'm using Eloquent to perform my queries into the database, having this code:
public function postSearch(Request $request)
{
$query = Customer::select('identification', 'first_name', 'second_name', 'first_lastname', 'second_lastname', 'genre')
->where('identification', 'LIKE', "%$request->identification%")
->where('first_name', 'LIKE', "%$request->first_name%")
->Where('second_name', 'LIKE', "%$request->second_name%")
->Where('first_lastname', 'LIKE', "%$request->first_lastname%")
->Where('second_lastname', 'LIKE', "%$request->second_lastname%")
->Where('genre', 'LIKE', "%$request->genre%");
$request->session()->put('list', $query->get());
$customers = $query->paginate(20);
return view('customer.index', compact('customers'));
}
/**
* Display a listing of the resource.
*
* #return \Illuminate\Http\Response
*/
public function index(Request $request)
{
$query = Customer::select('identification', 'first_name', 'second_name', 'first_lastname', 'second_lastname', 'genre');
$request->session()->put('list', $query->get());
$customers = $query->paginate(20);
return view('customer.index', compact('customers'));
}
It works perfectly, but now, I want to optimize it creating another funtion which receives the $query. Something like this:
public function displayResult(Builder $query,Request $request)
{
$request->session()->put('list', $query->get());
$customers = $query->paginate(20);
return view('customer.index', compact('customers'));
}
The objective is to call the function from my previous methods, e.g:
public function index(Request $request)
{
$query = Customer::select('identification', 'first_name', 'second_name', 'first_lastname', 'second_lastname', 'genre');
$this->displayResult($query, $request);
}
But, my view is not displaying nothing. Am I doing something wrong?
Should I use a Model instead Builder parameter? If I do so, then it's displaying this error:
Argument 1 passed to
App\Http\Controllers\CustomerController::displayResult() must be an
instance of App\Http\Controllers\Model, instance of
Illuminate\Database\Eloquent\Builder given, called in ....on line 54 and defined
That line is exactly where I call to my new funtion.
Thanks in advance.

Your displayResult() method returns the view instance, but you forgot to return it from your controller's index() method.
Replace
$this->displayResult($query, $request);
with
return $this->displayResult($query, $request);

Related

Call to undefined method Illuminate\Database\Eloquent\Builder::filter()

I try to make Filters.
When I have:
public function index(OrderFilter $filter): View
{
$items = Order::withTrashed()->filter($filter)->paginate(10);
return view($this->viewsPath . self::INDEX_ACTION, [
'items' => $items,
'perPage' => 10,
]);
}
I take mistake Call to undefined method Illuminate\Database\Eloquent\Builder::filter()
But when I delete filter($filter) I have not any mistake but my filtration does not work.
How can I make filtration correctly?
OrderFilter
<?php
namespace App\Filters\Orders;
use App\Filters\QueryFilter;
class OrderFilter extends QueryFilter
{
public function id(string $id)
{
$this->builder->where('id', $id);
}
public function name(string $name)
{
$this->builder->where('name', 'like', '%' . $name . '%');
}
public function address(string $address)
{
$this->builder->where('address', 'like', '%' . $address . '%');
}
}
filter() is a method that is available on collections. So when you do
$query = Order::withTrashed()->filter($filter)->paginate(10);
what you are doing is appending the filter method to the query builder instance and this will give you error.
In order to fix this, you can do:
$query = Order::withTrashed()->paginate(10)->filter($filter);
and, this won't give you error because now you're applying filters on the collection.
If you want to conditionally apply filters by modifying the query builder, maybe consider the EloquentFilter package by Tucker-Eric.

Eloquent Query With Custom Method

i am using laravel 7 eloquent. i am very new to laravel
this is basic method i am getting data from category table
public function category(){
$category = Category::orderBy('id', 'desc')->get();
$data['pageData'] = $category;
$data['pageTitle'] = "Category";
return view('admin.category.index')->with('data',$data);
}
But i want to do something like this
public function category(){
$category = Category::orderBy('id', 'desc')->get();
if(!empty($_REQUEST['parent_id']))
$category->where('parent_id',$_REQUEST['parent_id']);
$data['pageData'] = $category;
$data['pageTitle'] = "Category";
return view('admin.category.index')->with('data',$data);
}
So how can this is possible using eloquent.
Any help out of this question are helpful for me as i am beginner.
Try this
public function category(){
$query = Category::orderBy('id','desc');
$query = where('parent_id',$_REQUEST['parent_id']);
$category = $query->get();
$data['pageData'] = $category;
$data['pageTitle'] = 'Category';
return view('admin.category.index')->with('data',$data);
}
You can leverage the when() eloquent method to add conditional clause to query:
public function category()
{
$category = Category::when(request('parent_id'),function($parent_id,$query)
{
$query->where('parent_id',$parent_id);
})->orderBy('id', 'desc')->get();
$data['pageData'] = $category;
$data['pageTitle'] = "Category";
return view('admin.category.index')->with('data',$data);
}
when() doc reference https://laravel.com/docs/8.x/queries#conditional-clauses
You can use the when method to only apply the query if the request contains the parent_id.
From the docs:
Sometimes you may want certain query clauses to apply to a query based
on another condition. For instance, you may only want to apply a where
statement if a given input value is present on the incoming HTTP
request. You may accomplish this using the when method:
$role = $request->input('role');
$users = DB::table('users')
->when($role, function ($query, $role) {
return $query->where('role_id', $role);
})
->get();
The when method only executes the given closure when the first
argument is true. If the first argument is false, the closure will not
be executed. So, in the example above, the closure given to the when
method will only be invoked if the role field is present on the
incoming request and evaluates to true.
In your case it would be the following:
use Illuminate\Http\Request;
public function category(Request $request)
{
$categories = Category::query()
->when($request->input('parent_id'), function ($query, $parent_id) {
$query->where('parent_id', $parent_id);
})
->orderBy('id', 'desc')
->get();
$data['pageData'] = $categories;
$data['pageTitle'] = "Category";
return view('admin.category.index')->with('data', $data);
}
You can do as like below
public function category(){
$category = new Category();
if(!empty($_REQUEST['parent_id'])){
$category->where('parent_id',$_REQUEST['parent_id']);
}
$category = $category->orderBy('id', 'desc')->get()
$data['pageData'] = $category;
$data['pageTitle'] = "Category";
return view('admin.category.index')->with('data',$data);
}
Try using laravel when condition
https://laravel.com/docs/8.x/queries#conditional-clauses
Improve your question with proper details. as you mention in the question the second coding path won't work because it doesn't have $request query to functionally run the if statement. anyhow if you want to get only pageData & pageTitle in laravel Eloquent ORM you have to select both columns as follows.
class CategoryController extends Controller
{
public function category(){
$category = Category::select('pageData', 'pageTitle')->orderBy('id', 'desc')->get();
return view('admin.category.index')->with('data', $category);
}
}

parameter passed to relationship from controller to model in laravel but not working

in my controller parameter passed to posts function in user model with construct method .
class MyController extends Controller
{
private $user;
public function __construct(User $getuser)
{
$this->user = $getuser;
}
public function index($id = 2)
{
$posts = $this->user->posts($id);
$user = User::FindOrFail($id);
return $user->posts;
}
}
in my user model parameter accessed and passed to relationship .
class User extends Authenticatable
{
use Notifiable;
protected $fillable = [
'name', 'email', 'password',
];
function posts($id)
{
return $this->hasMany('App\Post')->where('id',$id);
}
}
it works when use like this
"return $this->hasMany('App\Post')->where('id',1);"
but not working with passed parameter. getting this error
"Symfony\Component\Debug\Exception\FatalThrowableError Too few
arguments to function App\User::posts(), 0 passed in
C:\xampp\htdocs\blog\vendor\laravel\framework\src\Illuminate\Database\Eloquent\Concerns\HasAttributes.php
on line 415 and exactly 1 expected"
Check your controller method you should be returning. ie: return $posts instead of return $user->posts as this is seeking to find posts without passing in the id as you do with $posts = $this->user->posts($id);
That's why you are getting a symphony error of too few arguments as you pass no arguments in return $user->posts
User Model
function posts($id)
{
return $this->hasMany('App\Post');
}
You could access the post with the given condition by using where on the relation method.
Querying relations
https://laravel.com/docs/7.x/eloquent-relationships#querying-relations
$post = $user->posts()->where('id', $id)->first();
You could use get() or first() according to your requirement.
$posts = $user->posts()->where('id', $id)->get();
If you want a user who has a post that satisfies the criteria.
$user = User::whereHas('posts', function($query) use($id){
$query->where('id', $id);
// You may add several other conditions as well.
})
->with(['posts' => function($query) use($id){
$query->where('id', $id);
}
])
->first();
Now,
$user->posts
will give a collection of only ONE post Model Instance that satisfied the condition

How to get only the searched data with where clause?

$data['ads'] = PostAd::where('category_id',$id)
->orwhere('district_id','LIKE','%'.$location.'%')
->orWhere('condition','LIKE','%'.$condition.'%')
->orWhere('price','>='.$min_price)
->orWhere('price','<='.$max_price)
->orWhere('fuel',$fuel)
->orWhere('anchalorpradesh',$anchal)
->orWhere('mileage',$mileage)
->orWhere('kilometers',$kilometers)
->orWhere('engine',$engine)
->get();
i want to show data whose category_id is $id. But whenever i try to search it shows me all the data in the database. Suppose i want to search data whose kilometer is 24. There is only one data whose kilometer is 24. But instead of showing that one data it shows me all the data in database.
Try something like this, adding conditional optionally based on search parameters choosen
$query = PostAd::query();
if ( isset($id) ) {
$query = $query->where('category_id',$id);
}
if ( isset($location) ) {
$query = $query->where('district_id', 'LIKE', '%' . $location . '%');
}
if ( isset($condition) ) {
$query = $query->where('condition', 'LIKE', '%' . $condition. '%');
}
$result = $query->get();
You can use the when method to conditionally add clauses to your queries depending on a value passing a “truth” test:
PostAd::query()
->when($request->get('category_id'), function ($query, $categoryId) {
$query->where('category_id', '=', $categoryId);
})
->paginate();
The closure you pass as the second argument will receive two arguments: a query builder instance that you can modify, and the value you passed as the first parameter to the when method.
You can also take this one step further and move your filtering logic to a dedicated class:
class PostAdFilters
{
protected $request;
protected $builder;
public function __construct(Request $request)
{
$this->request = $request;
}
public function apply(Builder $builder)
{
$this->builder = $builder;
foreach ($this->request->query() as $key => $value) {
// Convert something like `category_id` to `filterByCategoryId`
$methodName = 'filterBy' . Str::studly($key);
if (method_exists($this, $methodName)) {
// If the method exists, call it
call_user_func([$this, $methodName], $value);
}
}
// Return the modified query builder
return $this->builder;
}
private function filterByCategoryId($value)
{
$this->builder->where('category_id', '=', $value);
}
private function filterByKilometers($value)
{
$this->builder->where('kilometers', '=', $value);
}
// And so on...
}
class PostAd extends Model
{
public function scopeFilters(Builder $query, PostAdFilters $filters)
{
return $filters->apply($query);
}
}
You can then inject this class in your controller method, and apply it to your model:
public function search(PostAdFilters $filters)
{
return PostAd::filter($filters)->paginate();
}
This approach is based on https://laracasts.com/series/eloquent-techniques/episodes/4

Filtering data with spatie query builder using trait

I put logic from my function index() of UserController in trait taht i created:
public function index()
{
$this->authorize('view', Auth::user());
$users = QueryBuilder::for(User::class)
->allowedIncludes('kids','roles','articles','recordings')
->allowedFilters('first_name', 'last_name', 'email')
->get();
return UserResource::collection($users);
}
and this is my trait :
<?php
namespace App\Http\Traits;
use App\Models\User;
use Spatie\QueryBuilder\QueryBuilder;
trait Filterable
{
public function filter()
{
$users = QueryBuilder::for(User::class)
->allowedIncludes('kids','roles','articles','recordings')
->allowedFilters('first_name', 'last_name', 'email')
->get();
return $users;
}
}
So now my function index() looks like this:
use Filterable;
public function index()
{
$this->authorize('view', Auth::user());
$users = $this->filter();
return UserResource::collection($users);
Now when i do this in my postman
{{url}}/api/users?filter[first_name]=anna
it works and it returns anna from my database but when I try
{{url}}/api/users?include=roles
it return every user from database but does not include roles.
Can somebody help me with this?
This is taken straight from the github page: https://github.com/spatie/laravel-query-builder#custom-filters
Custom filters
use Spatie\QueryBuilder\Filters\Filter;
use Illuminate\Database\Eloquent\Builder;
class FiltersUserPermission implements Filter
{
public function __invoke(Builder $query, $value, string $property) : Builder
{
return $query->whereHas('permissions', function (Builder $query) use ($value) {
$query->where('name', $value);
});
}
}
use Spatie\QueryBuilder\Filter;
// GET /users?filter[permission]=createPosts
$users = QueryBuilder::for(User::class)
->allowedFilters(Filter::custom('permission', FiltersUserPermission::class))
->get();
// $users will contain all users that have the `createPosts` permission

Categories