how can fetch value from database - laravel-4

when we can type a letter in textbox.. onkeyup action done. go to search database and than display the corrosponding words below..
eg: i enter A,then display Apple,Ant(my database table contain this words staring letter is A) how can fetch value from database .
my controller.php is
public function executeSearch()
{$keywords=Input::get('keywords');
$users=User::all();
$searchUsers=new\Illuminate\Database\Eloquent\Collection();
foreach($users as $u)
{
if(Str::contains(Str::Lower($u->name),Str::Lower($keywords)))
$searchUsers->add($u);
}
return View::make('searchUsers')
->with('searchUsers',$searchUsers);
}

Simply use SQL's LIKE:
$users = User::query();
foreach($keywords as $keyword){
$users->orWhere('name', 'LIKE', '%'.$keyword.'%');
}
$users = $users->get();
Then pass it to your view:
return View::make('searchUsers')->with('users', $users);
And loop over the results in the view:
#foreach($users as $user)
Name: {{ $user->name }}
#endforeach

Related

Do not display duplicated posts on 2nd loop if 1st loop already displays the same posts in laravel

I'm building a dictionary website with laravel6.
And when a visitor search a keyword, 2 queries will run to find posts.
Controller.php
public function index(Request $request)
{
$keyword = $request->input('keyword');
$query = Post::query();
$query2 = Post::query();
if(!empty($keyword)){
$query->where('word','like','%'.$keyword.'%');
$data = $query->orderby('word', 'DESC')->paginate(4);
$query2->where('definition','like','%'.$keyword.'%');
$data2 = $query2->orderby('definition', 'DESC')->paginate(4);
return view('index')->with(['keyword' => $keyword])->with(['data' => $data])->with(['data2' => $data2]);
}
}
Then, show 1st query & 2nd query result.
index.blade.php
#foreach($data as $val)
<div class="post">
<h2>{{$val->word}}</h2>
<p>{{$val->definition}}</p>
</div>
#endforeach
#foreach($data2 as $val2)
<div class="post">
<h2>{{$val2->word}}</h2>
<p>{{$val2->definition}}</p>
</div>
#endforeach
The problem is, 2nd loop ($data2) shows duplicate posts of $data.
So how can I not display duplicate posts on $data2 loop?
I tried like:
#foreach($data2 as $val2)
#if($val2->id !== $val->id)
<div class="post">
<h2>{{$val2->word}}</h2>
<p>{{$val2->definition}}</p>
</div>
#endif
#endforeach
But didn't work. Appreciate any suggestion.
If you use the pagination for queries the only solution is to implement code in the controller. In the second foreach of the view it is not possible to know all the values of the first foreach.
If I understand your question correctly, you can change your approach and use a single query.
In the controller you can write a query more or less like this:
$data = Post::select('word', 'definition')
->where(function ($query) use ($keyword) {
$query->where('word', 'like', '%' . str_replace(' ', '%', $keyword) . '%')
->orWhere('definition', 'like', '%' . str_replace(' ', '%', $keyword);
})
->paginate(4);
You have no duplicate posts and you can also search with multiple words separated by a space (for multiple search the order of words must be that of the text).
EDIT:
This the solution with two query. The first query rest the same, the second query is filtered by the id list of the first query:
$listDataId = Post::where('word','like','%'.$keyword.'%')>orderby('word', 'DESC')->get()->pluck('id');
$query2->where('definition','like','%'.$keyword.'%');
$data2 = $query2->whereNotIn('id', listDataId)->orderby('definition', 'DESC')->paginate(4); // whereNotIn exclude the first query value
You can also do that with laravel's collection. As you might have noticed each query in laravel is a collection, so you can play with collections like you can search here https://laravel.com/docs/7.x/collections#method-merge
public function index(Request $request)
{
$keyword = $request->input('keyword');
$query = Post::query();
$query2 = Post::query();
if(!empty($keyword)){
$query->where('word','like','%'.$keyword.'%');
$data = $query->orderby('word', 'DESC')->paginate(4);
$query2->where('definition','like','%'.$keyword.'%');
$data2 = $query2->orderby('definition', 'DESC')->paginate(4);
//collection starts here.
//It will replace duplicate keys and will give you one collection
$merged = $data->merge($data2);
//Now you will have only one foreach loop in the view.
return view('index')->with(['keyword' => $keyword])->with(['data' => $merged]);
}
}
You can use the following query
$query2->where('definition','like','%'.$keyword.'%')->where('word','not like','%'.$keyword.'%')

How to search in multi column?

I need to search in users table with the name and if there no match with any name in table transfer into category table which has relation with each one of user.
the code of html:
<form action="{{ route('search') }}" method="GET">
<input type="search" class="input" name="q" placeholder="Search">
</form>
Controller code (my shut):
public function search(Request $request)
{
$users = new User;
$req = $request->input('q');
$users = $users->where('name','LIKE','%'. $req .'%')->whereHas('category', function ($query) use($req) {
$query->where('name','LIKE','%'. $req .'%');
});
$users = $users->unverified()->active()->orderBy('id','desc')->paginate(16);
return view('frontend.search.search', compact('users'));
}
category has relation with user:
public function category()
{
return $this->belongsTo('App\Category');
}
I need to say if there is no name ( users table ) check the category one.
You will need to use a orWhere method, which means or do the other. To avoid weird logic it is the easiest approach to wrap it in a where closure.
$users = User::where(function ($query) use($req) {
$query->where('name','LIKE','%'. $req .'%')
->orWhereHas('category', function ($query) use($req) {
$query->where('name','LIKE','%'. $req .'%');
});
});
This means your code will find elements with the name or with the given category. There is an edge case where it will find by the category name even if user is set. But avoiding that, is not as straight forward as this.

How to display records in view based on their first letter?

In my controller I am passing to a view a bunch of categories in alphabetical order like this :
public function index()
{
$categories = Category::orderBy('name', 'asc')->get();
return view('categories')->with('categories',$categories);
}
In my view, I want to display in separate columns corresponding to letters from the alphabet each of these categories, so in column "A" I will have all categories starting with A and so on.
Is it possible to filter the results in the view by letter in order to achieve this, and if yes, how can it be done?
You can group the list of categories by first letter in your controller and then pass the result to your view, here is how to do:
Controller:
public function index() {
$categories = Category::orderBy('name', 'asc')->get();
$groups = $categories->reduce(function ($carry, $category) {
// get first letter
$first_letter = $category['name'][0];
if ( !isset($carry[$first_letter]) ) {
$carry[$first_letter] = [];
}
$carry[$first_letter][] = $category;
return $carry;
}, []);
return view('categories')->with('groups', $groups);
}
View:
#foreach($groups as $letter => $group)
<ul>
<li>{{ $letter }}</li>
#foreach($group as $category)
<li>{{ $category['name'] }}</li>
#endforeach
</ul>
#endforeach
Here is a working example using array_reduce (it's the same as Collection::reduce function above)
In your view instead of using foreach use for and conditionally check the first letter of every current item with the first character of its previous item:
<h4>{{$categories[0]->name[0]}}</h4>
#for($i = 0; $i < count($categories); $i++)
#if($i > 0 && $categories[$i]->name[0] != $categories[$i-1]->name[0])
<h4>{{$categories[$i]->name[0]}}</h4>
#endif
.....
#endfor
Another fact used in this solution that you can access a character in a string by its index in that string. i.e we accessed the first character by its index 0 in the category name string.
If you want to load from database only categories with a specified first letter:
$categories = Category::where('name', 'like', 'A%')->orderBy('name', 'asc')->get();
If you want to load all categories and then filter them, use filter() method:
#foreach ('ABCDEFGHIJKLMNOPQRSTUVWXYZ' as $letter)
#foreach ($categories->filter(function($i) use($letter) { return starts_with($i->name, $letter); }) as $category)
{{ $category->name }}
#endforeach
#endforeach

How to pass variable from foreach to view in laravel 5.4?

I want to count each location in my Job table by using location_id in my job table with id in location table. below code, I can count result correctly but I don't know how to pass this variable to the view. Please help?
//my code
public function index(){
$location = Location::all();
$count_location = [];
foreach ($location as $locations){
$count_location = Job::where('location_id', $locations->id)->count();
}
}
Use withCount() and view() to pass location with counted jobs to the view:
public function index(){
return view('view.name', [
'locations' => Location::withCount('jobs')->get()
]);
}
In the view:
#foreach ($locations as $location)
{{ $location->name }} has {{ $location->jobs_count }} jobs
#endforeach
You can return the collection of locations to the view and then loop through each object in the collection like so:
return view('index', [
'locations'=> $locations,
]);
Then in your index.blade.php you can use something like a #foreach or #forelse loop
#foreach ($locations as $location)
{{ $location->id }}
#endfoeach
EDIT
From the looks of it you would be better off defining a relationship between locations and jobs (i.e. a "many to many" or "one to many" relationship). this would allow you to get the counts for jobs at given locations very easily like so:
$location->jobs->count()
Eloquent relationships are explained in the documentation here
https://laravel.com/docs/5.5/eloquent-relationships
It would be more efficient if construct your query to fetch the count of related models instead of looping through all the results.
Have a look at Counting Related Models in the documentations.
For example, to get the count of all jobs related to a location, you could do:
$locations = App\Location::withCount('jobs')->get();
foreach ($locations as $location) {
echo $location->jobs_count;
}
You need to adjust the code according to your models structure.
Do this
public function index(){
$locations = Location::all();
return view('index', compact('locations'));
}
In your Location model make a relationship by adding this
public function jobs(){
return $this->hasMany(Job::class);
}
In your index view do this
#foreach ($locations as $location)
{{$location->jobs->count}}
#endforeach
Please note that Job should be there in your your model

Laravel conditional on relation: return first()

I have a Laravel 5.2 one-to-many relation and I want to return the model and put a condition to relation.
I've tried this:
$categories = Category::with(['descriptions' => function($d) use ($default_language) {
$d->where('language_id', $default_language->id);
}])->get();
It work fine, I just want something else: the relation should not be a collection or array, just a simple object. I want to do something like
$d->where('language_id', $default_language->id)->first();
, just in this case first() is not working. Any ideas?
EDIT
Actually first() is not working properly, it returns first description just for the first object returned, for others it return nothing.
Try this:
$categories = \Jobinja\CMS\Blog\Models\Category::with([
'descriptions' => function ($q) use ($defaultLanguage) {
return $q->where('language_id', $defaultLanguage->id)->take(1);
}
])
->get()
->map(function ($item) {
if ($item->descriptions->isEmpty() === false) {
$item->description = $item->descriptions->first();
}
return $item;
});
and get to description:
foreach ($categories as $category) {
$description = $category->description;
}
You can't do that but you can use first() on a collection later, for example in a view:
#foreach ($categories as $category)
{{ $category->descriptions->first()->name }}
#endforeach
I can say to use instead of first() find() and give it the language_id or $default_language->id and this will try to find in the table first the column id and assign the value. If you have different id column name give it to the find like find(['your_column_name' => '<your_value']).
If you want array to something like ->toArray(). You can test different scenarios in tinker. php artisan tinker
Here is a link to document this -> https://laravel.com/docs/5.3/eloquent#retrieving-single-models

Resources