Relation between 2 tables with a link table - laravel

I have this tables :
topics
-------
id | title
------+----------
1 | Sport
2 | Social
posts_topics
------------
id | post_id | topic_id
------+--------------+------------
1 | 1 | 1
2 | 1 | 2
posts
------
id | title
-----+----------
1 | A Test Post
I store topics in topics table and use posts_topics to link between my posts table and topics
now I want select title of topics when selecting posts,
After some searching in StackOverflow and Google, I've written this models:
Posts.php
public function post_topics()
{
return $this->hasMany('App\PostTopics');
}
PostTopics.php
public function topics()
{
return $this->hasManyThrough('App\Posts', 'App\Topics', 'id', 'topic_id');
}
Topics.php
protected $table = 'topics';
and in my controller I trying to fetch:
$post = Posts::with('post_topics')->find($post_id);
dd($post);
Now this code will work but cannot return title of topics.

Change the code to a Many to Many relationship in Posts.php:
public function post_topics()
{
return $this->belongsToMany('App\Topics', 'posts_topics', 'post_id', 'topic_id');
}
And then call it:
$post = Posts::with('post_topics')->find($post_id);
Try this and check if it works for you.

Related

How should I use HasManyThrough connecting 3 tables via 2 pivot tables in Laravel?

I am having trouble wrapping my head around the HasManyThrough relationship in Laravel 5.8 which I think is what I need to use, but I am not sure how to implement. I've tried following along a Laracasts video where Jeffrey describes it and read the docs, but I can't seem to grasp the concept and feeling rather stupid right now.
How should I define the relationships in my models and write the correct Eloquent query in my ProductsController to display posts in a product view that shares the same tag id?
For example I have a post tagged with "mbti" and I have a product tagged also with "mbti". How would I go about displaying those related posts in the relevant product view? I've managed to display the tags in the view so far, but I want the posts associated with that tag to display as well. I appreciate any guidance on how I should approach this.
I have 3 tables and 2 pivot tables (some column names removed for brevity):
| products |
+----------+
|id |
------------
| posts |
+----------+
|id |
------------
| tags |
+----------+
|id |
------------
| post_tag |
+----------+
|post_id |
|tag_id |
------------
| product_tag |
+-------------+
|product_id |
|tag_id |
---------------
My models:
Post.php
public function tags() {
return $this->belongsToMany('App\Tag')->withPivot('tag_id');
}
Tag.php
public function posts()
{
return $this->belongsToMany('App\Post')->withPivot('post_tag');
}
public function products()
{
return $this->belongsToMany('App\Product')->withPivot('product_tag');
}
Product.php
public function tags()
{
return $this->belongsToMany('App\Tag')->withPivot('product_id');
}
I ended up adding a tag_id column to my products table and referencing the tag id there. A product in my application can only be assigned one tag, so the need for a pivot table was kind of redundant and added unnecessary complexity.
In my Tag.php model, I defined the relationship as:
public function products()
{
return $this->hasManyThrough('App\Post', 'App\Product');
}
and in my ProductsController.php I select the tags as such in mthe show method:
$tag = Tag::where('id', '=', $product->tag_id)->first();
if($tag) {
$tags = Tag::whereName($tag->name)->first();
}

How to query a table based on criteria of another table in Laravel?

In my laravel project I have an inventory and a medicine table which the formats are as the following:
Inventory Table
id | medicine_id | expiry_date
-------|-----------------|-------------
1 | 1 | 13-11-2021
2 | 2 | 01-01-2020
3 | 2 | 23-05-2024
Medicine Table
id | name | category
-------|-----------------|-------------
1 | Hemophine | Syringe
2 | andrenalin | Tablet
3 | aspirin | Capsule
The models are set as below:
Inventory Model
class Inventory extends Model
{
public $incrementing = false;
public function medicine(){
return $this->belongsTo('App\Medicine', 'medicine_id');
}
}
Medicine Model
class Medicine extends Model
{
public $incrementing = false;
public function inventory(){
return $this->hasMany('App\Inventory', 'medicine_id');
}
}
For retrieving all the inventories with a specific category such as Syringe, I tried eager loading, but couldn't figure out the flaws. Here is what I did to get all the inventories with a Syringe category, but it didn't work.
public function index()
{
$medicines = Inventory::where('medicine_id'->category, "Syringe")->get();
foreach($medicines as $medicine){
echo $medicine->medicine->name ." ".$medicine->expiry_date;
echo "<br>";
}
}
Now, Is there anyway to get all the inventory items based on their categories they are in? in this case in "Syringe" category?
Your syntax is a bit wrong, in order to load the medicine for each inventory you need to use with and the where function is where('column', value)
So change it to this:
$medicines = Inventory::with([
'medicine' => function($query) {
$query->where('category', "Syringe");
}
])->get();
or even better the other way around:
$medicines = Medicine::with('inventory')->where('category', 'Syringe')->get();

How can I notify a specific group in Laravel

I have a problem, I want to notify specific users, like a group of users or admins for example. But I don't know how I can only notify admin or users in my code with Laravel.
Here is my AdsController.php in which I notify only admin:
$ads = new Ad;
$current_user=Auth::user();
$ads->object = $request->input('object');
$ads->description = $request->input('description');
$ads->save();
$users = User::where('id', '<>', $current_user->id)->where('admin', 1)->get();
foreach ($users as $user) {
$user->notify(new NewAd($current_user, $ads));
}
please someone help me
you can add 1 table calls "role", and on table users add 1 field calls role_id. and then you can make condition in your controller,
for example :
Role table
id | name
1 | Admin
2 | User
User table
id | name | role_id
1 | Jon | 1
2 | Doe |2
Data table
id | name |user_id
1 |Data1 | 1
2 |Data2 | 2
Controller
public function index() {
if(Auth::user()->role_id == 1 ){
$datas = Data::all();
return view('projects.index',['datas' => $datas]);
} else {
$datas = DB::table('datas')->where('user_id', Auth::user()->id )->get();
return view('projects.index',['datas' => $datas]);
}
Hope can help you

How to join tables in laravel 5.4

In my case, I have 3 tables like Question, options, and answers
Questions table
|id | question_name|
------------------------------
1 question1
2 question2
3 question3
options table
id | question_id | options |
----------------------------------------
1 1 option1
----------------------------------------
1 1 option2
----------------------------------------
1 1 option3
----------------------------------------
1 1 option4
Answers table
id | customer_id | question_id | answer(selected by user) |
--------------------------------------------------------------------
1 1 1 option1
--------------------------------------------------------------------
1 2 2 option2
--------------------------------------------------------------------
1 1 3 option3
--------------------------------------------------------------------
1 1 3 option2
How can I get below output from answers using joins table
For customer 1
question1
--option1
question2
--option2
question3
--option3
--option2
I have eloquent relation,
Question model
class Question extends Model
{
public function options()
{
return $this->hasMany(Option::class);
}
public function customer()
{
return $this->belongsTo(CustomerProfile::class);
}
public function answers()
{
return $this->hasMany(Answer::class);
}
}
Option model
public function question()
{
return $this->belongsTo(Question::class);
}
Answer model
public function customer()
{
return $this->belongsTo(CustomerProfile::class);
}
public function question()
{
return $this->belongsTo(Question::class);
}
That is how my relationships looks like, Now I just need to join the tables to get output.
In order to get the related options for your questions, you can use eager loading.
An example would be:
$questions = Question::with('options')->get();
You will then have a collection with the questions, and their related options. You will need to construct a loop to get the data you want.
Going off the comment you left on Aaron Fahey's answer, you'll need to add a constraint to the query and the eager-load:
$customerId = 1;
$questions = Question::with([
'options', 'answers' => function ($query) use ($customerId) {
$query->where('customer_id', $customerId);
}])
->whereHas('answers', function ($query) use ($customerId) {
$query->where('customer_id', $customerId);
})
->get();
https://laravel.com/docs/5.4/eloquent-relationships#constraining-eager-loads
https://laravel.com/docs/5.4/eloquent-relationships#querying-relationship-existence
Hope this helps!
I guess, you also have defined eloquent relations in Customer Model class.
If you do so, then you can retrieve all the answers of a particular customer through customer model and this will give you the hook to get the answer's question and its all options:
$customer = Customer::find($customerId);
$answer = $customer->answers()->where('id', $answerId)->get();
$question = $answer->question;
$questionOptions = $question->options;
I hope it will help.

Joining pivot table to access data

I am trying to access data from a database query which I think will need a join. I have users that can be apart of many groups. I am using a belongsToMany
relationship. My Models are like so
class User extends Model
{
protected $table = 'users';
protected $guarded = [];
public function group()
{
return $this->belongsToMany('App\Group', 'users_user_groups')->withPivot('user_id', 'group_id');
}
}
class Group extends Model
{
protected $table = 'user_groups';
protected $guarded = [];
use SoftDeletes;
public function user()
{
return $this->belongsToMany('App\User', 'users_user_groups')->withPivot('user_id', 'group_id');
}
}
When I run everything I need too, I might get data like the following.
users
+----+---------------+
| id | name |
+----+---------------+
| 1 | John Doe |
+----+---------------+
user_groups
+----+---------------+-----------------+
| id | name | description |
+----+---------------+-----------------+
| 1 | Group AA | Something |
+----+---------------+-----------------+
| 2 | Group BB | Something |
+----+---------------+-----------------+
users_user_groups
+----+---------------+-----------------+
| id | user_id | group_id |
+----+---------------+-----------------+
| 1 | 1 | 1 |
+----+---------------+-----------------+
| 2 | 1 | 2 |
+----+---------------+-----------------+
So I know user with the id 1 belongs to the user_groups with ids of 1 and 2. What I am trying to do is grab all the users within my database who
belong to a user_group with the name admin. So I am trying something like this
DB::table('users')->select('userName')
->join('user_groups', 'users_user_groups')
->where('name', '=', 'admin')->get();
This I know is all wrong, how can I get all users within a group when using belongsToMany and a pivot table?
Thanks
Eloquent uses relations, not the query builder.
You can achieve what you're aiming for by doing something like this:
$group = Group::where('name', 'admin')->first();
$users = $group->users; // Where users is the name of your relationship (At the moment you have user)
Under the hood that will do two SQL statements and map them together in eloquent objects, rather than a join. The statements will look something like this:
select * from user_groups where name = ? and deleted_at is not null limit 1
select * from users where id in (?, ?)
When you have an instance Group you execute the relationship by calling it as if it was a property. So after that $users will contain a collection of User instances, so you can just loop through them:
foreach ($users as $user) {
// Do something with $user
}

Resources