Query hasMany relation with slug instead of id? - laravel

I'm trying to query a category and all of its channels based on a slug.
Works
\App\Category::find(1)->channels()->get();
Doesn't Work
\App\Category::where('slug','animals')->channels()->get()
BadMethodCallException with message 'Method Illuminate/Database/Query/Builder::channels does not exist.'
Relationship on Category Model
public function channels()
{
return $this->hasMany(Channel::class,'category_id');
}

Assuming that you correctly have your slug field set-up in migration and model attributes (It looks like so from the Exception message).
Doing
\App\Category::find(1)->channels()->get();
is under the hood equivalent to
\App\Category::where('category_id', 1)->first()->channels()->get();
So what you are requiring, is to get the categories to actually execute the query and then be able to retrieve the channels from the hydrated model.
\App\Category::where('slug', 'animals')->first()->channels()->get();
should work as well as
\App\Category::where('slug', 'animals')->first()->channels; // calling as attribute will perform the get() on the relationship
Also take note that you may take advantage of other methods like with() for eager loading the relationship, first() to perform a get and ensure you take only one instance, and calling the relationship as attribute as shown above. Refer to the docs

there are so many possible answer in your question .. be more specific .. but here's the list of sample queries that may help you ..
GETTING ALL THE CATEGORY WITH ITS CHANNELS WHERE CATEGORY SLUG = ANIMAL
Category::with(['channels'])->where('slug', 'animal')->get();
GETTING ALL THE CATEGORY WITH ITS CHANNELS WHERE HAS A CHANNEL SLUG = ANIMAL
Category::with(['channels'])->whereHas('channels'=>function($q){
$q->where('slug','animal');
})->get();
GETTING ALL THE CATEGORY WITH ONLY CHANNELS THAT HAS A SLUG = ANIMAL
Category::with(['channels'=>function($q){
$q->where('slug','animal');
}])->get();

Related

Eloquent with diferent relationships for same table

i need some hints and what is the best way and pratice with laravel to solve this problem!
I have a main table called colors with the fields category_id and type and i have in my models 2 relationships for the category_id, the bluecategory and redcategory.
In some cases i use the id from bluecategory and in other exemples i use the redcategory id.
Now in one page i want to shows all the results from colors, but i can't do this $data->bluecategory or $data->redcategory because i dont'no what record is using what relationship.
My ideia was using a function to send parameters category_id and type and inside the function discover what is the correspondente relashion and return the correct result.
But how i can handle this?
Sorry its a bit confuse!
You could add a scope to your modal and than chain it to your existing query.
Example
public function scopeName($query, $catID, $type)
{
return $query->where('category_id, $catID)
->where('type', $type);
}

Laravel: How to retrieve this nested model

In Laravel I have ModelA, ModelB and ModelC. ModelA has many ModelB. ModelB has many ModelC. I want to retrieve all ModelC for a selection of ModelA. How do I do this?
I tried the following:
$models = ModelC::with(['modelB','modelB.modelA' => function ($query) {
$query->where('owner', 123);
}])->get();
But the first query in that case is select * from model_c. Obviously not the result I am looking for.
Imagine that you were received 100 objects from the database, and each record had 1 associated model (i.e. belongsTo). Using an ORM would produce 101 queries by default; one query for the original 100 records, and additional query for each record if you accessed the related data on the model object. In pseudo code, let’s say you wanted to list all published authors that have contributed a post. From a collection of posts (each post having one author) you could get a list of author names like so:
$posts = Post::published()->get(); // one query
$authors = array_map(function($post) {
// Produces a query on the author model
return $post->author->name;
}, $posts);
We are not telling the model that we need all the authors, so an individual query happens each time we get the author’s name from the individual Post model instances.
Eager Loading
As I mentioned, ORMs “lazy” load associations. If you intend to use the associated model data you can trim that 101 query total to 2 queries using eager loading. You just need to tell the model what you need it to load eagerly.
Here’s an example from the Rails Active Record guide on using eager loading. As you can see, the concept is quite similar to Laravel’s eager loading concept.
$posts = Post::with('author')->limit(100)->get();
I find that I receive better understanding by exploring ideas from a wider perspective. The Active Record documentation covers some examples that can further help the idea resonate.
I managed to solve this with nested whereHas calls as follows:
$models = modelC::whereHas('modelB', function ($query) {
$query->whereHas('modelA', function ($query) {
$query->where('owner', 123);
});
})->get();
Laravel to the rescue, yet again!

Accessing Related Model inside the mutator

I have question about my problem, so let me explain..
I have these Model which is Product and ProductVariant , the ProductVariant has "belongsTo" relation into the Product model.. and Product model have "hasMany" relation into the ProductVariant
My Question is...
i did createMany for variation from the product which is like
Product->variant()->create($variantProducts);
and i'd like to create some mutator on the ProductVariant model to manipulate one column called "sku".
my problem is, how to get some column value from the mutator to get data from the related model ( Product ) , in this case i want to get the category_id of the Product from the ProductVariant mutator
i try to do this , but it seems doesnt work
public function setSkuAttribut($v){
// product() is belongsTo relation to the product model
$cat = $this->product()->category_id;
dd($cat);
}
but it returns me this error
Undefined property: Illuminate\Database\Eloquent\Relations\BelongsTo::$category_id
Any helps would be really appreciated.. thankyou :)
You're calling the product() relation method as a method, which means you're receiving a Builder instance. In order to get the model instance, you'll either have to execute ->product()->get()->category_id, which will make a new query on each occasion or use the lazy eager loading with ->product->category_id which will use an already loaded relation instance if present.

Laravel complicated relationship

My laravel app structed like this:
People: Model & Controller
Pets: Model & Controller. Has many to many relationship with People.
Abiilities: Model & Controller.
People_pets: People pets. (pivot table with people_id and pet_id). Also has 4 columns of abbility1_id, abbility2_id, abbility3_id and abbility4_id.
Now.. I built an API method to return the user pets, and it looks like this:
public function pets()
{
return $this->belongsToMany(Pet::Class, 'user_pets')->withPivot(
'abbility1_id',
'abbility2_id',
'abbility3_id',
'abbility4_id'
)->orderBy('position','asc');
}
which makes $user->pets returns the user list of pets, with the pivot information of user_pets and the abbility ids.
The question
What I want to do is add a json object to this method result named "abbilities" and get the data of the abbilities there such as name and description from the Abbilities model/controller.
How I can add the abbilities information to my query out of just the ID's?
The output of the current API CALL:
Desired output: array of Abbilities inside every pet object with the detail of the attack_id's inside $user->pets->pivot->attack1_id
You could just use the query builder and orWhere to grab the data. I don't think you can access it through relationships with the way you have it set up.
I don't know how you access your pet ability ids, but I'm guessing it's like $pet->abbility1_id.
$abbilities = Abbilities::where('id', '=', $pet->abbility1_id)
->orWhere('id', '=', $pet->abbility2_id)
->orWhere('id', '=', $pet->abbility3_id)
->orWhere('id', '=', $pet->abbility4_id)
->get();

eloquent filter result based on foreign table attribute

I'm using laravel and eloquent.
Actually I have problems filtering results from a table based on conditions on another table's attributes.
I have 3 tables:
venue
city
here are the relationships:
a city has many locations and a location belongs to a city.
a location belongs to a venue and a venue has one location.
I have a city_id attribute on locations table, which you may figured out from relationships.
The question is simple:
how can I get those venues which belong to a specific city?
the eloquent query I expect looks like this:
$venues=Venue::with('location')->where('location.city_id',$city->getKey());
Of course that's not gonna work, but seems like this is common task and there would be an eloquent command for it.
Thanks!
A couple of options:
$venues = Venue::whereIn('location_id', Location::whereCityId($city->id)->get->lists('id'))
->get();
Or possibly using whereHas:
$venues = Venue::whereHas('location', function($query) use ($city) {
$query->whereCityId($city->id);
})->get();
It is important to remember that each eloquent query returns a collection, and hence you can use "collection methods" on the result. So as said in other answers, you need a Eager Loading which you ask for the attribute you want to sort on from another table based on your relationship and then on the result, which is a collection, you either use "sortBy" or "sortByDesc" methods.
You can look at an example below:
class Post extends Model {
// imagine timpestamp table: id, publish, delete,
// timestampable_id, timestampble_type
public function timestamp()
{
return $this->morphOne(Timestamp::class, 'timestampable');
}
}
and then in the view side of the stuff:
$posts = App\Post::with('timestamp')->get(); // we make Eager Loading
$posts = $posts->sortByDesc('timestamp.publish');
return view('blog.index', compact('posts'));

Resources