Laravel eloquent with archive table - laravel

I have two tables with same schema.
TABLE: items, items_archive
+-------------+-------------------
| partno |qty | brand|| category |
+--------------------------------+
| | | | |
| | | | |
| | | | |
+--------+----+------+-----------+
Is there any way to create a eloquent model which i can use to query from both at same time?
Item::where('brand', 'acer') => which will query will do something like union.

You should be able to take an approach like this:
$a = Item::where('brand', 'acer');
$b = ItemArchive::where('brand', 'acer');
$results = $a->union($b)->get();`
In this, we are creating 2 models with search queries, but not executing them. Finally, we union them together and the get() the results. You can then loop through the $results array for all the data.
Alternatively, you could hide all this logic inside your Item model:
public function retrieveAllWithArchive($brand)
{
return $this->where('brand', $brand)->union((new ItemArchive)->where('brand', $brand))->get();
}
Then, call it from anywhere with:
$results = (new Item)->retrieveAllWithArchive($brand);
Hope this helps!

Related

How can I fetch value from 3 tables using laravel relationship?

I have 4 tables named: categories, products, blogs, companies.
+-----------+
| Category |
+----+------+
| id | name |
+----+------+
| 1 | Cat1 |
| 2 | Cat2 |
+----+------+
+-----------+
| Company |
+----+------+
| id | name |
+----+------+
| | |
+----+------+
+-------------------------+
| Product |
+----+-------------+------+
| id | category_id | name |
+----+-------------+------+
| 1 | 1 | P1 |
| 2 | 2 | P2 |
| 3 | 1 | P3 |
+----+-------------+------+
+---------------------------+
| Blog |
+----+------------+---------+
| id | product_id | heading |
+----+------------+---------+
| 1 | 1 | H1 |
| 2 | 2 | H3 |
| 3 | 3 | H4 |
+----+------------+---------+
Blog Model
public function product()
{
return $this->belongsTo(Product::class);
}
Product Model
public function company()
{
return $this->belongsTo(Company::class);
}
public function category()
{
return $this->belongsTo(Category::class);
}
Blog::with('product.category')
->where('status', 'Y')
->where('featured_position', 'Y')
->orderBy('id', 'DESC')
->get();
From the above tables the result will show 2 blogs namely blogs having id 1 and 3. But the above code is fetching result for all the blogs from the blog table.
You'll want to use a whereHas to query the relationship.
$categoryId = 1;
$productQuery = function ($query) use ($categoryId) {
// This $query object will be for the Product models, so we can treat it as
// such.
// We can query like we would on a Product, like Product::where([...]).
$query->with('category')->where('category_id', $categoryId);
};
$blogs = Blog::whereHas('product', $productQuery)
->with(['product' => $productQuery])
->get();
I've set the category ID to a variable, in case you need to change it during runtime.
Also, note that the with is completely optional.
If you exclude it, your query will run exactly the same, just without constrained eager loading. The effects of this are just that you will have to perform more database requests. The benefits come if you never actually need the relationship, then it won't have been fetch unnecessarily.
If you're curious what the SQL command will be, it will be:
SELECT * FROM `blogs`
WHERE EXISTS (
SELECT * FROM `products`
WHERE `blogs`.`product_id` = `products`.`id` AND `category_id` = ?
)
In simple terms, it will select everything from the blogs table.
It's then going to query the products table, using an inner join, to select products that have a corresponding blog entry.
The second part of the where clause is going to just get the specific character. The ? is because category_id can be any integer.
Catory with id 1
fetch its products
fetch blogs for each of its products ( map over products )
flatten the results ( since its gonna be nested for each product )
Category::find(1)->products->map->blogs->flatten();
you can use Tinker to interact with you application's query builder and eloquent models from terminal you can use :
$ php artisan tinker
For more clause you can use collection methods :
Category::find(1)->products->map->blogs->flatten()->where('status', 'Y')
->where('featured_position', 'Y')
->sortDesc('id') ;

Laravel | Return rows in order based off pivot

I have the following setup:
stages:
| id | name | order |
commands:
| id | name | body |
------------------------------=
| 1 | test | phpunit |
| 2 | style | echo "style" |
| 3 | deploy | deploy |
command_stage:
| command_id | stage_id | order |
---------------------------------
| 1 | 1 | 1 |
| 2 | 2 | 1 |
| 3 | 1 | 2 |
Basically, I would like to create a method on the stage model which allows me to get all of the commands back based off of the order, but commands have a specific order and so do the stages.
So each command is stored under a stage so we know which part to run but each command also has an order in that stage. Now I know I can do something like the following:
$inOrder = collect();
Stage::get()->each(function ($stage) {
$commands = $stage->commands()->orderByPivot('order')->get();
$inOrder->push($commands);
});
return $inOrder;
But I was wondering if there is a nicer way to do this? Or even a way to do this solely on one database hit?
Pre-load and sort the relationship:
$stages = Stage::with(['commands' => function ($subQuery) {
$subQuery->orderBy('command_stage', 'order');
}])->get();
foreach($stages as $stage) {
$inOrder->push($stage->commands);
}
This method of Eager-Loading will reduce the N+1 query issue of doing $stage->commands() inside the foreach() loop.

How can I get a post with all related ones?

Here is my table structures:
// tickets
+----+------------+----------------------+--------+---------+
| id | subject | content | closed | user_id |
+----+------------+----------------------+--------+---------+
| 1 | subject1 | question1 | 0 | 123 |
+----+------------+----------------------+--------+---------+
// answers
+----+----------------------+---------+-----------+
| id | content | user_id | ticket_id |
+----+----------------------+---------+-----------+
| 1 | answer1 | 123 | 1 |
| 2 | answer2 | 456 | 1 |
+----+----------------------+---------+-----------+
Now I need to get a ticket with along all its answers. I can do that using pure SQL like this:
SELECT t.*, a.*
FROM tickets t
LEFT JOIN answers a
ON t.id = a.ticket_id
WHERE t.id = ?
Now I'm using Laravel and I want to do that using with() class (however not sure it is possible). Any idea what change should I make in the models for doing that?
Noted that I can get just a ticket in Laravel like this:
$ticket = Tickets::where('id', $request->id)->get();
First make a hasMany() relationship in your Tickets model class.
public function answers()
{
return $this->hasMany(Answers::class, 'ticket_id', 'id');
}
And then in your controller query
$tickets = Tickets::with('answers')->where('id', $request->id)->get();

Laravel order by related table not working

I have this structure.
class Product extends Model{
public function office()
{
return $this->belongsTo(Office::class,'office_id');
}
}
I want to list products order by office.name.
this is the query
$res = \App\Product::with(['office' => function($q){
$q->orderBy('offices.name','asc');
}])->get();
this is the output loop
foreach($res as $key => $val){
print "<br />user: ".$val->id.", office: ".$val->office->id;
}
this is the Product data:
+----+--------+
| id | name |
+----+--------+
| 1 | Life |
| 2 | Cars |
| 3 | Health |
| 4 | House |
+----+--------+
this is the data in Office
+----+----------------+
| id | name |
+----+----------------+
| 1 | First office |
| 2 | working office |
+----+----------------+
The order by is not affecting the result.
same result, the order by like not existed.
Thanks
In your code you are simply "ordering" the offices by name, which means if each product had many offices, it would sort the offices alphabetically.
To sort (OrderBY()) a collection, the column has to be an attribute of the collection object. One solution could be to Join your models. SOmething like this might help you.
$res = Product::with('office')
->join('offices', 'products.office_id', '=', 'offices.id')
->select('products.*', 'offices.name')
->orderBy('office.name')
->get();

Laravel 5 - Eloquent JOIN confusion

I have two simple tables, cats and breeds:
mysql> select * from cats;
+----+--------+---------------+----------+---------------------+---------------------+
| id | name | date_of_birth | breed_id | created_at | updated_at |
+----+--------+---------------+----------+---------------------+---------------------+
| 1 | Rita | 2008-07-06 | 1 | 2015-05-09 20:40:49 | 2015-05-09 20:50:20 |
| 2 | Muni | 1992-05-15 | 3 | 2015-05-09 20:50:54 | 2015-05-09 20:50:54 |
| 3 | Hector | 2005-01-23 | 4 | 2015-05-09 21:08:23 | 2015-05-09 21:08:23 |
+----+--------+---------------+----------+---------------------+---------------------+
3 rows in set (0.00 sec)
mysql> select * from breeds;
+----+------------+
| id | name |
+----+------------+
| 1 | Domestic |
| 2 | Persian |
| 3 | Siamese |
| 4 | Abyssinian |
+----+------------+
4 rows in set (0.00 sec)
All I want to do is get a list of the cats that are of a certain breed. In the cats table, breed_id is a FK that points to the PK of the breeds table. The example code in my book which is supposed to return a view with all cats of a specific breed returns no results:
The url I am trying is /cats/breeds/Domestic
The view that is generated uses this logic in the routes.php file:
Route::get('cats/breeds/{name}', function($name)
{
$cats = Furbook\Cat::with('breeds')
->whereName($name)
->get();
dd($cats);
});
When I dd($cats) I get zero results even though I have a cat with a domestic breed_id of 1. What have I done wrong here?
EDIT:
I can get it to work with the following hacky code, which first gets the id from the breeds table by querying against the name field, then queries the cats table with that id:
$breed = Furbook\Breed::whereName($name)->get();
$id = $breed[0]['attributes']['id'];
$cats = Furbook\Cat::whereId($id)->get();
How do I make this into one Eloquent query? I see no examples for this kind of query on the Laravel site.
For more information this is how the models look:
class Breed extends Model {
public $timestamps = false;
public function cats()
{
return $this->hasMany('Furbook\Breed');
}
}
class Cat extends Model {
protected $fillable = [
'name',
'date_of_birth',
'breed_id',
];
public function breed()
{
return $this->belongsTo('Furbook\Breed');
}
}
You're asking the system to give you all cats with a name of Domestic - not all cats of the breed name Domestic.
Assuming your model relationships are in order, you could do e.g.
$cats = Furbook\Breed::whereName($name)->first()->cats;
Also, my Burmese cat just hit the monitor; I think she's upset that she's not in the breeds list.

Resources