There is a model Invoice which equals to a purchase basket and model InvoiceItem which stores items inside a specific invoice. The model invoice has status field, if its value is 2999 and someone has verified it, it is successful. I need to get invoice items which are sold. Here is codes:
class Invoice extends Model
{
protected $fillable = [];
protected $table = 'payment_invoices';
public function user()
{
return $this->belongsTo(User::class, 'user_id');
}
public function scopeSuccessful($query)
{
return $query->where('status', 2999)->where('verified_at', '<>', null);
}
}
and
class InvoiceItem extends Model
{
protected $fillable = [];
protected $table = 'payment_invoice_items';
public function invoice()
{
return $this->belongsTo(Invoice::class, 'invoice_id');
}
public function user()
{
return $this->belongsTo(User::class, 'user_id');
}
public function vendor()
{
return $this->belongsTo(Vendor::class, 'vendor_id');
}
public function scopeNotDeleted($query)
{
return $query->where('deleted_at', null);
}
public function scopeSold($query)
{
return $query->notDeleted()->whereHas('invoice', function ($q) {
$q->successful();
});
}
}
The following statement
InvoiceItem::sold()->take(10)->get()
returns 10 sold items but it is very slow. it takes about 4 seconds to retrieve the information while the query
select *
from laravel.payment_invoice_items pii
join laravel.payment_invoices pi
on pi.id = pii.invoice_id
and pii.deleted_at isnull
and pi.status=2999
and pi.verified_at notnull
limit 10
takes about 800 milliseconds. Eloquent is very inefficient. Is there any solution to use the eloquent and get the same efficiency here?
Related
I am using Laravel 5.6 and would like to get a collection of featured articles published in the last 2 weeks sorted by the number of views over the last week. Ideally using pagination on the model.
DB:
author (id, name, ....)
article (id, title, content, publish_date, ...)
article_view (id, article_id, date, views)
featured_article (id, article_id, created_at)
Models
class Author extends Model
{
protected $table = 'author';
public function articles()
{
return $this->hasMany(Article::class,'id','author_id');
}
}
class Article extends Model
{
protected $table = 'article';
public function author()
{
return $this->hasOne(Author::class,'id','author_id');
}
}
class FeaturedArticle extends Model
{
protected $table = 'featured_article';
static public function getFeaturedArticles($limit)
{
$articles = FeaturedArticles::where('created_at', '>=', Carbon::now()->subDays(14))->with(['article.author','article.articleViews'])->paginate($limit);
}
}
Then in the Controller or Feature or Job
$featured_articles = FeaturedArticle::getFeaturedArticles(15);
This works fine, but the results aren't sorted yet. How to sort the paginated results by the sum of article_view.views over 7 days. Is it possible?
Assuming you want the most viewed article first:
class FeaturedArticle extends Model
{
public function articleViews() {
return $this->hasMany(ArticleView::class, 'article_id', 'article_id');
}
}
$articles = FeaturedArticle::where('created_at', '>=', Carbon::today()->subDays(14))
->withCount(['articleViews' => function($query) {
$query->select(DB::raw('sum(views)'))
->where('date', '>=', Carbon::today()->subDays(7));
}])
->orderByDesc('article_views_count')
->with('article.author', 'article.articleViews')
->paginate($limit);
I replaced Carbon::now() with Carbon::today(). Otherwise, you wouldn't get articles that were published 14 days ago before the time of now().
Also, your relationships are incorrect:
public function articles()
{
return $this->hasMany(Article::class, 'author_id', 'id');
}
public function author()
{
return $this->belongsTo(Author::class, 'author_id', 'id');
}
I have a problem with a many to many relationship and the translations of the terms.
I have 4 tables:
products
- id, price, whatever
products_lang
- id, product_id, lang, product_name
accessori
- id, active
accessori_lang
- id, accessori_id, lang, accessori_name
I'm trying to assign accessories to products with an intermediate table named:
accessori_products
this is the model for Product:
class Product extends Model {
protected $table = 'products';
public function productsLang () {
return $this->hasMany('App\ProductLng', 'products_id')->where('lang','=',App::getLocale());
}
public function productsLangAll() {
return $this->hasMany('App\ProductLng', 'products_id');
}
public function accessori() {
return $this->belongsToMany('App\Accessori', 'accessori_products');
}
}
this is the model for productLng:
class ProductLng extends Model {
protected $table = 'products_lng';
public function products() {
return $this->belongsTo('App\Product', 'products_id', 'id');
}
}
Then I have the model for Accessori:
class Accessori extends Model {
protected $table = 'accessori';
public function accessoriLang() {
return $this->hasMany('App\AccessoriLng')->where('lang','=',App::getLocale());
}
public function accessoriLangAll() {
return $this->hasMany('App\AccessoriLng');
}
public function accessoriProducts() {
return $this->belongsToMany('App\Products', 'accessori_products', 'accessori_id', 'products_id');
}
}
And the model for AccessoriLng:
class accessoriLng extends Model {
protected $table = 'accessori_lng';
public function accessori() {
return $this->belongsTo('App\Accessori', 'accessori_id', 'id');
}
}
the last model is for the relationship between the two tables above:
class ProductAccessori extends Model {
protected $table = 'accessori_products';
public function accessoriProducts() {
return $this->belongsTo('App\Product', 'accessori_id', 'products_id');
}
}
I'm trying to get the accessories of each product and to get also the translation but I'm having a lot of problem with this.
It's my first time with a many to many relation with translations too.
Can anyone put me on the right direction?
controller
$products = Product::has('accessori')->with([
'productsLang ',
'accessori' => function ($accessori){
$accessori->with([
'accessoriLang'
]);
}
])->get();
return $products;
you'll get products with accessori that has accessoriLang.
namespace App;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use Laravel\Scout\Searchable;
class Event extends Model
{
protected $table = 'events';
public $timestamps = true;
use Searchable;
use SoftDeletes;
protected $dates = ['deleted_at'];
public function entities()
{
return $this->belongsTo('App\Entity', 'entity_id');
}
public function users()
{
return $this->belongsTo('App\User', 'id');
}
public function events()
{
return $this->belongsTo('App\DirtyEvent', 'id');
}
public function toSearchableArray()
{
$data = $this->toArray();
$data['entities'] = $this->entities->toArray();
return $data;
}
}
This is my model for Event, as you can see I am using toSearchableArray which is Laravel scout function to import 'relations' to algolia. However the problem is that sometimes it is empty. So for example
event id 1 has entity_id 1
but in another example
event id 2 has entity_id = null
How can I modify this function to check if the entities() relation is not empty before putting it into array?
if i understand u correctly this should help. if the relationship does not exist return an empty array and scout won't update the index
public function toSearchableArray()
{
if(is_null($this->entities)){
return [];
}
$this->entities
return $this->toArray();
}
please update foreign_key in relation as this
user_id as foreign_key instead of id
event_id as foreign_key instead of id
public function users()
{
return $this->belongsTo('App\User', 'user_id');
}
public function events()
{
return $this->belongsTo('App\DirtyEvent', 'event_id');
}
I think if load the relation before the toArray().
public function toSearchableArray()
{
$this->entities;
return $this->toArray();
}
I have create a morphMany relationship for ratings and I'm having a problem loading the ratings relationship data inside the model using the model->load or model::with method both of them aren't letting me use the collections model builder.
if I do this inside a method of a model it throws an error:
$all = this->ratings()->get();
return $all;
Call to undefined method Illuminate\Database\Query\Builder::ratingInfo()
I need the ratings query builder so I can then query and filter the results but It's not using the query builder and even if I make this a scope it's still throws the same error.
all code:
class Product extends Model
{
use Rateable;
protected $table = "products";
protected $fillable = [
'title',
'sku',
'quantity',
'unit_price',
'created_by', 'updated_by'
];
public function created_by() {
return $this->belongsTo('App\User', 'created_by', 'id');
}
public function updated_by() {
return $this->belongsTo('App\User', 'updated_by', 'id');
}
public function ratings() {
return $this->morphMany('App\Rating', 'rateable');
}
public function ratingInfo() {
$all = $this->ratings()->get() error using get request for eager loading;
// i want to query like this
$two_star = $all->filter(function ($item, $key) {
return $item->rating === 2;
});
return $all;
}
}
public function show($id) {
$product = Product::findOrFail($id);
// it doesn't seem to matter if use the keyword ::with('ratingInfo')
$product->load('ratingInfo', 'created_by', 'updated_by');
return response()->json($product, 200, ['Content-Length' => strlen(json_encode($product))]);
}
class Rating extends Model
{
protected $table = 'ratings';
protected $fillable = ['rating', 'comment', 'user_id', 'rateable_id', 'rateable_type'];
public function rating()
{
return $this->morphTo();
}
}
Using phone numbers and user and companies as an example:
class PhoneNumber extends Model
{
/**
* Get all of the owning callable models.
*/
public function callable()
{
return $this->morphTo();
}
}
class Company extends Model
{
/**
* Get all of the model's phone numbers.
*
* #return mixed
*/
public function phoneNumbers()
{
return $this->morphMany(PhoneNumber::class, 'callable');
}
}
class User extends Model
{
/**
* Get all of the model's phone numbers.
*
* #return mixed
*/
public function phoneNumbers()
{
return $this->morphMany(PhoneNumber::class, 'callable');
}
}
To save a phone number to a user or company would be like this:
$phoneNumber = new PhoneNumber(['number' => '555-555-5555']);
$user->phoneNumbers()->save(phoneNumber);
$phoneNumber = new PhoneNumber(['number' => '555-555-5555']);
$company->phoneNumbers()->save(new PhoneNumber(phoneNumber));
Then to access the phone number collections associated with each, simply:
$user->phoneNumbers // this is a Collection
$company->phoneNumbers // this is a Collection
$user->phoneNumbers->count() // access to all Collection methods as this point
I am trying to do a single query to get back an order and the card to charge, but getting an error.
Card model:
class Card extends Eloquent {
protected $guarded = array();
public static $rules = array();
public function user()
{
return $this->belongsTo('User');
}
public function orders()
{
return $this->hasMany('Order');
}
}
Order model:
class Order extends Eloquent {
protected $guarded = array();
public static $rules = array();
public function user()
{
return $this->belongsTo('User');
}
public function card()
{
return $this->hasOne('Card');
}
public function address()
{
return $this->belongsTo('Address');
}
public function orderItems()
{
return $this->hasMany('OrderItem');
}
}
What I am trying to get back:
$order = Order::with('card')->find($id);
This obviously doesn't work and I have tried several combos. I think the issue is with my models/relationships.
Any idea how I can get back the order with the card/token details?
DB info: Each order can have only one card_id and each card can be in many orders. There is no order_id in the card.
Orders table basically:
id | card_id
Cards table:
id | token
Trying to get the token col to return with the Order.
In your Order model, you need to change this:
public function card()
{
return $this->hasOne('Card');
}
to this:
public function card()
{
return $this->belongsTo('Card');
}
The reason is that you are defining the inverse of the hasMany relationship. With the belongsTo relationship, Eloquent will look for a card_id column on the orders table.