I am having some trouble querying some data in Laravel.
I start my query doing the following:
$query = User::whereRole('advertiser');
When I query for example $usersall = $query->whereHave_pics('1')->get();
Then I also get users that have 0 in have_pics
The $query can consist of a long string of where queries that are dynamic depending on the users choices. Some of these where queries, the users that have 0 in have_pics do qualify for, but when I end the query with whereHave_pics('1'), shouldn't I only get the users that have '1' in Have_pics?
What I am wondering, is, if there is a max number of steps that laravel can handle in the query builder?
For example, if I but whereHave_pics('1') at the beginning of the query, like this:
$query = User::whereRole('advertiser')->whereHave_pics('1');
/* More queries are added */
$usersall = $query->get();
Then it completely ignores the whereHave_pics but not the whereRole...
If I do it at the end of the query, like this:
$query = User::whereRole('advertiser');
/* More queries are added */
$usersall = $query->whereHave_pics('1')->get();
Then it is dependent on the users choices that also creates queries.
I have been trying a ton of different work arounds, like changing the query model, e.g. instead of whereHave_pics('1') I have done where('have_pics', '1') or where('have_pics', true) etc.
I have no idea what to try next.
This is the complete function, that queries the users
public function search_adv(Request $request, $locale = 'dk') {
App::setLocale($locale);
$hair_queries = [
['input' => 'blonde', 'operator' => '=', 'field' => 'haircolor'],
['input' => 'brown', 'operator' => '=', 'field' => 'haircolor'],
['input' => 'red', 'operator' => '=', 'field' => 'haircolor'],
['input' => 'dark', 'operator' => '=', 'field' => 'haircolor'],
];
$eye_queries = [
['input' => 'green', 'operator' => '=', 'field' => 'eyecolor'],
['input' => 'brown', 'operator' => '=', 'field' => 'eyecolor'],
['input' => 'blue', 'operator' => '=', 'field' => 'eyecolor'],
['input' => 'hazel', 'operator' => '=', 'field' => 'eyecolor'],
['input' => 'silver', 'operator' => '=', 'field' => 'eyecolor'],
['input' => 'amber', 'operator' => '=', 'field' => 'eyecolor'],
];
$query = User::whereRole('advertiser');
/* HAIRCOLOR */
$hair = 0;
foreach($hair_queries as $filter) {
if($hair == 0) {
if(!empty($request->input($filter['input']))) {
$query = $query->where(
$filter['field'],
$filter['operator'],
$filter['input']
);
}
}
if(!empty($request->input($filter['input']))) {
$hair++;
}
}
if ($hair >= 2) {
foreach($hair_queries as $filter){
if(!empty(request()->input($filter['input']))){
$query = $query->orWhere(
$filter['field'],
$filter['operator'],
$filter['input']
);
}
}
}
/* END HAIR COLOR */
/* EYECOLOR */
$eye = 0;
foreach($eye_queries as $filter) {
if($eye == 0) {
if(!empty($request->input($filter['input']))) {
$query = $query->where(
$filter['field'],
$filter['operator'],
$filter['input']
);
}
}
if(!empty($request->input($filter['input']))) {
$eye++;
}
}
if ($eye >= 2) {
foreach($eye_queries as $filter){
if(!empty(request()->input($filter['input']))){
$query = $query->orWhere(
$filter['field'],
$filter['operator'],
$filter['input']
);
}
}
}
/* END EYE COLOR */
$usersall = $query->whereHave_pics('1')->get();
return view('search', compact('usersall'));
}
The problem is you need to understand how where chaining and orWhere chaining works in Laravel.
When you say $query->where(..a..)->orWhere(..b..)->where(..c..)->orWhere(..d..) it will evaluate to: (a || (b && c) || d). Where you may have intended ((a || b) && (c || d)) or you may have intended ((a && c) || b || d). This is why when you need advanced where clauses, use where closures and parameter grouping
Related
I have this variable called $projectFieldOptions and it's output is like this:
https://prnt.sc/7HtxrfTy9HiI.
Now, In the Controller I need to update this. What I am doing this, first delete all the existing rows based on id_feed and id_project and then loop through this variable $projectFieldOptions and insert it. Like this:
if( $request->feed_type !== 'scrape' ) {
$delete_mapping = DB::connection($db_name)->table($db_name . '.feed_mappings')
->where('id_feed', '=', $id_feed)
->where('id_project', '=', $token)
->delete();
}
// now insert
$field_mapping = true;
if( $request->feed_type !== 'scrape' ) {
if( count($projectFieldOptions) ) {
foreach ($projectFieldOptions as $mapping) {
$data[] = [
'id_feed' => $id_feed,
'id_project' => $token,
'import_field_slug' => $mapping['value'],
'internal_field_slug' => $mapping['custom'] ? $mapping['custom_field'] : $mapping['text'],
'custom_field' => $mapping['custom'],
'updates' => $mapping['updates'],
'removes' => $mapping['removes'],
'import' => 1,
'date_add' => now(),
'date_upd' => now()
];
}
} else {
$data = [];
}
$field_mapping = DB::connection($db_name)->table($db_name . ".feed_mappings")->insert($data);
}
Now, I don't want to delete existing rows instead I want to update those rows based on the id_feed_mappings. Can you tell how can I do this?
Check if this would work, to update based on id_feed_mappings value, you can use the ->where('id_feed_mappings', '=' ,'a value or variable') before ->update($data)
if( $request->feed_type !== 'scrape' ) {
// try using update instead of insert
$field_mapping = true;
if( $request->feed_type !== 'scrape' ) {
if( count($projectFieldOptions) ) {
foreach ($projectFieldOptions as $mapping) {
$data[] = [
'id_feed' => $id_feed,
'id_project' => $token,
'import_field_slug' => $mapping['value'],
'internal_field_slug' => $mapping['custom'] ? $mapping['custom_field'] : $mapping['text'],
'custom_field' => $mapping['custom'],
'updates' => $mapping['updates'],
'removes' => $mapping['removes'],
'import' => 1,
'date_add' => now(),
'date_upd' => now()
];
}
} else {
$data = [];
}
$field_mapping = DB::connection($db_name)->table($db_name . ".feed_mappings")->update($data);
}
this my code cause the trouble,
$cust = Customer::where('name', '=', $data[$i][0]['customer_name'])
->pluck('customer_id')[0];
this one for get customer id when i do store to sales order
$sales = array(
'customer_id' => Customer::where('name', '=', $data[$i][0]['customer_name'])->pluck('customer_id')[0],
'logistics_id' => Logistic::where('logistics_name', '=', $data[$i][0]['logistics'])->pluck('logistics_id')[0],
'subtotal' => $data[$i][0]['subtotal_rp'],
'shipping_cost' => $data[$i][0]['shipping_cost_rp'],
'discount_code' => 0,
'date_of_sales' => $data[$i][0]['date'],
'grand_total' => $data[$i][0]['grand_total_rp'],
'tax' => $data[$i][0]['tax_rp'],
'status' => $data[$i][0]['status'],
'discount_amount' => $data[$i][0]['discount_amount_rp']
);
$store_so = SalesOrder::create($sales);
but, when i do dd(), i get the right data
First of all, you need to check if the $data variable returns the data as you expect.
dd($data);
Next, you need to check that the $data array has the number of elements according to $total_data.
dd(count($data) == $total_data));
So basically, you just need to give condition or try-catch (recommended) :
if (isset($data[$i][0])) {
$customer = Customer::where('name', $data[$i][0]['customer_name'])->first();
$logistic = Logistic::where('logistics_name', $data[$i][0]['logistics'])->first();
if(!$customer){
dd('No customer found!');
}
if(!$logistic){
dd('No logistic found!');
}
$sales = [
'customer_id' => $customer->customer_id,
'logistics_id' => $logistic->logistics_id,
'subtotal' => $data[$i][0]['subtotal_rp'],
'shipping_cost' => $data[$i][0]['shipping_cost_rp'],
'discount_code' => 0,
'date_of_sales' => $data[$i][0]['date'],
'grand_total' => $data[$i][0]['grand_total_rp'],
'tax' => $data[$i][0]['tax_rp'],
'status' => $data[$i][0]['status'],
'discount_amount' => $data[$i][0]['discount_amount_rp'],
];
$store_so = SalesOrder::create($sales);
}
else{
dd('No $data[$i][0] found!');
}
PS : I recommend using the first() method instead of pluck('customer_id')[0].
It seems you need to get a customer_id from a customer_name.
Try to make everything simple:
$sales = array(
'customer_id' => Customer::where('name', $data[$i][0]['customer_name'])->first()->id,
...
);
I filter and list the products listed with the code samples on my model page below with some data from the user.
I want to sort the listed products according to their prices. However, as it is seen in the minprice-maxprice sample code block, relation depends on several conditions.
From the period consisting of postFrom and postTo dates received by the user, if the daily is 0, it should be listed according to the old_daily price, if the daily is not 0, it should be listed according to the daily price.
How can I do that?
my model page
public $belongsTo = [
'price' => [
'ac\prices\models\Price',
'key' => 'id',
'otherKey' => 'pro_id',
],
]
public static $allowedSortingOptions = array (
'name desc' => 'Name - desc',
'name asc' => 'Name - asc',
'price desc' => 'Price - desc',
'price asc' => 'Price - asc',
);
public function scopeListFrontEnd($query, $options = []){
extract(array_merge([
'page' => 1,
'perPage' => 10,
'sort' => 'created_at desc',
'postFrom' => null,
'postTo' => null,
'minPrice' => null,
'maxPrice' => null,
], $options));
if(!is_array ($sort)){
$sort = [$sort];
}
foreach ($sort as $_sort){
if(in_array($_sort, array_keys(self::$allowedSortingOptions))){
$parts = explode(' ', $_sort);
if(count($parts) < 2){
array_push($parts, 'desc');
}
list($sortField, $sortDirection) = $parts;
$query->orderBy($sortField, $sortDirection);
}
}
if($minPrice != null) {
if(!is_array($minPrice)){
$minPrice = [$minPrice];
}
foreach ($minPrice as $mnPrice){
$query->whereHas('price', function($q) use ($mnPrice,$maxPrice,$postFrom,$postTo){
$q->where('daily', '==', '0')
->where(function( $query ) use ( $mnPrice, $maxPrice ) {
$query->where('old_daily', '>=', $mnPrice);
$query->where('old_daily', '<=', $maxPrice[0]);
});
$q->orWhere('daily', '!=', '0')
->where(function( $query ) use ( $mnPrice, $maxPrice ) {
$query->where('daily', '>=', $mnPrice);
$query->where('daily', '<=', $maxPrice[0]);
});
$q->when($postFrom == '0', function ($sq) {
$sq->where('id', '>', '0');
}, function ($ssq) use ($postFrom, $postTo) {
$ssq->where(function($q) use ($postFrom) {
$q->whereDate('start_date', '<=', $postFrom[0])
->whereDate('end_date', '>=', $postFrom[0]);
})->orWhere(function($q) use ($postTo) {
$q->whereDate('start_date', '<=', $postTo[0])
->whereDate('end_date', '>=', $postTo[0]);
});
});
});
}
}
$lastPage = $query->paginate($perPage, $page)->lastPage();
if($lastPage < $page){
$page = 1;
}
return $query->paginate($perPage, $page);
}
Without trying to decode exactly what you are trying to do here, I would be adding a sub-query select that pulls a sort_price field into the results that you can then orderBy.
$query->selectRaw('CASE WHEN daily = 0 THEN old_daily ELSE daily END as sort_price');
$query->orderByRaw('(SELECT sort_price)');
You can also do this directly in the sort condition as per MYSQL ORDER BY CASE Issue if you don't need this price in your result.
You can do this in the orderByRaw builder method.
I want to create a hashtags system. Currently I have this code:
private function hashtags($post){
$htag = '#';
$arr = explode(" ", $post->description);
$arrc = count($arr);
$i = 0;
while($i < $arrc){
if(substr($arr[$i], 0, 1) === $htag ){
$hash = Hashtag::where('name', ltrim($arr[$i], '#'))
->where('slug', str_slug(ltrim($arr[$i], '#')))
->first();
if(!$hash){
Hashtag::create([
'name' => ltrim($arr[$i], '#'),
'type' => 1,
'slug' => str_slug(ltrim($arr[$i], '#'))
]);
}
$current_hash = Hashtag::where('type', 1)
->where('name', ltrim($arr[$i], '#'))
->first();
\DB::insert('insert into hashtag_post (hashtag_id, post_id) values (' .$current_hash->id. ', ' .$post->id. ')');
}
$i++;
}
}
This code isn't good for me because I prefer use attach method but if I try use $post->hashtags()->attach([1, 2, 3]); or other array which I created with hashtag's id, it display error:
"Call to undefined method App\Post::hashtags()".
My question is:How I can use attach with this example and how I can improve my code. It doesn't look well.
Firstly, your relationships should be public methods.
Secondly, both relationships should be belongsToMany.
Post class
public function hashtags()
{
return $this->belongsToMany(Hashtag::class);
}
Hashtag class
public function posts()
{
return $this->belongsToMany(Post::class);
}
Just an FYI, Laravel comes with helper methods that can reduce how much you have to write e.g. firstOrCreate(). So, this:
$hash = Hashtag::where('name', ltrim($arr[$i], '#'))
->where('slug', str_slug(ltrim($arr[$i], '#')))
->first();
if(!$hash){
Hashtag::create([
'name' => ltrim($arr[$i], '#'),
'type' => 1,
'slug' => str_slug(ltrim($arr[$i], '#'))
]);
}
can become:
$hash = Hash::firstOrCreate(
['name' => ltrim($arr[$i], '#'), 'slug' => str_slug(ltrim($arr[$i], '#'))],
['type' => 1]
);
If I store in DB criterias what I want to use to build and filter queries - how to build query with Laravel Fluent Query Builder? Maybe you can give advice for refactoring this array for adding OR/AND to make complex filter by such conditions? Thanks!
For example if I read from database these criteria and made array:
$array = array(
'0' => array(
'table' => 'users',
'column' => 'name',
'criteria' => 'LIKE'
'value' => 'John'
),
'1' => array(
'table' => 'groups',
'column' => 'name',
'criteria' => 'NOT LIKE'
'value' => 'Administrator'
),
...
)
If you are really set on doing it your way, make a switch statement to set the flag for the index of the array
switch ($query)
{
case 0:
$this->get_data($x);
break;
case 1:
$this->get_data($x);
break;
case 2:
$this->get_data($x);
break;
default:
Return FALSE;
}
public function get_data($x){
$value = DB::table($array[$x]['table'])
->where($array[$x]['name'], $array[$x]['criteria'], $array[$x]['value'])
->get();
Return $value;
}
However, I would not advise this at all. Instead of storing the query filters in an array I feel you should just make them methods in your model. This will help with readability, modularity, and having reusable code.
public function get_user_by_name($name){
$user = DB::table('users')->where('name', 'LIKE', '%'.$name.'%')->get();
return $user;
}
public function get_group_by_name($name, $criteria = 'LIKE'){
$groups = DB::table('groups')->where('name', $criteria, '%'.$name.'%')->get();
return $groups;
}
http://laravel.com/docs/database/fluent