Laravel- Eloquent many to many get unattached data - laravel

I have User, Shop and Product model on my app. And relationship like this:
User
public function products(){
return $this->hasMany("App\Product");
}
public function shops(){
return $this->hasMany("App\Shop");
}
Shop
public function user(){
return $this->belongsTo("App\User");
}
public function products(){
return $this->belongsToMany("App\Product");
}
Product
public function user(){
return $this->belongsTo('App\User');
}
public function shops(){
return $this->belongsToMany("App\Shop");
}
So, user can add Products and Shops and then attach a product to many shop. Now I can get all of the attached shops by $product->shops on product page and auth users all shop by auth()->user()->shops. Actually, I want to show the auth users shop that is not attached to this Product on the Product page. According to Laravel documentation, I write some code but for some reason it doesn't work. My code is :
auth()->user()->shops()->whereDoesntHave('products', function (Builder $query) {
$query->where('id','!=', $product->id);
})->get();
Error:
Any help will be appreciated.
Thanks

Converting comment to an answer here.
Firstly, the usage of function(Builder $query) is targeting the incorrect version of Builder (likely a namespacing issue), so simply removing Builder from the function should allow it to resolve.
Secondly, to use $product in scope of the new function, it needs to be passed use use($product), otherwise you'll get an Undefined variable $product error.
Altogether, the new function should look like this:
auth()->user()->shops()->whereDoesntHave('products', function ($query) use($product) {
$query->where('id','!=', $product->id);
})->get();

Related

How can I paginate Laravel's Eloquent's relationships' relationships?

I have two tables, users and profiles. A user has one profile. Also a user has referrals. The referrals are referenced by the column referrer_id in the users' table. So a user has a referrer, and a user can have many referrals.
Define a one-to-one relationship on the User's Model:
public function profile()
{
return $this->hasOne(Profile::class);
}
Define an inverse one-to-one relationship on the User's Model:
public function referrer()
{
return $this->belongsTo(User::class);
}
Define a one-to-many relationship on the User's Model:
public function referrals()
{
return $this->hasMany(User::class, 'referrer_id');
}
Define an inverse one-to-one or many relationship on the Profile's Model:
public function user()
{
return $this->belongsTo(User::class);
}
I wish to retrieve the user's profile, the user's referrals along with their profiles, and the referrals' referrals along with a count of each of the referrals' referrals.
The following Eloquent query works, but doesn't paginate:
namespace App\Http\Controllers;
class ReferralsController extends Controller
{
public function index(Request $request)
{
return $request->user()->loadMissing(['profile', 'referrals' => function ($query) {
$query->with(['profile', 'referrals'])->withCount('referrals');
}]);
}
}
I've tried to add ->paginate() to the query (on both as show below and also one or the other) but it doesn't work:
return $request->user()->loadMissing(['profile', 'referrals' => function ($query) {
$query->with(['profile', 'referrals'])->withCount('referrals')->paginate(2);
}])->paginate(2);
Adding it to the inner function doesn't do anything, and adding it to the main query just retrieves the entire users table.
EDIT
I've realized that adding ->paginate() to the inner function actually does limit the number of rows in the collection, but there is no Paginator instance anywhere, so I don't have access to any of the links to move pages.
Got it to work by doing it separately:
$profile = $request->user()->profile()
->firstOrFail();
$referralsPaginator = $request->user()->referrals()
->with('profile')
->withCount('referrals')
->paginate(2);

Laravel get value from 2 column with relationship one to one

I have 2 tables and have relationship one to one. Second table use a FK from first one, and I want to display a list with all values .
public function index(Request $request)
{
$listOfPersons = new Person();
$listOfRegisters = new Register();
$listOfRegisters->listOfPersons()->associate();
return $listOfRegisters;
}
In Register Model
public function people(){
return $this->hasOne(Person::class);
}
In Person Model
public function register(){
return $this->hasOne(Register::class);
}
If you just want a list with all pairs of values, it should be enough with this code:
public function index(Request $request)
{
$registers = Register::all();
$list = [];
foreach($registers as $register){
array_push($list,['register'=> $register, 'person'=>$register->people]);
}
return $list;
}
But remember you can just have the list of registers and access the person via the relationship. Moreover, you should change the hasOne relationship to belongsTo in register.
I hope that helps.
I think you have to use leftjoin. (not foreach and php loop)
Because:
The alternative of handling this inside your PHP code with a foreach
loop is unattractive for several reasons. First, you would probably
need to bring in all information from both tables, which is wasteful
from both a memory and network usage point of view. Then, even after
you have brought in the data, you would be relying on PHP to perform
the join. PHP wasn't really designed for in house database operations,
and cannot use something like an index to speed up the process.
So you can write your query like:
User::leftJoin('register', 'register.user_id', '=', 'id');
However, I prefer to add a scope in my model for this situation
<?php
class User extends Authenticatable
{
public function scopeRegister($builder)
{
$query = $query->leftJoin('register', 'register.user_id', '=', 'id');
return $query;
}
and in my controller
public function index(Request $request)
{
$records = User::register()->get();
}

How to return collection in reverse order

In my Conversation model I have
protected $with = ['messages', 'users'];
How would I change the order that it returns the 'messages' to DESC?
Usual Eloquent relationship looks something like this:
class Category extends Model
{
public function products()
{
return $this->hasMany('App\Product');
}
}
So here’s what we should do to automatically order products by title in every query that uses this relationship:
public function products()
{
return $this->hasMany('App\Product')->orderBy('name');
}
That’s it, everything is “in order” now!
Source: https://laraveldaily.com/eloquent-relationships-with-automatic-orderby/
Try this on your controller, it will order messages in descending order
User::with(['messages' => function($query) {
$query->orderBy('id', 'DESC');
}])->get();
for more see documentation

Laravel 5 - Defining Two Relationships Between Models

I'm learning Laravel, and really OOP in general. I've followed several YouTube tutorial series, that teach you to create a blog in Laravel.
I'm building a task app for a brewery, and I'm trying to define the relationships between the users and the tasks. So I have two models: User.php and Task.php. I had no problem defining the user in a hasMany tasks relationship, and reciprocally, a task belongsTo a user. Where I'm confused is that I'd like to also have a user belong to the task as well. I have two MySQL columns, one with the heading of "user_id" and the other with "user_assigned_id". What I want is that a user has many tasks, but a task also has one assigned user, the idea being that the user that created the task might assign the task to another user. I've found several tutorials on creating relationships between three models, such as a user owning several messages, but only having one address, so I figured that I could just treat two models as if they were three models and connected the User model back to the Task model in a hasOne relationship, but I'm having a really hard time passing that through to the Controller and View.
Here is the relevant code in each file:
User.php
public function tasks()
{
return $this->hasMany('App\Task');
}
Task.php
public function user()
{
return $this->belongsTo('App\User');
}
// Added an user_assigned_id relationship
public function user_assigned()
{
return $this->hasOne('App\User', 'name', 'user_assigned_id');
}
DashboardController.php
public function index()
{
$user_id = auth()->user()->id;
$now = Carbon::now();
$tasks_assigned = Task::orderBy('date', 'asc')->whereDate('date', '>=', $now)->where('user_assigned_id', '=', $user_id)->user_assigned()->where('name', '=', 1)->get();
$tasks_created = Task::orderBy('date', 'asc')->whereDate('date', '>=', $now)->where('user_id', '=', $user_id)->get();
return view('dashboard')->with('tasks_assigned', $tasks_assigned)->with('tasks_created', $tasks_created);
}
I've gotten a bit turned around in the Controller, so I'm not sure if I messed something up there. Basically, I'm getting results from tasks owned by the logged in user, but not assigned to the logged in user.
You can just add a second relationship defined on your Task.php Model and assign a different agent based on user_assigned_id. You can manipulate it as expected via Eloquent.
Task.php
public function user() {
return $this->belongsTo('App\User');
}
public function assignedUser() {
return $this->belongsTo('App\User', 'user_assigned_id');
}
Then on DashboardController.php
$tasks_assigned = Task::orderBy('date', 'asc')->whereDate('date', '>=', $now)->where('user_assigned_id', '=', $user_id)->get();
should work
public function user()
{
return $this->belongsTo('App\User');
}
// Added an user_assigned_id relationship
public function assignee()
{
return $this->belongsTo('App\User', 'user_assigned_id');
}
The relationship is still a belongsTo, you just need to provide the column where the foreign key is held.
Other files:
User.php
public function ownedTasks()
{
return $this->hasMany('App\Task');
}
public function assignedTasks()
{
return $this->hasMany('App\Task', 'user_assigned_id');
}
Dashboard Controller
public function index()
{
$now = Carbon::now();
$tasks_assigned = Auth::user()->assignedTasks()->where('date', '>=', $now)->get();
$tasks_created = Auth::user()->ownedTasks()->where('date', '>=', $now)->get();
return view('dashboard')->with(compact('tasks_assigned', 'tasks_created'));
}

Call to undefined method whereHas() in laravel 5.5

I am upgrading and refactoring my site to laravel 5.5, and this code is giving me a problem at the moment. I searched in the laravel github docs and didn't find any breaking changes that might affect this.
What I am trying to do is Related To section in my site, In every recipe page I want to display some more recipes that has the same category.
Here is my code:
public static function getRelatedRecipes($recipe){
$related_category_ids = $recipe->category()->pluck('categories.id');
return $relatedRecipes =
Recipe::whereHas('categories', function ($q)use($related_category_ids){
$q->whereIn('category_id', $related_category_ids);
})
->where('id', '<>', $recipe->id)
->take(4)
->inRandomOrder()
->get();
}
This is the recipe model:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Recipe extends Model
{
protected $guarded=[];
/**
* Get the route key name for Laravel.
*
* #return string
*/
public function getRouteKeyName()
{
return 'slug';
}
public function category()
{
return $this->belongsToMany('App\Category');
}
}
What could be the problem?
Thanks,
P.S
If any other code that you think is needed to resolve this, please tell me and I will post it here. :)
First of all make sure, Recipe you use in the method is the model, so instead of
Recipe::whereHas('categories', function ($q)use($related_category_ids){
use
\App\Recipe::whereHas('categories', function ($q)use($related_category_ids){
The other thing is this categories relationship. In model you don't have categories relationship, you have only category relationship

Resources