Actually i want to search those question which user want to search after select any subject or course.
if a remove either whereHas from subject or course its works but with both its not working.
Please give a better solution for searching in belongsToMany realtionship.
i have a question table with Question model class
class Question extends Model{
public function courses(){
return $this->belongsToMany('App\Models\Course','course_questions');
}
public function subjects(){
return $this->belongsToMany('App\Models\Subject','subject_questions');
}
}
and in my searchController
public function index(Request $request){
$questions = Question::with(['user','courses','branches','subjects','years','universities','question_type'])
->where("status","=",1)
->where(function($query) use($request){
$q = $request->q;
if(isset($q) && !is_null($q)){
$query->where("question","LIKE","%$q%");
}
})
->whereHas('subjects',function($query) use($request){
$subjects = $request->subject;
if(isset($subjects)){
$_subjects = explode(" ",$subjects);
$query->whereIn("slug",$_subjects)
->orWhereIn("subject_name",$_subjects);
}
})
->whereHas('courses',function($query) use($request){
$course = $request->course;
if(isset($course)){
$_course = explode(" ",$course);
$query->whereIn("slug",$_course)
->orWhereIn("course",$_course);
}
})
->paginate();
if($request->ajax()){
$returnHTML = view('questions.question_list')->with('questions', $questions)->render();
return response()->json(array('success' => true, 'pageContent'=>$returnHTML));
}
You should build your query probably this way - you should verify conditions before adding any constraints to your query:
$query = Question::with(['user','courses','branches','subjects','years','universities','question_type'])
->where("status","=",1);
$q = $request->q;
if(isset($q) && !is_null($q)) {
$query = $query->where("question","LIKE","%$q%");
}
$subjects = $request->subject;
if (isset($subjects)) {
$query = $query->whereHas('subjects',function($query) use($subjects){
$_subjects = explode(" ",$subjects);
$query->whereIn("slug",$_subjects)
->orWhereIn("subject_name",$_subjects);
});
}
$course = $request->course;
if (isset($course)) {
$query = $query->whereHas('courses',function($query) use($course ){
$_course = explode(" ",$course);
$query->whereIn("slug",$_course)
->orWhereIn("course",$_course);
});
}
$questions = $query->paginate();
$products = Product::query()->
WhereHas('categories', function ($q) use ($keyword) {
$q->where('products.name', $keyword)
->orWhere('categories.name', $keyword);
})->get();
This is how I have used in my project
Related
I wanted to left join Product and ProductPrice tables together, but my mentor said not to use the eloquent relationship. So here's the code he said to use:
This is a function in App\Http\Controllers\Api\ProductController.php that's using his custom left join:
public function table($dproduct, $start, $search, $sortColumn, $sort, $index, $limit)
{
$result['dproduct'] = $dproduct;
$result['data'] = array();
$result['recordsFiltered'] = 0;
$result['recordsTotal'] = 0;
$product = new Product();
$productResult = $product->getResult($search, $sortColumn, $sort, $index, $limit);
if ($productResult['Total'] > 0) {
$result["recordsFiltered"] = $productResult['Total'];
$counter = $start;
$data = array();
foreach ($productResult['Data'] as $productData) {
$counter++;
$data[] = $this->set($counter, $productData);
}
$result["recordsTotal"] = $counter;
$result["data"] = $data;
} else {
$result["error"] = $productResult['Message'];
}
return $result;
}
here's the actual ProductController(non-api):
class ProductController extends Controller
{
const PRODUCT = 'product';
public function __construct()
{
return parent::authenticate();
}
public function index()
{
$admin = $this->getAdmin();
$productView = $this->isView(ProductController::PRODUCT);
$productCreate = $this->isCreate(ProductController::PRODUCT);
$productUpdate = $this->isUpdate(ProductController::PRODUCT);
$productDelete = $this->isDelete(ProductController::PRODUCT);
if ($productView) {
return parent::setCompactView(ProductController::PRODUCT, compact(
'admin',
'productView',
'productCreate',
'productUpdate',
'productDelete'
));
} else {
return parent::setCompactView('error', compact('admin'));
}
}
}
Here's my Product Model:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
use App\Http\Controllers\GlobalController;
class Product extends Model
{
protected $table = 'Product';
protected $primaryKey = 'Id';
public $incrementing = false;
const CREATED_AT = 'CreatedDate';
const UPDATED_AT = 'UpdatedDate';
public function getAll()
{
return self::where('Active', true)->get();
}
public function getById($Id)
{
return self::where('Id', $Id)->first();
}
public function getResult($search = '', $sortColumn = 0, $sort = '', $page = 0, $limit = 0)
{
if ($sortColumn == 1) {
$sortColumn = 'Description';
} else {
$sortColumn = 'Name';
}
if ($sort == '') {
$sort = 'asc';
}
$data = self::where(function ($query) use ($search) {
return $query->where('Name', 'like', '%' . $search . '%')
->orWhere('Description', 'like', '%' . $search . '%');
})
->skip(($page - 1) * 10)
->take($limit)
->orderBy($sortColumn, $sort)
->get();
$count = self::where(function ($query) use ($search) {
return $query->where('Name', 'like', '%' . $search . '%')
->orWhere('Description', 'like', '%' . $search . '%');
})->get()->count();
$result['Data'] = $data;
$result['Total'] = $count;
if ($count <= 0) {
$result['Message'] = GlobalController::TEXT_NO_DATA;
}
return $result;
}
public function getTotal()
{
return self::get()->count();
}
public function setDelete($id)
{
return self::where('Id', $id)->delete();
}
}
And here's my ProductPrice Model:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
use App\Http\Controllers\GlobalController;
class ProductPrice extends Model
{
protected $table = 'ProductPrice';
protected $primaryKey = 'Id';
}
ProductPrice doesn't have a controller yet as i don't really understand what to type in it.
The Product table has these as tables:
Schema::create('Product', function (Blueprint $table) {
$table->uuid('Id')->primary();
$table->uuid('CategoryId')->nullable();
$table->string('Name', 60)->charset('utf8');
$table->mediumText('Description')->charset('utf8')->nullable();
$table->uuid('CreatedId')->nullable();
$table->timestamp('CreatedDate')->useCurrent();
$table->uuid('UpdatedId')->nullable();
$table->timestamp('UpdatedDate')->useCurrent();
});
Schema::table('Product', function ($table) {
$table->foreign('CategoryId')->references('Id')->on('Category')->onDelete('set null');
$table->foreign('CreatedId')->references('Uid')->on('Admin')->onDelete('set null');
$table->foreign('UpdatedId')->references('Uid')->on('Admin')->onDelete('set null');
});
and ProductPrice is this:
Schema::create('ProductPrice', function (Blueprint $table) {
$table->uuid('Id')->primary();
$table->uuid('ProductId');
$table->integer('Price')->default(0);
$table->integer('CutPrice')->default(0);
$table->integer('SpecialPrice')->default(0);
$table->smallInteger('Discount')->default(0);
$table->uuid('CreatedId')->nullable();
$table->timestamp('CreatedDate')->useCurrent();
$table->uuid('UpdatedId')->nullable();
$table->timestamp('UpdatedDate')->useCurrent();
});
Schema::table('ProductPrice', function ($table) {
$table->foreign('ProductId')->references('Id')->on('Product')->onDelete('cascade');
$table->foreign('CreatedId')->references('Uid')->on('Admin')->onDelete('set null');
$table->foreign('UpdatedId')->references('Uid')->on('Admin')->onDelete('set null');
});
My question is, what do i need to do to left join them together on ProductId as foreign key then show them in my view on the same table view?
I have made a query in Laravel Eloquent to search in table.
public function searchContest($search){
$category = [];
$area = [];
if(isset($search['area'])){
$area = $search['area'];
}
if(isset($search['category'])){
$category = $search['category'];
}
$qry = self::whereIn('area',$area)
->whereIn('category', $category)
->get();
var_dump($query);
return;
}
But sometimes, area or category is empty and whereIn does not work with it. I'm not able to find any working solutions in the net. How can I make such a query?
Or you can take advantage of the conditional clauses as here
DB::table('table_name')
->when(!empty($category), function ($query) use ($category) {
return $query->whereIn('category', $category);
})
->when(!empty($area), function ($query) use ($area) {
return $query->whereIn('area', $area);
})
->get();
$q = self::query();
if (isset($search['area'])) {
$q->whereIn('area', $search['area']);
}
if (isset($search['category'])) {
$q->whereIn('category', $search['category']);
}
$qry = $q->get();
You can use query scope inside the entity
public function scopeArea($query, $ids)
{
if (! $ids) {
return ;
}
return $query->whereIn('area', $ids);
}
public function scopeCategory($query, $ids)
{
if (! $ids) {
return ;
}
return $query->whereIn('category', $ids);
}
Now you can build the query
$entity
->area($area)
->category($category)
->get();
https://laravel.com/docs/5.7/eloquent#query-scopes
I have query for filters:
public function filter(Request $request)
{
$category_id = $request->category;
$brand_id = $request->brand;
$filters = $request->filters;
if($brand_id == null){
$products = Products::with('brand')->whereHas('category',function($q) use($category_id){
$q->where('category_id', $category_id);
})->whereHas('filters',function($q) use($filters){
$q->where('filter_id', $filters);
})->paginate(9);
}else{
$products = Products::with('brand')->where('brand_id',$brand_id)->whereHas('category',function($q) use($category_id){
$q->where('category_id', $category_id);
})->whereHas('filters',function($qw) use($filters){
$qw->where('filter_id', $filters);
})->paginate(9);
}
//Брэнды всех товаров
$Brands = array();
foreach ($products as $product) {
if(!in_array($product->brand, $Brands)){
array_push($Brands, $product->brand);
}
}
return response()->json(['products' => $products,'brands' => $Brands]);
}
I get response only for first product, but i need to get all products which contain at least one filter from the list.How can I do it?
Just a small refactor + i'm not sure if you receive an array of filters or just a single id. If you need more than 1 id, use whereIn.
If you want to make this even cleaner, you can create Eloquent scope for filters and brands.
public function filter(Request $request)
{
$categoryId = $request->category;
$brandId = $request->brand;
$filters = $request->filters;
$query = Products::with('brand');
if ($brandId) {
$query = $query->where('brand_id', $brandId);
}
if ($filters) {
$query = $query->whereHas('filters', function($q) use ($filters) {
// If you have more than one filter id, use whereIn
// $q->where('filter_id', $filters);
$q->whereIn('filter_id', (array) $filters);
});
}
if ($categoryId) {
$query = $query->whereHas('category', function($q) use ($categoryId) {
$q->where('category_id', $categoryId);
});
}
$products = $query->paginate(9);
$brands = $products->total() > 0 ? $products->items()->pluck('brand')->all() : [];
return response()->json(compact('products', 'brands'));
}
use whereIn() function instead of where() when query products
I have products which have a many to many relationship with filters
The user may choose multiple filters and I want to display all products that match the selected filters. But by matching them I mean containing all of them (not only some of them). Here's an example to explain what I mean, let's say that the user is on the cars category page and he wants to filter all cars that are from year 2013 AND have 4x4. Now if the user selects those filters it will show all the cars that are from year 2013 OR have 4x4.
Here's my code in the controller:
public function showFilteredProducts(Request $request)
{
$products = collect([]);
$this->request = $request;
foreach ($request->filters as $filter_id => $active) {
$this->filter_id = $filter_id;
$queriedProducts = Product::whereHas('filters', function($query) {
$query->where('filters.id', $this->filter_id);
})
->whereHas('category', function($query) {
$query->where('slug', $this->request->category_slug);
})
->get();
foreach ($queriedProducts as $product) {
if (!$products->contains($product)) {
$products[] = $product;
}
}
}
return response()->json($products->chunk(3));
}
As i explained this now returns the products if they match only one of the filters, but I want them to match all of them.
try this
public function showFilteredProducts(Request $request)
{
$filters = $request->filters;
$query = Product::query();
foreach ($filters as $filter_id => $active) {
$query = $query->whereHas('filters', function($query) use ($filter_id) {
$query->where('filters.id', $filter_id);
});
}
$query = $query->whereHas('category', function($query) use ($request) {
$query->where('slug', $request->category_slug);
})
$products = $query->get();
return $products->chunk(3);
}
alternatively, based on your previous code, you can use array_intersect like this:
public function showFilteredProducts(Request $request)
{
$products = collect([]);
$this->request = $request;
foreach ($request->filters as $filter_id => $active) {
$this->filter_id = $filter_id;
$queriedProducts = Product::whereHas('filters', function($query) {
$query->where('filters.id', );
})
->whereHas('category', function($query) {
$query->where('slug', $this->request->category_slug);
})
->get();
$products = array_intersect($queriedProducts, $products);
}
return response()->json($products->chunk(3));
}
I think you want to use orWhereHas() instead of whereHas() on the second table that you are checking against.
I need to get contact name using laravel Eloquent
I have table stucture below :
CallLogs Table :
id,user_id,PhoneNumber
Phone Table :
id,PhoneNumber,contact_id
contact table :
id,Name
//CallLogs Model :
public function phone()
{
return $this->hasManyThrough('\App\Models\Phone','\App\Models\Contact','id','phoneNumber','phoneNumber');
}
// phone Model :
public function contact()
{
return $this->belongsTo(Contact::class);
}
// Contact Model:
public function phones()
{
return $this->belongsTo(Phone::class, 'contact_id');
}
Join Query :
Please look with->(['phone']) in below query
$data = CallLogs::select('*')->where('call_type', '=', '1')
->when($q, function ($query) use ($q) {
return $query->where(function ($query) use ($q) {
/** #var Builder $query */
$preparedQ = '%' . $q . '%';
$num = 0;
foreach (
[
'to_call',
'from_call',
'callcost',
'created_at'
] AS $field
) {
if ($num) {
$query = $query->orWhere($field, 'LIKE', $preparedQ);
} else {
$query = $query->where($field, 'LIKE', $preparedQ);
}
$num++;
}
return $query;
});
});
//dd($data);exit;
$outgoingcalls = $this->CallLogsFilter->applyFilter($request->get('filter', []), $data);
//$outgoingcalls = $data->paginate($count, ['*'], 'page', $pageNumber);
// Here I am using getting Name
$outgoingcalls = $outgoingcalls->with(['phone'])
->sortable()
->paginate($count, ['*'], 'page', $pageNumber);
$links = $outgoingcalls->appends(Input::except('page', 'table_only'))->links();
$filter = $request->get('search');
return compact('outgoingcalls', 'links','filter');