laravel multiple relation query - laravel

I have 3 model in my project and i want to get a query or collection result as i say:
JewelsItem model:
protected $table = 'jewel_items';
public function jewel(){
return $this->belongsTo('App\Models\Jewel');
}
public function sellInvoice(){
return $this->belongsTo(SellInvoice::class,'sell_invoice_id');
}
2.Jewel model:
public function jewelsItems(){
return $this->hasMany('App\Models\JewelsItem');
}
3.sellInvoice model:
protected $table = "sell_invoices";
public function jewelsItems(){
return $this->hasMany(JewelsItem::class,'buy_invoice_id');
}
Query: i want to get all jewelsitems that has no sellInvoice and has jewel name like 'something'.
note: jewel model has a name attribute .and i want to add name of jewel to first of all the collection's items of result.
i know how to get all jewel with name of 'something' :
Jewel::where('name','like','something'.'%')->get();
but i can't get all jewelItem related to it an add name of jewel to first of them.

To look for condition in another relationship you can use whereHas() and whereDoesntHave()
$name = 'something';
$items = JewelsItem::whereHas('jewel', function($query) use ($name) {
$query->where('name', 'LIKE', "%{$name}%");
})
->whereDoesntHave('sellInvoice')
->with('jewel')
->get();
It reads: getting jewel items where jewel has $name in the name field
and doesn't have sell invoice
then add related jewel to the jewel item.
When you want to retrieve the name of the jewel, you can access its property like so.
foreach($items as $item) {
echo $item->jewel->name;
}

Related

retrieving related field in controller index function gives error but ok in show function

I define the relation in Company table (where I added the plural):
protected $table = 'companies';
public function country() {
return $this->belongsTo(Country::class, "country_id")->withDefault(['country' => 'unknown']);
}
I also did the same in the Country model.
When I use the following code in the controller show function it works:
public function show (Company $company) {
$company->country = $company->country()->pluck('country');
But if I use the same code in the index function in a loop, I get an error "Call to undefined method stdClass::country()":
public function index (Company $company) {
if (request('tag')) {
$companies = Tag::where('name',request('tag'))->firstOrFail()->companies;
$companies->page_title = "Businesses matching tag '".request('tag')."'";
} else {
$companies = DB::table('companies')
->where([['is_active', '=', '1']])
->orderBy('company')
->get();
}
foreach($companies as $key => $thisCompany) {
...
$thisCompany->country = $company->country()->pluck('country');
}
I guess it is due to the fact that $company is created in the loop and not passed through the function like in show(Company $company)... but I could not find how to solve this issue... so help will be appreciated.
I have added the model in the argument of the function and change the name of the $company variable in the loop by $thisCompany to avoid confusion with the $company model.
No error but the field $country->country does not contain the name of the country but "Illuminate\Support\Collection {#443 …1}"
Why is it so complicated? Please help...
Paul, sorry, I think I didn't explain myself well in the comments.
What I meant by "What about if you change DB::table('companies') by Company?", is to stop using DB Query Builder to use the Eloquent Company model.
Specifically in this segment of code:
$companies = DB::table('companies')
->where([['is_active', '=', '1']])
->orderBy('company')
->get();
So, it could be:
$companies = Company::where([['is_active', '=', '1']])
->orderBy('company')
->get();
The explanation is that in the first way (with DB Query Builder), the query will return a collection of generic objects (the PHP stdClass object) that do not know anything about the Company and its relationships.
On the other hand, if you use the Eloquent model Company, it will return a collection of Company objects, which do know about relationships, and specifically the relationship that you have defined as country.
Then, when you loop over the collection, you will be able to access the country relation of each Company object:
foreach($companies as $key => $company) {
//...
$company->country = $company->country()->pluck('country');
}
Finally, your code could looks like:
public function index () {
if (request('tag')) {
$companies = Tag::where('name',request('tag'))->firstOrFail()->companies;
$companies->page_title = "Businesses matching tag '".request('tag')."'";
} else {
$companies = Company::where([['is_active', '=', '1']])
->orderBy('company')
->get();
}
foreach($companies as $key => $company) {
//...
$company->country = $company->country()->pluck('country');
}
//...
}

Laravel Eloquent get all categories of restaurants?

I'm trying to get all categories of restaurants.
My models:
Restaurant
public function categories()
{
return $this->belongsToMany(Category::class,'restaurant_categories_relation','restaurant_id');
}
Category
public function restaurants()
{
return $this->belongsToMany(Restaurant::class,'restaurant_categories_relation', 'category_id');
}
In my controller:
$restaurants = Restaurant::where('district_id', $request->district)->paginate(8);
$categories = $restaurants-> ????;
Please help me do this, thanks!
You could use has() like :
Category::has('restaurants')->get();
That will return the categories who are related with the restaurants.
Try also the use of whereHas like :
$users = Category::whereHas('restaurants', function($q){
$q->->where('district_id', $request->district)->paginate(8);
})->get();
Since you've already a Collection we can't query the categories so I suggest adding a function to scope that inside the Restaurant model like :
public static function getCategoriesOfRestaurants($restaurants)
$categories = [];
foreach($restaurants as $restaurant){
array_push( $categories, $restaurant->categories->pluck('id')->toArray());
}
return Category::WhereIn('id', array_unique($categories))->get();
}
Then just call it when you get the $restaurants collection :
$restaurants = Restaurant::with("categories")->where('district_id', $request->district)->paginate(8);
$categories = Restaurant::getCategoriesOfRestaurants($restaurants);
Note: The use of with("categories") when getting the collection will query All the related categories in the first query so the foreach loop will not generate any extra query just looping through the already fetched data, and finally we will get the collection of categories in the return statement.
use with() method for eagerloading, that provides you get all categories in a single query
$restaurants = Restaurant::with("categories")->where('district_id', $request->district)->paginate(8);
foreach($restaurants as $restaurant){
foreach($restaurant->categories as $category)
{{$category}}
}
}
if you want to use categories outside of the loop, then assign these categories to a variable
foreach($restaurants as $restaurant){
$categories = $restaurant->categories;
}
// do something with $categories
Your relation should be
Restruant.php
public function categories() {
return $this->belongsToMany(Category::class,'restaurant_categories_relation','restaurant_id','category_id');
}
then in you controller method just wirte
$restruants = Restruant::with('categories')->get();
It should return you collection of all restruants with all related categories.

Add custom column to identify table during query

How can I add a custom column in an Eloquent select query in order to identify the table?
For example, I have the current query:
$posts = Post::where('user_id', getUserID())
->get();
I'd like to add a column is_post with value 1 (for true) during the query.
The Post class:
<?php
class Post extends Eloquent {
protected $table = 'posts';
}
How can I do this?
You could do it for example this way:
$posts = Post::where('user_id', getUserID())->selectRaw('*, 1 AS `is_post`')->get();
but depending on your needs, you can also use the piece of code you showed:
$posts = Post::where('user_id', getUserID())->get();
and add accessor in Post model this way:
public function getIsPostAttribute($value) {
return 1;
}
In both cases you should be able to display is_post value for example this way:
foreach ($posts as $post) {
echo $post->is_post;
}

Laravel 4 unable to retrieve value from belongsTo relation using query builder

I have two tables, organizations and categories. This is how my tables and models are set up:
Tables:
organizations
id - integer
category_id - integer, fk
name - string
...
categories
id - integer
name - string
Models:
class Organization extends Eloquent
{
public function category()
{
return $this->belongsTo('Category');
}
public function comments()
{
return $this->morphMany('Comment', 'commentable');
}
}
class Category extends Eloquent
{
public $timestamps = false;
public function organization()
{
return $this->hasMany('Organization');
}
}
In my routes.php file, I have the following code (where $category is equal to "organizations"):
$query = Organization::query()
->join('categories', 'categories.id', '=', $category . '.id')
->select('categories.name as category');
$tiles = $query->get();
In my view, I am able to perform the following actions without any errors:
foreach($tile->comments as $comment)
{
...
}
...
$tile->name;
However, calling $tile->category->name will give me the error Trying to get property of non-object. And calling $tile->category will just return null. How can I display the category associated with the organization? I am able to retrieve other properties and relations just fine, but this is giving me a problem.
You have a bug in your code: $category . '.id' should be $category . '.category_id' doing so should make $tile->category->name work.
Also please note (you probably already know this) that in the code that you provided you are not actually using the belongsTo relation as set in your Organization class, you are just using the joined data.
The following would also work using the Eloquent ORM utilizing the models relationship methods:
$tiles = Organization::with('category')
->get();
foreach ($tiles as $tile)
{
echo $tile->name . '<br>';
echo $tile->category->name . '<br>';
}
Or you could do so the other way round from the categories model like so:
$tiles = Category::with('organization')
->get();
foreach ($tiles as $tile)
{
echo $tile->name . '<br>';
foreach($tile->organization as $org)
{
echo $org->name . '<br>';
}
}

Eloquent where condition based on a "belongs to" relationship

Let's say I have the following model:
class Movie extends Eloquent
{
public function director()
{
return $this->belongsTo('Director');
}
}
Now I'd like fetch movies using a where condition that's based on a column from the directors table.
Is there a way to achieve this? Couldn't find any documentation on conditions based on a belongs to relationship.
You may try this (Check Querying Relations on Laravel website):
$movies = Movie::whereHas('director', function($q) {
$q->where('name', 'great');
})->get();
Also if you reverse the query like:
$directorsWithMovies = Director::with('movies')->where('name', 'great')->get();
// Access the movies collection
$movies = $directorsWithMovies->movies;
For this you need to declare a hasmany relationship in your Director model:
public function movies()
{
return $this->hasMany('Movie');
}
If you want to pass a variable into function($q) { //$variable } then
function($q) use ($variable) { //$variable }
whereBelongsTo()
For new versions of Laravel you can use whereBelongsTo().
It will look something like this:
$director = Director::find(1);
$movies = Movie::whereBelongsTo($director);
More in the docs.
is()
For one-to-one relations is() can be used.
$director = Director::find(1);
$movie = Movie::find(1);
$movie->director()->is($director);

Resources