Laravel - Elegant way to query the latest date on a database table - php

I have products and prices table (Temporal Data).
what is the best approach for getting the latest price of a specific product?
here's the basic structure of my two tables:
products table:
-ID
-name
prices table
-ID
-product_id
-amount
-effective_datetime
Product Model:
public function prices()
{
return $this->hasMany('App\Price', 'product_id', 'id');
}
Price Model:
public function product()
{
return $this->belongsTo('App\Product', 'product_id');
}
Im currently using this code to get the latest price of a product:
$product->prices->sortByDesc('effective_datetime')->first()->amount
As you can imagine, I have to call that long line all over my application just to get the latest price of a product. is there a better way?
My idea is to create a queryScope on my Price model like this:
public function scopeLatest($query)
{
return $query->sortBy('effective_datetime', 'desc')->first();
}
and Call
$product->prices->latest()->amount
but laravel is throwing an error "Call to undefined method Illuminate\Database\Eloquent\Collection::latest()"

In order to apply scopes to a relationship, you have to call them on the relationship's method (rather than its dynamic property) to allow query chaining. Try this:
$product->prices()->latest()->amount
(Originally commented)

In your case it would be ideal to have an accessor:
public function getPrice()
{
$this->prices()->sortBy('effective_datetime', 'desc')->first()->amount;
}
Now you can use it like $product->price.

Related

How can i make a relationship between my three Models where Distributor and Product model are directly connected with the Distributorproduct Model

Distributor Table - id
Product Table - id
Distributorprocuct Table - distributor_id, product_id
Distributor Model -
public function product() { return $this->hasMany(Distributorproduct::class); }
Product Model -
public function distributor() { return $this->hasMany(Distributorproduct::class); }
Distributorproduct Model -
public function distributor() { return $this->belongsTo(Distributor::class); }
public function product() { return $this->belongsTo(Product::class); }
If I write $product->distributor then it gives me all the details of distributorproduct but i need the details of distributor not distributorproduct .
If i write $distributor->product then it gives me all the details of distributorproduct but i need the details of product not distributorproduct .
Thanks in advance...
It is not clear to me what is the relationship between Product, DistributorProduct and Distributor, but I think what you want is to specify a different kind of relationship between Distributor and Product (and Product -> Distributor).
In your Distributor modal class you can try defining your product method like this:
public function product() {
return $this->hasOneThrough(Product::class, Distributorproduct::class);
}
and the distributor method in the Product modal class like this:
public function distributor() {
return $this->hasOneThrough(Distributor::class, Distributorproduct::class);
}
But your mileage may vary, this kind of relationship is ok only if a Product has a single distributor (likely), and a distributor has a single Product (unlikely I guess).
The Laravel docs have a pretty good documentation about relationships. Looks especially at the Has One Through and the Has Many Through paragraphs.

pivot table relationship Laravel

I have the following relation:
RAB hasMany products.
products belongsToMany RAB
but this products also hasMany currency that belongsToOne RAB itself.
it looks like this.
in RAB model:
public function products()
{
return $this->belongsToMany('App\ModelKeuangan\ProductsModel', 'rab_products', 'rab_id', 'products_id');
}
in products model:
public function rab()
{
return $this->belongsToMany('App\ModelUnitKerja\Perencanaan\RabModel', 'rab_products', 'products_id', 'rab_id');
}
rab_products is my intermediate/join table.
it works just fine when im syncing products data for RAB. but i cant get how to make eloquent model for syncing Currency data to rab and products.
do i need to make model for currency too? if yes, how do i define it?
my plan is make a pivot like this, but can i make relation inside pivot table?
class RabProducts extends Pivot {
//relation function to currency
}
and change my products model something like:
public function rab(){
return $this->belongsToMany('App\ModelUnitKerja\Perencanaan\RabModel')->using('App\RabProducts');
}
Create the currency model and add foreign_key product_id:
php artisan make:model Currency
Build the one-to-many between Product and Currency
and you need to add product_id in your currencies table.
In your Currency Model:
public function product() {
return $this->belongsTo('App\Product', 'product_id');
}
In your Product Model:
public function currencies()
{
return $this->hasMany(\App\Currency::class, 'product_id', 'id');
}
So that you can call it like this:
RAB::with(['products' => function($query) {
$query->with('currencies');
}])->get();
Unfortunately, the foreign_key between products and rabs is in pivot table, you cannot create the hasmanythrough with currency directly.
You can call the currency by products. Or you can create a pivot model, and then use hasmanythrough.

Laravel Relaton Return null

I have two table
one is products another is offers
products
---------
id | offer_id
offers
---------
id | product_id
Now I want to get all offers against a product
In my product model I wrote
public function getOfferDetails()
{
return $this->belongsTo('App\Offer');
}
but it return null.
You want to get all offers that belong to a product, right? Have you tried this:
public function getOfferDetails()
{
return $this->hasMany('App\Offer');
}
In your Product model?
Need to define how your relationships are. Based on what you have
A Product can have 0 - many offers and an Offer belongs to 1 Product.
You will need some foreign key to match the models. OTB Laravel will attempt to use the method name appended with _id as the foreign key. Since your method name is different, you need to pass the foreign key as the second parameter in your relationship method.
Products Model should have
public function getOfferDetails()
{
return $this->hasMany('App\Offer', 'product_id');
}
Offer Model should have
public function getProduct()
{
return $this->belongsTo('App\Product', 'product_id');
}
Laravel Documentation that might help out as well.
This is what you're looking for I think:
public function getOfferDetails()
{
return $this->hasMany('App\Offer', 'id', 'offer_id');
// as ceejayoz mentioned in comments, Laravel should be able to detect this themselves. The below would work the exact same as above
// return $this->hasMany('App\Offer', 'id', 'offer_id')
}
$product->getOfferDetails()->get();

Querying with relationship not working

I am trying to grab an InvoiceDetails record and the matching Product record via the product foreign key.
This isn't working:
$r = InvoiceDetail::with('products')->find(52184)->toArray();
The 2 database calls are
SELECT * FROM `invoice_details` WHERE `id` = '52184' LIMIT 1
SELECT * FROM `products` WHERE `products`.`id` in ('0')
Where am I going wrong?
Table Structure of invoice details:
Schema::create('invoice_details', function (Blueprint $table) {
$table->increments('id');
$table->integer('invoice_id')->unsigned();
$table->integer('product_id')->unsigned();
$table->integer('quantity');
$table->foreign('product_id')->references('id')->on('products')->onDelete('restrict')->onUpdate('cascade');
$table->foreign('invoice_id')->references('id')->on('invoices')->onDelete('cascade')->onUpdate('cascade');
});
Table structure for Products:
Schema::create('products', function(Blueprint $table)
{
$table->increments('id');
$table->string('name');
});
Products Model:
class Product extends \Eloquent
{
public function products()
{
return $this->hasMany('InvoiceDetail');
}
}
Invoice Details Model:
class InvoiceDetail extends \Eloquent
{
public function details()
{
return $this->belongsTo('Invoice');
}
public function products()
{
return $this->belongsTo('Product');
}
}
Your relationships are weird. (Okay, that wasn't really any longer.)
Assuming that an Invoice can belong to many Products (with specific details about each such as quantity), and that a Product can belong to many Invoices, you have a classic pivot table scenario. In which case, you're doing extra work and making life more difficult for yourself than it has to be.
If that's the case, there are a few steps you can take to reduce your code and make life easier:
Remove the InvoiceDetails model. Laravel can handle pivot tables on its own pretty well. So unless you have something really custom that you need the pivot table model to handle, you don't need it.
Update your Product model. You have a products() method in the Product model. That doesn't really make any sense. Don't products belong to invoices? Let's fix that.
class Product extends Eloquent
{
public function invoices()
{
return $this->belongsToMany('Invoice', 'invoice_details', 'product_id', 'invoice_id');
}
}
The additional parameters indicate the pivot table name, the column name for the Product model identifier, and the column name for the Invoice model identifier, respectively.
Update your Invoice model. You didn't paste it here, but I'll assume it has a relationship for invoice details. If not, well, oops! Because an invoice can belong to many products, essentially the inverse of the products relationship we just defined, it's defined it pretty much the exact same way.
class Invoice extends Eloquent
{
public function products()
{
return $this->belongsToMany('Product', 'invoice_details', 'invoice_id', 'product_id');
}
}
You now have a many-to-many relationship between Products and Invoices, that is retrieved using intuitive relationship methods! Huzzah.
Hey wait, where's my quantity?
You'll have to figure that one out on your own. :)
Got the answer (there is 2 hours of my life I'm never getting back) I had to manually add the fk and pk. So in my InvoiceDetails model it should have looked like this
public function products()
{
return $this->belongsTo('Product', 'product_id', 'id');
}

Laravel 4 Eloquent/Model Relationships

I am setting up several Models an want to know the correct approach to table structure and Model relationships.
Let's assume we have a shop containing products, each with properties size and color.
Table products
id
size_id
color_id
price
Table sizes
id
name
Table colors
id
name
Models
class Product extends Eloquent {
public function size() {
return $this->hasOne('Size', 'id');
}
public function color() {
return $this->hasOne('Color', 'id');
}
}
class Size extends Eloquent {
public function products() {
return $this->belongsTo('Product', 'size_id');
}
}
class Color extends Eloquent {
public function products() {
return $this->belongsTo('Product', 'color_id');
}
}
This way I can easily echo the color/size of a product using {{ Product->size['name'] }}. Also, I want to pass Eloquent the size's foreign key size.id like Product::where('size_id', '5') rather than its name size.name.
Problem: Doing $products = Product::has('size', '=', '5')->get() does not give me any results, yet doing $products = Product::where('size_id', '5')->get() does.
I am pretty confused, what went wrong?
I think that the problem is that your ::has() method is looking for products with exactly 5 different sizes on each specific product, which would assume that you would be using $this->hasMany('Size') in your Product model. Where as the ::where() method is returning results where the size of the product is 5.
In the documentation they use an example of comments. A post will have a list of comments. You can find posts that have at least one comment (ie. Post::has('comments')->get()) or you can find posts that have more than 3 comments (ie. Post::has('comments', '>=', '3')->get()).
http://laravel.com/docs/eloquent#querying-relations

Categories