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.
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();
How can I get the users based on which role they have in laravel? I have roles like for example "admin", "author", "editor" and I want to have a dynamic api-endpoint.
so in my api.php I have:
Route::get('users/{role}', "Api\UserController#role");
and my Controller looks like this:
public function show()
{
$user_role = User::whereHas(
'roles',
function ($q) {
$q->where('name', 'admin');
}
)->get();
return $user_role;
}
This works fine so far, but I want the endpoint to be dynamic, like if want all my editor users the endpoint should be api/users/editors etc. etc.
How can I achieve this?
public function show($role) //example: $role = 'admin'
{
return User::whereHas('roles', function ($q) use ($role) {
$q->where('name', $role);
})->get();
}
Your controller function should look like this:
public function show(Role $role)
{
$users = $role->users;
return $users;
}
And your Role Eloquent Model should have these methods:
public function users()
{
return $this->belongsToMany(User::class, 'user_role')
}
public function getRouteKeyName()
{
return 'name';
}
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
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 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').'%');
});
}