Laravel 5.4: search by tag - php

This works fine but what I want to know is if there is a better way to do a search for tags in Laravel. Thanks.
Tag model:
class Tag extends Model
{
public function noticias()
{
return $this->morphedByMany('App\Models\Noticia', 'taggable');
}
// ...
}
Noticia model:
class Noticia extends Model
{
public function tags()
{
return $this->morphToMany('App\Models\Tag', 'taggable');
}
// ...
}
SearchController
public function tag($id){
$noticias= Noticia::all();
$data['noticias'] = [];
foreach($noticias as $value){
foreach($value->tags as $tag){
if($tag->id == $id){
$data['noticias'][] = $value;
}
}
}
return view('web.buscar.index');
}

use whereHas()
$noticias= Noticia::with('tags')->whereHas('tags', function($q) use ($id){
$q->where('id',$id);
})->get();
To get only ids use pluck()
$noticias= Noticia::whereHas('tags', function($q) use ($id){
$q->where('id',$id);
})->pluck('id');

Try this,
public function tag($id){
$noticicas = Noticia::has(['tags'=> function($query) use($id){
return $query->where('id',$id);
}])->get();
dd($noticicas);
//you can also, get the tag with the id you send, and then get all the `Noticias` for it
$tag = Tag::find($id);
$noticias = $tag->noticias->with(["tags"]); // the with is in case you want to show all the tags from the news
}

Related

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

Laravel "nested" with()

I have 3 models: Article, Comment, Reaction.
Each article has many comments, and each comment has many reactions:
App\Article:
class Article extends Model
{
public function comments() {
return $this->hasMany('App\Comment');
}
}
App\Comment:
class Comment extends Model
{
public function article() {
return $this->belongsTo('App\Article');
}
public function reactions() {
return $this->hasMany('App\Reactions');
}
}
App\Reaction:
class Reaction extends Model
{
public function comment() {
return $this->belongsTo('App\Comment');
}
}
In my ArticleController#index I want to fetch comments and their reactions:
ArticleController:
public function index()
{
$articles = Article::with('comments')
->select('articles.*')
->leftjoin('comments', 'comments.article_id', '=', 'articles.id')
->get();
return view('wiki')->withArticles($articles);
}
I can loop through the comments ($article->comments), however I'm not sure how to do a with('reactions') for the comments? i.e.,
#foreach($article->comments as $comment)
#foreach($comment->reactions)
// something like this...
#endforeach
#endforeach
you can do Nested Eager Loading
$article = Article::with('comments.reactions')
->leftjoin('comments', 'comments.article_id', '=', 'articles.id')
->select('articles.*')
->get();
You can also do this way
ArticleController:
public function index()
{
$articles = Article::with('comments')
->select('articles.*')
->get();
return view('wiki')->withArticles($articles);
}
App\Article:
class Article extends Model
{
public function comments() {
return $this->hasMany('App\Comment')->with('reactions');
}
}
App\Comment:
class Comment extends Model
{
public function article() {
return $this->belongsTo('App\Article');
}
public function reactions() {
return $this->hasMany('App\Reactions');
}
}

Laravel Eloquent - list of parent from a collection

I can get the list of Likes that User 1 did on a Media from Store 1
$medias = User::find(1)->likes()->with('media')->whereHas('media', function($q) {
$q->where('store_id', '=', 1);
})->get();
But i need to retrieve the list of medias, so i tried
$medias = User::find(1)->likes()->with('media')->whereHas('media', function($q) {
$q->where('store_id', '=', 1);
})->get()->media;
But then i get
Undefined property: Illuminate\Database\Eloquent\Collection::$media
class User extends Model
{
public function likes()
{
return $this->hasMany('App\Like');
}
}
class Media extends Model
{
public function store()
{
return $this->belongsTo('App\Store');
}
public function likes()
{
return $this->hasMany('App\Like');
}
}
class Like extends Model
{
public function user()
{
return $this->belongsTo('App\User');
}
public function media()
{
return $this->belongsTo('App\Media');
}
}
This is because you get media separate for each like. You should use:
$likes = User::find(1)->likes()->with('media')->whereHas('media', function($q) {
$q->where('store_id', '=', 1);
})->get();
foreach ($likes as $like) {
$media = $like->media;
// now you can do something with your media
}
EDIT
If you want to get only media, you should add to your User model the following relationship:
public function medias()
{
return $this->hasManyThrough('App\Media','App\Like');
}
Now to get your media, you should do :
$medias = User::find(1)->medias()->where('store_id', '=', 1)->get();
Made it work with
$store->medias()->whereHas('likes', function($q) use($user) {
return $q->where('user_id', '=', $user->id);
});

Laravel 4.1 eager loading

I'm having trouble on the eager loading.
Let's say I have models of Members, TrainingCategory, TrainingCategoryResult and Registration
Member Model:
public function registration() {
return $this->hasMany('Registration', 'member_id');
}
public function trainingResults(){
return $this->hasMany('trainingResult', 'member_id');
}
public function trainingCategoryResults() {
return $this->hasMany('TrainingCategoryResult', 'member_id');
}
TrainingCategory Model:
public function trainings() {
return $this->hasMany('Training', 'id');
}
public function trainingCategoryResults() {
return $this->hasMany('trainingCategoryResult', 'category_id');
}
TraningCategoryResult Model:
public function category() {
return $this->belongsTo('TrainingCategory', 'id');
}
public function member() {
return $this->belongsTo('Member', 'id');
}
Registration Model:
public function course() {
return $this->belongsTo('Course', 'course_id');
}
public function member() {
return $this->belongsTo('Member', 'id');
}
I am trying to eager load all the registration info and its related info including the TraningCategoryResult info but I not sure how to get that TraningCategoryResult which required two foreign keys (category_id and member_id), is there any way to do that?
Here is my code atm:
$members= Member::where(function($query) use ($id, $site) {
$query
->where('id', '=', $id)
->where('site', '=', $site);
});
$members= $members
->with('registration.course',
'registration.course.traningCategories',
->get(['member.id']);
Thank you.
This will not work Member::with('categoryResult')->with('registration')->get()
You can make a new relation in Member Model
public function categoryResult()
{
return $this->belongsTo('Category')->with('Registration');
}
//and then call
Member::with('categoryResult')->get();
You could use a few options to achieve that:
OPTION 1: create a variable relationship
Change your relation in the Member model
public function trainingCategoryResults($category_id = null) {
if(empty($category_id))
return $this->hasMany('TrainingCategoryResult', 'member_id');
else
return $this->hasMany('TrainingCategoryResult', 'member_id')
->where('category_id', $category_id);
}
The code above might have limitations and it doesn't take advantage of many laravel features, but it will work.
OPTION 2: Access from relationship
You can keep everything as is, and load as follow:
$members= Member::where(function($query) use ($id, $site) {
$query
->where('id', '=', $id)
->where('site', '=', $site);
})
->where('id', $member_id) // set the id of the memeber
->with(array(
'traningCategoryResults' => function($q)use($category_id){
$q->where('category_id', $category_id); // This makes sure you get only desired results
}
))
In this way you will have only what you need, assuming you know the $category_id

Laravel - search by title?

How to search by title in the ServiceType only? There is also a title field in the Package which should be avoided
For example, in the Model:
class Package extends Eloquent {
protected $table = 'package';
function serviceType()
{
return $this->belongsTo('ServiceType');
}
public static function getPackagesByServiceType($service)
{
return Package::with('serviceType')->where('title', '=', $service);
}
}
Note:
There is a service_type_id field in the Package and id, title fields in the serviceType
in the controller:
$packages = Package::getPackagesByServiceType('something')->get();
No result appeared for some reason? It should search for something in the serviceType
It seem it wouldn't work to combine with() and where(). When I remove the where() and it work.
You can't use where() like that to filter by a related model. You should use whereHas() instead:
public static function getPackagesByServiceType($service)
{
return Package::with('serviceType')->whereHas('serviceType', function($q) use ($service){
$q->where('title', '=', $service);
});
}
Note if you don't need serviceType in the packages afterwards you don't have to eager load it, ergo you can remove the with('serviceType')
Also if you call get() in the controller you should use a query scope. It offers the same functionality but it's not a static function and it's the Laravel way
public function scopeByServiceType($query, $service){
return $query->with('serviceType')->whereHas('serviceType', function($q) use ($service){
$q->where('title', '=', $service);
});
}
And you use it like this:
$packages = Package::byServiceType('something')->get();
class Package extends Eloquent {
protected $table = 'package';
function serviceType()
{
return $this->belongsTo('ServiceType');
}
public static function getPackagesByServiceType($service)
{
return Package::with('serviceType')->where('title', '=', $service)->get();
}
}
You forgot the ->get();
The ->get() should be in the Model
public static function getPackagesByServiceType($service)
{
return Package::with('serviceType')->where('title', '=', $service)->get(); // here
}
and in the controller it should be like this:
$packages = Package::getPackagesByServiceType('something');
Hope that helps... I had similar issues in my Model - Controller structure....

Categories