Eloquent Select behaving oddly when querying a belongsToMany relationship - php

I am trying to retrieve and paginate the related User models of a Group model.
The response should only contain first_name, but there seems to be two issues causing additional fields to get added.
Because an 'appends' is defined it seems to be bringing in those fields as well even though I have a select statement.
When I use the paginate() function it seems to omit my select statement altogether and brings in all fields. When I use get() instead, I at least get first_name + the appends.
Questions:
How do you disable appends for a single query?
Why isn't the select statement working when paginating results of the belongsToMany relationship? Why would all fields be returned instead of the ones passed to select()?
I simplified/changed the code to show what I'm trying to do.
Group Model
protected $fillable = [
'name',
]
public function users()
{
return $this->belongsToMany('App\Models\User');
}
User Model
protected $fillable = [
'first_name',
'... many more fields....'
]
public $appends = [
'profile_pic'
];
Controller:
$users = $group->users();
// returns all fillable and appends fields instead of just first_name
$paginated = $users->select('first_name')->paginate(10);
Thank you!

Related

Error when trying to use eloquent relationships

I am trying to get this problem fixed for hours now and I just don't get what I am doing wrong.
I want to get all entries of my tables where my id of posts equals the id of tables bewerbungens.
So I get all applications of every user existing with the corresponding title of the post the user applied to.
I asked a question here before and got resources to add relationships, which I did, as seen here:
Bewerbungen Model:
protected $fillable = [
'bewerber_email',
'Stellenanzeigen_ID',
'is_Accepted',
'accept_Date',
'is_Canceled',
'cancel_Date',
'is_Received',
'receive_Date',
'is_Canceled_Bewerber',
'cancel_Date_Bewerber',
'lebenslauf_File',
'zeugnis_File',
'anschreiben_File',
'weitere_Doks',
];
public function post() {
return $this->belongsTo('Post', 'Stellenanzeigen_ID', 'Bewerbung_ID');
}
and here in my Post model:
protected $fillable = [
'titel',
'startdate',
'enddate',
'beschreibung',
'standort',
'type_name',
'abteilung_name',
'kontakt',
'isActive',
'lebenslauf',
'zeugnisse',
'anschreiben',
'weitere_Doks',
'is_Permitted',
'job_start',
];
public function bewerbungen() {
return $this->belongsToMany(Bewerbungen::class);
}
Here is my Controller code where I try to get the entries:
$dummy = Post::with('Bewerbungen.post')->get();
But I get the error:
SQLSTATE[42S02]: Base table or view not found: 1146 Table 'portal.bewerbungen_post' doesn't exist (SQL: select bewerbungens.*, bewerbungen_post.post_id as pivot_post_id, bewerbungen_post.bewerbungen_id as pivot_bewerbungen_id from bewerbungens inner join bewerbungen_post on bewerbungens.id = bewerbungen_post.bewerbungen_id where bewerbungen_post.post_id in (1, 2, 3, 4))
I also tried this instead:
$dummy = Post::where('id', 'Stellenanzeigen_ID')->get();
But it just returns an empty set.
How can I fix this?
Edit: Post Model
protected $fillable = [
'titel',
'startdate',
'enddate',
'beschreibung',
'standort',
'type_name',
'abteilung_name',
'kontakt',
'isActive',
'lebenslauf',
'zeugnisse',
'anschreiben',
'weitere_Doks',
'is_Permitted',
'job_start',
];
public function location() {
return $this->hasOne(Standort::class);
}
public function job_type() {
return $this->hasOne(Jobtypes::class);
}
public function bewerbungen(): BelongsToMany
{
return $this->belongsToMany(Bewerbungen::class, 'bewerbungens');
}
I had the bewerbungen() method as suggested in the comment, I just played around with it so it looks different, but it is currently not in use since it didn't work
The SQL Error said that there's no bewerbungen_post table, since you use belongsToMany with only one argument. As mentioned here, if your relationship's intermediate table name is different with the Laravel Behavior, then add the relationship's intermediate table name to the second argument, or Laravel will join the two table for the relation table's name. For example:
public function bewerbungen() {
return $this->belongsToMany(Bewerbungen::class, 'bewerbungen_post');
}
I've checked your previous question, and I think that the Post model joined directly to the Bewerbungen model, so the relation in the Post Model should looks like this:
public function bewerbungens(): HasMany
{
// It's mean that `Post` has many `Bewerbungen` where `Stellenanzeigen_ID` = `posts.id`
return $this->hasMany(Bewerbungen::class, 'Stellenanzeigen_ID', 'id');
}
And in the Bewerbungen model:
public function post(): BelongsTo
{
// It's mean that `Bewerbungen` owned by Post as `Stellenanzeigen_ID` = `posts.id`
return $this->belongsTo(Post::class, 'Stellenanzeigen_ID', 'id');
}
If you want to get Post with all Bewerbungen owned by Posts:
// You will get All Post with all Bewerbungen each Post
$posts = Post::with('bewerbungens')->get();
Vice versa:
// You will All Bewerbungen and One Post for every Bewerbungen
$bewerbungen = Bewerbungen::with('post')->get();
All details about relationship could be found in Laravel Documentation.

Unable to get selective column names on Laravel Eloquent Nested Eager Relationship

I have a Product Model with a following relationship:
public function recommendedPricing()
{
return $this->hasMany(RecommendedPricing::class);
}
The Recommended Pricing Model is:
protected $fillable = [ 'sku_id', 'unit_type_id', 'base_price', 'min_billable_qty', 'max_billable_qty', 'discount_method'];
protected $with = ['bands'];
public function bands()
{
return $this->hasMany('App\Models\RecommendedPricingBand');
}
The Recommended Pricing Band Model is like:
protected $fillable = ['sku_id','recommended_pricing_id','start','end','percent_change','fixed_price'];
Now In my Controller I am doing this:
Product::where('id', $product->id)->with(['recommendedPricing', 'recommendedPricing.bands'])->get();
which gives the entire result. But I want selected columns from both Recommended Pricing and Recommended Pricing Band. So, I tried this:
Product::where('id', $product->id)->with(['recommendedPricing:id, base_price, discount_method', 'recommendedPricing.bands:id, percent_change, fixed_price'])->get();
But this always results in an error.
My question: Is there any better approach or way to fetch the correct result for this kind of a nested relationship scenario?
When eager loading particular fields you can't have spaces. I usually do a seperate with line for each relationship. I don't think you need the array either. And you always have to get the id first, which you have already :) hope this works...
->with('recommendedPricing:id,base_price,discount_method')
->with('recommendedPricing.bands:id,percent_change,fixed_price')

Laravel Eloquent belongsto relationship returns null

I have two Eloquent models:
1) Post
class Post extends Model
{
protected $table = 'posts';
protected $fillable = ['id', 'user_id', 'product_id', 'site_id', 'link_id', 'body', 'created_at', 'updated_at'];
public function user(){
return $this->belongsTo(User::class);
}
public function product(){
return $this->belongsTo(Product::class);
}
2) Product
protected $table = 'products';
protected $fillable = ['id', 'user_id', 'manufacturer_id', 'shift_product_id', 'name', 'english_name',
'slug', 'text', 'spec', 'live', 'created_at', 'updated_at'];
public function posts(){
return $this->hasMany(Post::class);
}
I need to get the product from a post
I do that:
$posts = Post::get();
foreach($posts as $key){
dd($key->product);
}
Like this it returns NULL
If I do like this:
dd($key->product());
I get the product but I can't to use that
but I need to get something like that to use whant I need:
Try to point out foregin key and other key in relation, examples:
public function post()
{
return $this->belongsTo('App\Post', 'foreign_key', 'other_key');
}
public function user()
{
return $this->belongsTo('App\User', 'foreign_key', 'other_key');
}
More: https://laravel.com/docs/5.5/eloquent-relationships
i found my problem
i dont have in the DB product with ID = 1
:/
stuped problem
thanks for all the help i leran alot from u.
The relationship probably doesn't exist in the database.
Based on your fillable array on Post, the way you have the relationships setup looks correct as you are following naming conventions for keys and your belongsTo relationship methods have the correct name for convention.
$post->product() is not returning your Product model. It is returning a Relation type object (BelongsTo). This is used for querying the relationship. $post->product would be the dynamic property for the relationship that would return the already loaded relationship or load the relationship and give you the result.
Laravel 5.5 Docs - Eloquent - Relationships - Relationship Methods Vs. Dynamic Properties
If the relationships are setup correctly $post->product being null would mean the relationship doesn't actually exist in the database, no matching id in products for product_id or product_id being null. (assuming no foreign key constraint)
Side note: eager loading the relationship would be a good idea:
$posts = Post::with('product')->get();
I just came across this post because I got a similar error while working on a project.
What I discovered is that when you query a model with the all() method, it ignores the related softdeleted rows.
When you try to access them tho, you get the null
Remember to hit save() after associate and dissociate. Got me a couple of times:
$model->relation()->associate($record)->save();

Get specific columns using with() in laravel with appends fields in model

In my User model, I have an appends fields:
protected $appends = [
'is_admin'
];
It will appends is_admin field in every request by using with() eager loading. However, in some scenario I don't want to return is_admin field, I am trying to use the follows:
$this->belongsTo('App\Models\User')
->select(['id', 'username', 'first_name', 'last_name']);
But it doesn't work.
Is the appends field always be appended even I use custome select field ?
appends is used when the model is serialized; it 'appends' attributes to the output.
If you have a single model and you want to not have the appends accessors added to the serialized data, you can set them hidden.
Example:
$test = new class extends Illuminate\Database\Eloquent\Model {
protected $appends = ['is_admin'];
public function getIsAdminAttribute() {
return rand(0, 1);
}
};
dump($test->toArray()); // will contain 'is_admin'
$test->makeHidden('is_admin');
dump($test->toArray()); // will not contain 'is_admin'
// This can be applied to Eloquent Collections.
$model->relation->makeHidden('is_admin');
One way of doing it.
Simply put this result to a variable
$data = $this->belongsTo('App\Models\User')->select(['id', 'username', 'first_name', 'last_name']);
and use directly
$data->makeHidden("is_admin");
This will work for you

Laravel Eloquent Save to DB Using Create - Unhelpful Error

I get a very unhelpful error when I try and insert a new record in to my db. Does anyone have any idea where to start to solve this error?
user_id
That's all it says. (This is the name of one of my required fields in the table I'm saving to but it's not very descriptive.)
For reference here's my code:
$data = array(
'user_id'=>1,
'post_type'=>'0',
'post_title'=>'blah',
'description'=>'blah');
//it fails on this line
$id = Post::create($data);
Here's what my model looks like:
class Post extends Eloquent{
public static $rules = array(
'user_id'=>'required',
'post_type'=>'required',
'post_title' => 'required|max:25',
'description'=>'required'
);
public static function validate($data){
return Validator::make($data, static::$rules);
}
public function user(){
return $this->hasOne('User', 'id', 'user_id');
}
}
Tried getting rid of all relationships and validation in the model. That didn't work.
This is called mass-assignment in Laravel, what you need to do to get it working on your model is to set a protected array called $guarded to be empty. Add this to your model.
protected $guarded = array();
What this array does, it can prevent attributes to be mass-assigned with an array, if you don't want an attribute to be filled with the Model::create() method, then you need to specify that attribute in the $guarded array.
If instead you want to specify only the fillable attributes, Laravel's Eloquent also provides an array called $fillable where you specify only the attributes that you want to fill via the mass-assigment way.
Further reading:
Mass Assignment:
http://laravel.com/docs/eloquent#mass-assignment
Create Method:
http://laravel.com/docs/eloquent#insert-update-delete

Categories