getting model belongsTo attributes
Your issue here is that you define a non-relationship method price()
but you call it as if it was a relationship method (i.e. you call it as a property and not as a method).
The code you should be using to get the Coupon
's price is:
$coupon->price();
The reason the relationship thing works (i.e. $coupon->batch
over $coupon->batch()
) is that Laravel has some special logic in - basically it catches you trying to access a property (->batch
in this case) and checked to see if there's a corresponding method (->batch()
). If there is one, it calls it and expects it to return a relationship, and then it calls ->first()
of ->get()
on that relationship depending on whether it's a single-result or a multiple-result relationship.
So what's happening in your code here is that you call $coupon->price
and Laravel, behind the scenes, decides that being as there's a ->price()
method it must be a relationship. It calls the method, checks that it returns one of the Laravel relationship types, and when it doesn't, throws that LogicException
.
The general rules of thumb is this:
- If you want an actual property (i.e. anything defined on the table) or the results of a relationship query, use property access
- If you want anything else (i.e. behaviour you're defined using a method) you must call the method directly
Also, sometimes there is a good reason to call a relationship as the method rather than the property - calling the method returns something you can add query builder constraints on to, whereas calling the property gets you all the results. So say Coupon
s can be enabled or disabled (for example), the following holds:
-
$batch->coupons
gets you all coupons that the batch has -
$batch->coupons()->whereEnabled(1)->get()
gets you all enabled coupons for a given batch -
$batch->coupons()->orderBy('order')->get()
gets you all the coupons that the batch has, ordered by a field calledorder
-
$coupon->batch
gets you the given coupon's batch
Hopefully that explains the difference between Eloquent's use of methods versus properties for relationships, and why all augmented behaviour (like price on coupon in your example, but not price on batch, which is inherent behaviour) must be called as a method.
Related videos on Youtube
Zayin Krige
Hello! I'm Zayin I have a love for development and have been coding for fun and professionally for 33 years. I started out with GWBasic(3 years) and have worked in Turbo Pascal (5 Years), ASM (2 Years), Delphi (7 Years), C/C++ (4 Years), Java (10 years), Kotlin (3 Years), Swift (5 Years), Objective-C (9 Years), Javascript (5 Years), PHP (6 Years), Python (2 Years) and PERL (2 Years) I have built numerous mobile apps for both iOS and Android, as well as cross platform apps using React Native. I have built NodeJs backends hosted on AWS, and PHP/Laravel backends which are self hosted. I have a wide range of experience across many different development related fields and bring a vast depth of systems knowledge with me. I have built systems using Interbase, Firebird Database, SQL Server, MySQL, CouchDB and DynamoDB on AWS. I owned and sold a point of sale company that had installations across Southern Africa. I co-founded a vending (TopItUp) startup in 2009 and sold my shares in 2013
Updated on September 14, 2022Comments
-
Zayin Krige over 1 year
class Batch extends Eloquent { public function coupons() { return $this->hasMany('Coupon'); } } class Coupon extends Eloquent { public function batch() { return $this->belongsTo('Batch'); } public function price() { $batch = $this->batch; return $batch->price; } }
$coupon->price
gives me this error:-LogicException Relationship method must return an object of type Illuminate\Database\Eloquent\Relations\Relation
However,
$coupon->batch->price
works just fine.What am I missing?
-
Zayin Krige about 10 yearsstrangely enough, $this->batch->price also didnt work. I did try that option along the way. I think @alexrussel has nailed it
-
Zayin Krige about 10 yearsthanks for the excellent explanation of the laravel magic. I assumed there was something like that happening behind the scenes, but I couldn't quite pin it down
-
alexrussell about 10 yearsYeah it's something that's not really documented. The collection versus query builder is mentioned in the Eloquent relationships docs, but not the fact that it can't be used for other things. Glad to be of help, anyway.
-
Richard Fu over 5 yearsI think you have a typo:
->first()
or->get()