I'm working on a jobber search project online using Laravel 5.5.
In my project I want to make a search to find jobbers who live in a certain area and who perform a certain service, or where only one criteria matches.
I use three models: User, Area and Service.
Here is my search bar: I want to use this search bar to do it
This is the User model:
class User extends Authenticatable
{
use Notifiable, EntrustUserTrait;
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = ['name', 'surname', 'email', 'phone',
'password','type',];
/**
* The attributes that should be hidden for arrays.
*
* #var array
*/
protected $hidden = [ 'password', 'remember_token',];
public function area(): BelongsTo
{
return $this->belongsTo(Area::class);
}
public function service(): BelongsTo
{
return $this->belongsTo(Service::class);
}
}
This is the Service model:
class Service extends Model
{
protected $fillable = ['category_id','name','description'];
public function category(): BelongsTo
{
return $this->belongsTo(Category::class);
}
public function users(): BelongsTo
{
return $this->belongsToMany(User::class, 'service_id');
}
public function jobs()
{
return $this->hasMany('App\Job');
}
}
And this is the Area model:
class Area extends Model
{
protected $fillable = ['town_id', 'name', 'description'];
public function town(): BelongsTo
{
return $this->belongsTo(Town::class);
}
public function user(): BelongsTo
{
return $this->belongsTo(User::class, 'area_id');
}
}
Here is the controller code that did not work for me so far:
public function search(Request $request) {
$service = $request->get('service');
$area = Input::get('area');
if (!(empty($service)) && !(empty($area))) {
$results = User::with(['area', 'service'])
->where('area_id', 'like', "%$area%")
->whereHas('service', function ($query) use ($service) {
$query->where('category_id', $service);
})
->paginate(10);
return view('Search.search', compact('results'));
} elseif (!(empty($service)) && empty($area)) {
$results = User::with(['area', 'service'])
->whereHas('service', function ($query) use ($service) {
$query->where('category_id', $service);
})
->paginate(10);
return view('Search.search', compact('results'));
} elseif (empty($service) && !empty($area)) {
$results = User::with(['area', 'service'])
->where('area_id', 'like', "%$area%")
->paginate(10);
return view('Search.search', compact('results'));
}
}
I would advice you to build your query dynamically depending on the available input. This reduces your code and makes sure you will not have to add new code in multiple places should you extend your search in future.
public function search(Request $request)
{
$query = User::with(['area', 'service']);
if ($request->filled('service')) {
$query = $query->whereHas('service', function ($q) use ($request) {
$q->where('category_id', $request->get('service'));
});
}
if ($request->filled('area')) {
$query = $query->where('area_id', $request->get('area'));
}
$results = $query->paginate(10);
return view('Search.search', compact('results'));
}
As long as you don't call get(), paginate() or find() on the $query, it will be a Illuminate\Database\Eloquent\Builder object. This means you can add additional conditions on the query which will all be included in the actual SQL query and are not performed in-memory (which you clearly don't want).
The method $request->filled('service') will check both of the following two conditions:
$request->has('service')
!empty($request->get('service'))
If you want to be able to search Areas by name, you might need to change the if($request->filled('area')) { ... } part to the following:
if ($request->filled('area')) {
$query = $query->whereHas('area', function ($q) use ($request) {
$q->where('name', 'like', '%'.$request->get('area').'%');
});
}
Related
In my Laravel 6.x project I have Product model, Warehouse and WarehouseProduct models.
In the Product I store the base information of my products. In the WarehouseProduct I store the stock amount informations about products in warehouse. Of course I have many warehouses with many products.
My Product looks like this:
class Product extends Model
{
protected $fillable = [
'name',
'item_number',
// ...
];
}
The Warehouse looks like this:
class Warehouse extends Model
{
protected $fillable = [
'name',
'address',
// ...
];
public function products() {
return $this->hasMany(WarehouseProduct::class);
}
public function missingProduct() {
// here I need to return a Product collection which are not in this Warehouse or the
// stored amount is 0
}
}
Finally the WarehouseProduct looks like this:
class WarehouseProduct extends Model
{
protected $fillable = [
'product_id',
'warehouse_id',
'amount',
// ...
];
public function product() {
return $this->belongsTo(Product::class, 'product_id');
}
public function warehouse() {
return $this->belongsTo(Warehouse::class, 'warehouse_id');
}
How can I get a Product collection which are not stored in a Warehouse or the amount is 0?
Something like this should work:
use App\Product;
public function missingProduct() {
$excludedProducts = $this->products()->where('amount', '>', 0)->pluck('id');
return Product::whereNotIn('id', $excludedProducts)->get();
}
Based on #KarolSobański's solution, when you add a warehouse_products relation to your product model:
use App\Product;
use Illuminate\Database\Eloquent\Builder;
public function missingProduct() {
return Product::whereDoesntHave('warehouse_products', function (Builder $query) {
$query->where('warehouse_id', $this->id);
})->orWhereHas('warehouse_products', function (Builder $query) {
$query->where('warehouse_id', $this->id);
$query->where('amount', 0);
})->get();
}
The shortest answer might be similar to this:
Product::doesntHave('warehouse_products')
->orWhereHas('warehouse_products', function (Builder $query) {
$query->where('amount', '=', 0)
})->get();
Although I am not sure if the above works.
But the following longer query certainly resolves the issue:
Product::where(function ($query) {
$query->doesntHave('warehouse_products');
})->orWhere(function ($query) {
$query->whereHas('warehouse_products', function (Builder $query) {
$query->where('amount', '=', 0);
});
})->get();
I'm getting the following error whenever i go on to a users page, its supposed to show if the authenticated user is already following the user that the profile is on.
Could this be a problem with the relationship setup, it hasMany
Stack trace
local.ERROR: Call to a member function addEagerConstraints() on
boolean {"userId":1,"email":"fakeemail#aol.com","exception":"[object]
(Symfony\Component\Debug\Exception\FatalThrowableError(code: 0):
Call to a member function addEagerConstraints() on boolean at
/Applications/MAMP/htdocs/elipost/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Builder.php:522)"}
[]
UserController.php
public function getProfile($user)
{
$users = User::with([
'posts.likes' => function($query) {
$query->whereNull('deleted_at');
$query->where('user_id', auth()->user()->id);
},
'follow',
'follow.follower'
])->with(['followers' => function($query) {
$query->with('follow.followedByMe');
$query->where('user_id', auth()->user()->id);
}])->where('name','=', $user)->get();
$user = $users->map(function(User $myuser){
return ['followedByMe' => $myuser->followers->count() == 0];
});
if (!$user) {
return redirect('404');
}
return view ('profile')->with('user', $user);
}
MyFollow(model)
<?php
class MyFollow extends Model
{
use SoftDeletes, CanFollow, CanBeFollowed;
protected $fillable = [
'user_id',
'followable_id'
];
public $timestamps = false;
protected $table = 'followables';
public function follower()
{
return $this->belongsTo('App\User', 'followable_id');
}
public function followedByMe()
{
return $this->follower->getKey() === auth()->id();
}
}
MyFollow
use Overtrue\LaravelFollow\Traits\CanFollow;
use Overtrue\LaravelFollow\Traits\CanBeFollowed;
class MyFollow extends Model
{
use SoftDeletes, CanFollow, CanBeFollowed;
protected $fillable = [
'user_id',
'followable_id'
];
public $timestamps = false;
protected $table = 'followables';
public function follower()
{
return $this->belongsTo('App\User', 'followable_id');
}
public function followedByMe()
{
return $this->follower->getKey() === auth()->id();
}
}
Post
class Post extends Authenticatable
{
protected $fillable = [
'title',
'body',
'user_id',
'created_at',
];
public function user()
{
return $this->belongsTo(User::class);
}
public function comments()
{
return $this->hasMany('App\Comment');
}
public function likes()
{
return $this->hasMany('App\Like');
}
public function likedByMe()
{
foreach($this->likes as $like) {
if ($like->user_id == auth()->id()){
return true;
}
}
return false;
}
}
Likes
<?php
namespace App;
use App\Post;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
class Like extends Model
{
use SoftDeletes;
protected $fillable = [
'user_id',
'post_id'
];
}
User(model)
class User extends Authenticatable
{
use Notifiable,CanFollow, CanBeFollowed;
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = [
'name', 'email', 'password',
];
/**
* The attributes that should be hidden for arrays.
*
* #var array
*/
protected $hidden = [
'password', 'remember_token',
];
public function posts()
{
return $this->hasMany(Post::class);
}
public function images()
{
return $this->hasMany(GalleryImage::class, 'user_id');
}
public function likes()
{
return $this->hasMany('App\Like');
}
public function follow()
{
return $this->hasMany('App\MyFollow');
}
public function comments()
{
return $this->hasMany('App\Comment');
}
}
As Jonas Staudenmeir stated, followedByMe isn't a relationship, it's a regular function and what it does is returning a boolean. I'm confused at why you've got a follow on your user model and trying to get information from the follow's follower? Just simplify, I see too much unneeded eager loading here.
Searching by indexed elements (id) > searching by name, any day of the week
Edit:
UserController
public function getProfile(Request $request, $id)
{
//$request->user() will get you the authenticated user
$user = User::with(['posts.likes','followers','follows','followers.follows'])
->findOrFail($request->user()->id);
//This returns the authenticated user's information posts, likes, followers, follows and who follows the followers
//If you wish to get someone else's information, you just switch
//the $request->user()->id to the $id if you're working with id's, if you're
//working with names, you need to replace findOrFail($id) with ->where('name',$name')->get() and this will give you
//a collection, not a single user as the findOrFail. You will need to add a ->first() to get the first user it finds in the collection it results of
//If you're planning on getting an attribute (is_following = true) to know if
//the authenticated user is following, you can use an accessor in the User model and write this after you've fetched the instance of the User
//$user->append('is_following');
return view ('profile')->with('user', $user);
}
User Model
//Accessor
//People who this user follows
public function getIsFollowingAttribute()
{
return MyFollow::where('followable_id',$this->attributes['id'])->where('user_id',Auth()->user()->id)->count() > 0 ? true : false;
}
//Relationships
//People who this user follows
public function follow()
{
return $this->hasMany('App\MyFollow','user_id','id');
}
//People who follows this user
public function followers()
{
return $this->hasMany('App\MyFollow','followable_id','id');
}
//Posts of this user
public function posts()
{
return $this->hasMany('App\Post','user_id','id');
}
//Likes of this user, not sure about this one tho, we're not using this for now but it could come in handy for you in the future
public function likes()
{
return $this->hasManyThrough('App\Likes','App\Post','user_id','user_id','id');
}
Post Model
//Who like this post
public function likes()
{
return $this->hasMany('App\Post','user_id','id');
}
MyFollow Model
//Relationships
//People who follow this user
public function followers()
{
return $this->hasMany('App\MyFollow','followable_id','user_id');
}
//Relationships
//People who this user follows
public function follow()
{
return $this->hasMany('App\MyFollow','user_id','followable_id');
}
With the help of #abr i found a simple fix, simple solution.
MyFollow.php(model)
public function followers()
{
return $this->hasMany('App\MyFollow','followable_id','user_id');
}
//Relationships
//People who this user follows
public function follow()
{
return $this->hasMany('App\MyFollow','user_id','followable_id');
}
User.php(model)
public function getIsFollowingAttribute()
{
return MyFollow::where('followable_id',$this->attributes['id'])->where('user_id',Auth()->user()->id)->count() > 0 ? true : false;
}
public function follow()
{
return $this->hasMany('App\MyFollow');
}
UserController.php
public function getProfile($user)
{
$users = User::with(['posts.likes' => function($query) {
$query->whereNull('deleted_at');
$query->where('user_id', auth()->user()->id);
}, 'followers','follow.followers'])
->with(['followers' => function($query) {
}])->where('name','=', $user)->get();
$user = $users->map(function(User $myuser){
$myuser['followedByMe'] = $myuser->getIsFollowingAttribute();
return $myuser;
});
if(!$user){
return redirect('404');
}
return view ('profile')->with('user', $user);
}
it works now. :)
I'm trying to build a small application in laravel 5.4 where I'm having a contacts table, companies table, interactions table and users table each with their respective models. An Interaction is being created by the User where there are client_contact, contact, user participating. Each client_contact and contact shares the same model and belongs to a company which have type in their column for example Investor, Research, Corporate etc. Now I'm trying to generate a report where interaction done by a user with Investors. First of all let me show you my models:
User Model:
class User extends Authenticatable
{
use HasApiTokens, Notifiable, SoftDeletes;
public function interactions()
{
return $this->hasMany('App\Interaction');
}
public function clients()
{
//Each user has been assigned a particular client
return $this->belongsToMany('App\Company', 'company_user', 'user_id', 'company_id');
}
}
Contacts Model:
class Contact extends Model
{
use SoftDeletes, DataViewer;
public function company()
{
return $this
->belongsToMany('App\Company', 'company_contact','contact_id', 'company_id')->withTimestamps();
}
public function interactions()
{
return $this->belongsToMany('App\Interaction', 'contact_interaction','contact_id', 'interaction_id');
}
public function clientInteractions()
{
return $this->belongsToMany('App\Interaction', 'contact_client_interaction','contact_id', 'interaction_id');
}
}
Company Model:
class Company extends Model
{
use SoftDeletes, DataViewer;
public function contacts()
{
return $this->belongsToMany('App\Contact', 'company_contact', 'company_id','contact_id');
}
public function users()
{
return $this->belongsToMany('App\User', 'company_user', 'company_id', 'user_id')->withTimestamps();
}
}
Interaction Model:
class Interaction extends Model
{
use SoftDeletes;
public function stellarParticipants()
{
return $this->belongsToMany('App\User')->withTimestamps();
}
public function clientsAssociation()
{
return $this->belongsToMany('App\Contact', 'contact_client_interaction', 'interaction_id', 'contact_id')->withPivot('company_id')->withTimestamps();
}
public function contactsAssociation()
{
return $this->belongsToMany('App\Contact', 'contact_interaction', 'interaction_id', 'contact_id')->withPivot('company_id')->withTimestamps();
}
public function user()
{
return $this->belongsTo('App\User');
}
}
Now in my ReportController: I'm doing something like this:
public function getAnalystInvestor(Request $request)
{
$user = User::find($request->id);
$interactions = Interaction::whereHas('contactsAssociation', function ($query3) {
$query3->whereHas('company', function ($query4) {
$query4->where('type', 'like', '%'.'Investor'.'%');
});
})->whereHas('user', function ($query1) use($user) {
$query1->where('name', '=', $user->name);
})->orWhereHas('stellarParticipants', function ($query2) use($user) {
$query2->where('name', '=', $user->name);
})
->orderBy('created_at', 'desc')
->take(50)
->with(['contactsAssociation', 'clientsAssociation', 'stellarParticipants'])
->get();
return response()->json(['interactions' => $interactions], 200);
}
But I'm unable to get the desired results, still some of the data are displaying which is not investors. I also tried:
$interactions = Interaction::whereHas('user', function ($query1) use($user) {
$query1->where('name', '=', $user->name);
})->orWhereHas('stellarParticipants', function ($query2) use($user) {
$query2->where('name', '=', $user->name);
})->whereHas('contactsAssociation', function ($query3) {
$query3->whereHas('company', function ($query4) {
$query4->where('type', 'like', '%'.'Investor'.'%');
});
})
Where user filters are assigned first but its not displaying as desired. Help me out with this.
You should be able to chain your query, similar to this:
$cfs = \App\Service::with('items', 'required_services', 'supported_services')
->where(function ($query) {
$query->where('stm', 11)
->orWhere('stm', 17)
->orWhere('stm', 31);
})
->where('lifecycle_id', '!=', 12)
->where('type', 'Customer Facing')
->orderBy('service_full_name')
->get();
I don't really understand the report you are developing, but hopefully this helps you.
I have two tables
table 1 = NewsCollection
table 2 = NewsConllectionTranslation
here is the models
NewsCollection
class NewsCollection extends \Eloquent
{
use \Dimsav\Translatable\Translatable;
public $translatedAttributes = ['title', 'content'];
public $translationModel = 'NewsCollectionTranslation';
public function newsTrans()
{
return $this->hasMany('NewsCollectionTranslation', 'news_collection_id');
}
}
NewsConllectionTranslation
class NewsCollectionTranslation extends \Eloquent
{
public $timestamps = false;
protected $table = 'news_collection_translations';
protected $fillable = ['title', 'content'];
public function transNews()
{
return $this->belongsTo('NewsCollection', 'news_collection_id');
}
}
and here is the show controller
public function show($title)
{
$news = NewsConllectionTranslation::with('newsTrans')->where('title', $title)->first();
return View::make('portal.news.show', compact('news'));
}
What I need to do is
->where('title', $title)->first();
should be selected from NewsConllectionTranslation and I don't want to lose the translation so I don't want to select from NewsConllectionTrnslation first
You should try this:
$news = NewsConllectionTranslation::whereHas('newsTrans', function ($query) use ($title) {
$query->where('title', $title);
})->first();
Change your function like this
public function show($title)
{
$news = NewsConllectionTranslation::with(['newsTrans' => function ($query) use($title) {
$query->where('title', $title)->first();
}])
return View::make('portal.news.show', compact('news'));
}
I am using Laravel 5.2 ,how to write this query?
There are two tables,user and articles,they have a one-to-many relationship.
I want to query users according to these conditions:
1、Show users who have articles,not show users who have not articles.
2、Articles contain two types,published and not published, "1" indicates published,show published articles ,not show articles which not published.
3、30 users are shown per page.
Like this, it's not right ,how to modify it?
HomeController:
public function index()
{
$users = User::with('articles')->where('is_published','=',1)->paginate(30);
return view('index', compact('users'));
}
User:
class User extends Model implements AuthenticatableContract, CanResetPasswordContract, HasRoleAndPermissionContract
{
use Authenticatable, CanResetPassword, HasRoleAndPermission;
protected $fillable = [
'name', 'email', 'password',
];
protected $hidden = [
'password', 'remember_token',
];
public function articles()
{
return $this->hasMany(Article::class);
}
}
Article:
class Article extends Model
{
public function user()
{
return $this->belongsTo(User::class);
}
//edit-1:
//Scope a query to only include status=1.
public function scopeStatus($query)
{
return $query->where('status',1);
}
}
edit:
#SSuhat #RamilAmr Thanks! If there is a Local Scope in Model "Article",how to modify the answer:
$query = User::with(['articles' => function ($q) {
$q->where('is_published', 1);
}])
->has('articles') //<<<<<<<<<
->paginate(30);
return $query;
Try this:
$query = User::with(['articles' => function ($q) {
$q->where('is_published', 1);
}])->paginate(30);
return $query;
if the user has not any articles,the user will not be shown,how to filter?
Try this code:
$query = User::with(['articles' => function ($q) {
$q->where('is_published', 1);
}])
->has('articles') //<<<<<<<<<
->paginate(30);
return $query;
$query = User::with('articles')->wherehas('articles', function ($q) {
$q->where('is_published', 1);
})->paginate(30);
return $query;
I hope this helps you.