How to group similar records in Laravel? - laravel

I have a problem with grouping records based on their name of the color. Here I would like to explain with an example. I have "BLUE JEAN(3)" with the quantity 3 & "BLUE JEANS MET(7)" with the quantity 7, can we group together ? I want the output BLUE JEAN(10).
Note: These are already distributed in database with different ID. I have lots of colors so I need to group only those similar colors and need to populate for searching.
Here is my structure of coding:
Model:
class MyVehicle extends Model
{
protected $fillable = [
'name',
'color_id',
'stock_number'
];
}
Controller:
public function searchVehicleColor()
{
$vehicles_colors = DB::table('vehicles')
->select(DB::raw('COUNT(vehicles.color_id) as color_count'), 'colors.color')
->leftjoin('colors', 'colors.id', '=', 'vehicles.color_id')->get();
return view('public/search_result', compact('vehicles_colors'));
}
View:
#foreach($vehicles_colors as $vehicles_color)
<li>
{{ Form::checkbox('color[]', $vehicles_color->color, null, ['class' => 'color field','id'=>$vehicles_series_color->color,'onClick'=>'reply_click(this.id)']) }}
<label for="{{$vehicles_color->color}}">{{$vehicles_color->color}}({{$vehicles_color->color_count}})</label>
<div class="check"></div>
</li>
#endforeach
Here is the output , I just want to merge highlighted data.
Please help, Thanks in advance.

public function searchVehicleColor(){
$vehicles_colors = DB::table('vehicles')
->select(DB::raw('COUNT(vehicles.color_id) as color_count'),'colors.color')
->leftjoin('colors', 'colors.id', '=','vehicles.color_id')->groupBy('name')->get();
return view('public/search_result', compact('vehicles_colors'));
}

Related

How to create a hasMany relationship with different models in folder?

I have a strange Laravel 9 setup due to being constrained to a very ancient database.
I'm trying to come up with a clean way to create a hasMany relationship to multiple models located in a folder. I believe it would be easiest explained with diagrams:
app/Models/
- Customer
app/Models/Records/
- Orange
- Green
- Blue
Now, all of these records has some connection to customer, but these are all different as well, for example, orange refers to customer using cid, where Green might use customerid.
I've already set up logic where every record model has a customer belongsTo relationship depending on the different field names.
public function customer()
{
return $this->belongsTo('App\Models\Customer', 'CustomerId');
}
I need to create a records() function in the Customer model, that pulls in all of these Records where found. I can't create any new tables that would be stored on the DB.
For multiple tables (models) to be connected as hasMany is probably not possible out of the box in Laravel.
However if you do really need to combine them all, I did once but it is not pretty.
First add following to each of your App\Records\Model in example is Green
class Green extends Model
{
protected $table = 'GreenRecords';
....
....
// this is to append/add extra fields into your model
// that not exist inside the table it self
protected $appends = [
'product_data',
'stuffs',
];
// relationship to App\Models\Customer
public function customer()
{
return $this->belongsTo(Customer::class, 'customerid', 'id');
}
// you can use it later as Green::query()->customer($id)->get()
public function scopeCustomer($query, $id)
{
return $query->where('customerid', $id);
}
// you can add here as many data as you like from table GreenRecords,
// this will make Green Orange and Blue as if they have common fields
// you can also separate them by adding add each custom field to $appends
public function getProductDataAttribute()
{
return [
'name' => $this->name,
'color' => $this->color,
'stuffs' => $this->stuffs,
'other_stuffs' => $this->other_stuffs,
];
}
public function getStuffsAttribute()
{
return $this->stuffs;
}
}
And now for the Customer model
class Customer extends Model
{
// your Customer relation to Orange
public function oranges()
{
return $this->hasMany(Orange::class, 'cid', 'id');
}
// your Customer relation to Green
public function greens()
{
return $this->hasMany(Green::class, 'customerid', 'id');
}
public function getRecords(): Collection
{
// we can not use collection merge due to same 'id' in Orange and Green
$collections = collect();
if ($oranges = Orange::query()
->customer($this->id)
->get()
) {
foreach ($oranges as $record) {
$collections->push($record);
}
}
if ($greens = Green::query()
->customer($this->id)
->get()
) {
foreach ($greens as $record) {
$collections->push($record);
}
}
return $collections;
}
}
So now you can do
$customer = Customer::find(3);
$records = $customer->getRecords(); // result will be a collection
And inside your blade you can access them
#foreach ($records as $record)
{{ $record->stuffs }}
{{ $records->product_data['other_stuffs'] }}
#endforeach
A collection can be filtered and sorted
$records->where('product_data.stuffs', 'abc')->sortBy('name');
The only problem here is the records id where Orange can have the same id as Green and Blue.
Best is to add new field into Orange Green and Blue
$table->uuid('record_id')->nullable();
Hope this can help you out.
None of these solutions quite achieved what I was looking for in terms of simplicity, and in my case my database is quite out of date and slow, so I ended up landing on a solution that is quite simple and faster than everything posted for my use case:
public function records()
{
return [
"Orange" => $this->hasMany(\App\Models\Records\Orange::class, 'CustomerId', 'Id')->get(),
"Blue" => $this->hasMany(\App\Models\Records\Blue::class, 'Customerid', 'Id')->get(),
"Purple" => $this->hasMany(\App\Models\Records\Purple::class, 'customerid', 'Id')->get(),
"Black" => $this->hasMany(\App\Models\Records\Black::class, 'CustomerId', 'Id')->get(),
"Green" => $this->hasMany(\App\Models\Records\Green::class, 'Customerid', 'Id')->get(),
"Cyan" => $this->hasMany(\App\Models\Records\Cyan::class, 'CustomerId', 'Id')->get()
];
}
This achieves what I was looking for in terms of setting up the relationships when the customerId field was subject to change on the other tables, and is pretty readable overall.

Laravel How to display related products?

I have ShopController . Now I am displaying products in random order from database.
Here is the code
$productsLike = Product::with('categories')->where('slug', '!=', $slug)->inRandomOrder()->take(4)->get();
What i should do to display products related to the same category as current product?
I would make a local scope on your Product model to make things reusable.
public function scopeRelatedProducts($query, $count = 10, $inRandomOrder = true)
{
$query = $query->where('category_id', $this->category_id)
->where('slug' '!=' $this->slug);
if ($inRandomOrder) {
$query->inRandomOrder();
}
return $query->take($count);
}
Then you could do something like:
$related = Product::relatedProducts(4, true)->with('categories')->get();
This assumes the column your Product table stores the relationship to a Category follows the Laravel naming convention (e.g. RelatedModelName_id).
You could also replace the slug_id with the Product id
You can then use the resulting $related variable in your view, so assuming your using the above in a Product show controller method, you might do:
class ProductController
{
public function show (Product $product)
{
$related = $product->relatedProducts(4, true)->with('categories')->get();
return view('products.show', compact('product', 'related');
}
}
#foreach ($related as $item)
<h5>{{ $item->name }}</h5>
<p>{{ $item->description }}</p>
#endforeach
You can check with category id.
$productsLike = Product::with('categories')
->where('category_id_column', $category_id)
->where('slug', '!=', $slug)
->inRandomOrder()->take(4)->get();

Building complex Eloquent query using belongsToMany relationship, foreign table and whereIn()

In a Laravel 5 app, I have 5 tables - users, books, authors, followers and activity_feeds.
Users can follow authors and a book can have several authors.
When a book is made, an activity_feeds entry is made that references the book_id.
I need to build an eloquent query to get a collection of activity_feeds for each users, to iterate over in their home page activity feed.
My Book model includes
public function authors()
{
return $this->belongsToMany('App\Author')->withTimestamps();
}
The activity_stream table looks like this (with example data)
id (1)
user_id (3)
type (New Book)
book_id (18)
created_at etc
and my User controller includes
public function feedItems()
{
return $this->hasMany('App\ActivityFeed');
}
public function userFollowings()
{
return $this->belongsToMany('App\User', 'followers', 'follower_id', 'subject_id')->withTimestamps();
}
public function authorFollowings()
{
return $this->belongsToMany('App\Author', 'followers', 'follower_id', 'author_id')->withTimestamps();
}
My current query (which isn't working), contained in the User model is
public function getactivityFeedsAttribute()
{
$userFollowings = $this->userFollowings()->pluck('subject_id')->toArray();
$authorFollowings = $this->authorFollowings()->pluck('author_id')->toArray();
$userFeeds = ActivityFeed::whereIn('user_id', $userFollowings)
->orwhereIn('book_id', function($query){
$query->select('id')
->from(with(new Book)->getTable())
->whereHas->authors()
->whereIn('id', $authorFollowings);
})
->get();
return $userFeeds;
}
$userFollowings and $authorFollowings are working fine.
I'm not sure I'm using the correct syntax for data[book_id] to pluck the book id from the activity_feeds row, and I'm really not sure if I can nest a table look up or use $query like this.
It also seems VERY complicated. Am I might be missing something much more straight forward?
In the blade I am calling like this
#forelse ($user->activityFeeds as $activityFeed)
<div class="row">
<div class="col-2">
{{ $activityFeed->user->firstname }}
</div>
<div class="col-2">
{{ $activityFeed->type }}
</div>
</div>
<hr>
#empty
No activity yet
#endforelse
Which works if I just query 'ActivityFeed::whereIn('user_id', $userFollowings)'
I'll rewrite the query in an answer because comments aren't very legible.
public function getactivityFeedsAttribute()
{
$userFollowings = $this->userFollowings()->pluck('subject_id')->toArray();
$authorFollowings = $this->authorFollowings()->pluck('author_id')->toArray();
$books = Book::whereHas('authors', function ($query) use ($authorFollowings) {
// Have to be explicit about which id we're talking about
// or else it's gonna throw an error because it's ambiguous
$query->whereIn('authors.id', $authorFollowings);
})->pluck('id')->toArray();
$userFeeds = ActivityFeed::whereIn('user_id', $userFollowings)
->orwhereIn('book_id', $books)
->get();
return $userFeeds;
}

Laravel 5.3 access hasone in elequant from view

I'm trying to access a relations table from a collection of data passed in from the controller. I am able to iterate the collection in my view but I am unable to access the relationship data.
There are 2 tables:
stocks (default model)
stock_datas (has a foreign key stock_id which is already setup)
Controller:
public function getstock() {
return view('vehicles.getstock', ['stock' => \App\Stock::all()]);
}
Model (App\Stock) and then (App\StockData)
// From stock model:
public function stockdata() {
return $this->hasOne('App\StockData');
}
// Stock Data model:
public function stock() {
return $this->belongsTo('App\Stock');
}
View (loop):
#foreach ($stock as $k => $v)
{{ print_r($v->stockdata()->get())->year }}
#endforeach
When I try the query below, I get a
Undefined property: Illuminate\Database\Eloquent\Collection::$year (View: F:\websites\tempsite\resources\views\vehicles\getstock.blade.php)
However, year is a column in the stock_datas table.
I am also able to print_r data from the \App\StockData() table so the reference to the table is correct as doing print_r(\App\StockData::all()) from the controller does return all the rows as expected.
What am I doing wrong?
Since it's one to one relation, you should do it like this:
#foreach ($stock as $v)
{{ $v->stockdata->year }}
#endforeach
First one You have to change {{ print_r($v->stockdata()->get())->year }} this line, remove print_r. Next one in foreach loop you can do something like this
#foreach($stock as $one)
{{ $one->stockadata()->first()->year }}
#endforeach
For better solution you should check if isset $one->stockadata()->first()
and after that call ->year. Finally code should be like this
#foreach($stock as $one)
{{ isset($one->stockadata()->first()) : $one->stockadata()->first()->year : 'Default' }}
#endforeach
When calling get() method on any relationship You will always receive collection, no matter what relationship You have.
There are at least two (2) ways to solve Your problem:
1. $v->stockdata->year
2. $v->stockdata()->first()->year
I would suggest You to use first one, because Your stockdata has 1:1 relationship.
Good luck!
For example:
Stock.php model
class Stock extends Model
{
protected $primaryKey = 'id';
function stockdata() {
return $this->hasOne('App\StockDatas', 'id', 'stock_id');
}
public function getStock(){
return Stock::with('stockdata')->get();
}
}
In contriller
public function getstock(Stock $stock) {
return view('vehicles.getstock', ['stock' => $stock->getStock]);
}
view
#foreach ($stock as $k => $v)
{{ $v->stockdata->year }}
#endforeach

How to safely access other users and other model's records inside Blade template

I have 3 models in my app Users, Sales and Plans, when I render sales for each customer (due to storing) I only get id's for other users and models related to that sale (like account manager, owner, plan), now I'm trying to use those ID's inside blade to get names or other rows based on ID and model. Here is the show function:
public function show($id) {
$user = User::find($id);
$sales = Sale::where('customer_id', '=', $id)->get();
return view('profiles.customer', ['user' => $user, 'sales' => $sales]);
}
And in blade I get all those sales like:
#foreach ($sales as $sale)
<li>
<i class="fa fa-home bg-blue"></i>
<div class="timeline-item">
<span class="time"><i class="fa fa-clock-o"></i> {{$sale->created_at->format('g:ia, M jS Y')}}</span>
<h3 class="timeline-header">{{$user->name}} became a customer</h3>
<div class="timeline-body">
<p>Date: {{$sale->sold_date}}</p>
<p>Price: {{$sale->sale_price}}</p>
</div>
</div>
</li>
#endforeach
So inside each record I have like "account_manager_id", "agent_id", "owner_id", "plan_id".
Currently I have this solved by adding public static function (this is for users, have same function for Plan model as well) in Sale model class:
public static function getUser($id) {
return User::where('id', $id)->first();
}
And I'm using it like this in Blade:
Account manager: {{$sale->getUser($sale->account_mgr_id)->name}}
Is this the safest and best way to do it? Or there is something I'm overlooking here?
You need to add relationships in your Sales Model.
class Sales extends Eloquent {
.....
.....
public function accountManager() {
return $this->hasMany('App\User', 'account_manager_id');
}
public function agents() {
return $this->hasMany('App\User', 'agent_id');
}
public function owner() {
return $this->hasOne('App\User', 'owner_id');
}
}
Now $sales->agents will give you a user with agent_id as id in User table.
Update your hasOne, hasMany relationships as your need. Laravel Documentation.
From your blade template, your access your AccountManager as
#foreach($sales->accountManager as $manager)
Name: {{ $manager->name}}
#endforeach
I think you could use Eloquent relationships. Taking your example, you should define relationship in your User model:
<?php
class User extends Eloquent {
public function sales() {
return $this->hasMany(Sale::class, 'customer_id');
}
}
Then, whenever you need to get sales of that user (entries, that relate via customer_id column), just simply do
<?php
$user = User::find($id);
$sales = $user->sales;
This is very fun when when you have to print out list of users that have sales, for example
<?php
public function showUsersWithSales() {
$users = User::with('sales')->get();
return view('users-with-sales', compact('users'));
}
users-with-sales.blade.php example:
#foreach ($users as $user)
User: {{ $user->name }}<br>
Sales:<br>
#foreach ($user->sales as $sale)
{{ $sale->amount }} {{ $sale->currency }} # {{ $sale->created_at }}<br>
#endforeach
<hr>
#endforeach
It would print all users with their sale amount and currency, followed by date when it was created.
This sample takes into account, that your User model has name attribute and your Sale model has amount, currency, created_at and customer_id fields in your database.
To reverse the action, say you have a sale and want to know who made it, just simply define a relationship!
<?php
class Sale extends Eloquent {
public function customer() {
return $this->belongsTo(User::class, 'customer_id');
}
}
Hope that helps!
Eloquent Relationship is your friend, https://laravel.com/docs/5.2/eloquent-relationships and you can solve your problem easily.
Suggestion is to remove all those function access and control from view and put it somewhere else. This will be good habit for you so you can avoid the infamous fat view.

Resources