Table join: unable to show the data what I want - php

If I have table like this:
ID | Title | Topic | Summary
1 | A | Technology | ...
2 | B | Health | ...
3 | C | Sport | ...
This is my CI_Model:
function show($limit, $offset)
{
$this->db->select('document.id, document.title, document.summary, document.id_topic AS topic');
$this->db->from('document');
$this->db->join('topic', 'topic.id_topic = document.id_topic');
$this->db->limit($limit, $offset);
$this->db->order_by('id', 'asc');
return $this->db->get()->result();
}
This is my Controller:
$docdata = $this->Trainingmodel->show($this->limit, $offset);
...
$this->table->set_heading('ID', 'Title', 'Topic', 'Summary');
foreach ($docdata as $doc)
{
$this->table->add_row($doc->id, $doc->title, $doc->topic, $doc->summary);
}
Evidently the topic shows it's id, not name.
For example:
ID | Title | Topic | Summary
1 | A | 1 | ...
2 | B | 2 | ...
3 | C | 3 | ...
What should I do? I want to show topic's name, not topic's id.

Looking at your table structure you posted as comments in the other answers, I think you need topic.topic in your select() and topic.id = document.id_topic in your join() -
$this->db->select('document.id, document.title, document.summary, topic.topic');
$this->db->from('document');
$this->db->join('topic', 'topic.id = document.id_topic');

$this->db->select('document.id, document.title, document.summary, topic.topic');
$this->db->from('document');
$this->db->join('topic', 'topic.id = document.id_topic');

Maybe its because of this document.id_topic
$this->db->select('document.id, document.title, document.summary, document.id_topic AS topic');
should it be something like document.topic or document.name_topic ?

Related

How to filter post by category in laravel?

I am currently trying to make a relation between 3 tables.
post
id
name
category
id
name
post_category
id
post_id
category_id
Database
post
| 1 | post1 |
| 2 | post2 |
| 3 | post3 |
category
| 1 | cat1 |
| 2 | cat2 |
| 3 | cat3 |
post_category
| 1 | 1 | 1 |
| 2 | 2 | 1 |
| 3 | 3 | 2 |
| 3 | 2 | 2 |
| 3 | 1 | 3 |
Model Post.php
public function getCategory()
{
return $this->belongsToMany(Category::class, 'post_category');
}
PostController.php
$data = Post::with('getCategory')->get();
It returns correct post list.
Now i want to filter the post by category. I try, but it not working
$categoryId = [1,2];
$data = Post::with('getCategory')->whereHas('category', function ($query) use ($categoryId) {
$query->whereIn('id', $categoryId);
})->orderBy('id','DESC')->get();
please help me
use Laravel 5.4
apparently everything is fine!
One suggestion is to add two more parameters to the belongsToMany method, like:
public function getCategory()
{
return $this->belongsToMany(Category::class, 'post_category', 'post_id', 'category_id');
}
https://laravel.com/api/7.x/Illuminate/Database/Eloquent/Concerns/HasRelationships.html#method_belongsToMany
You should rename your getCategory() function to simply category(). That makes the relation names much more straightforward and probably fixes your issue.
THEN, you should be able to call whereHas('category', ...).
If it still does not work, simply chain a ->toSql() to any of your queries and debug the actual query that way.

How can I write a relation for pivot table in Laravel?

Here is my table structure:
// tickets
+----+------------+----------------------+--------+---------+-------------------+
| id | subject | content | closed | user_id | unique_product_id |
+----+------------+----------------------+--------+---------+-------------------+
| 1 | subject1 | question1 | 0 | 123 | 2 |
+----+------------+----------------------+--------+---------+-------------------+
// unique_product
+----+---------------+------------+
| id | serial_number | product_id |
+----+---------------+------------+
| 1 | 2342rd34fc | 3 |
| 2 | fg34gt4r5t | 1 |
| 3 | 34ffvv4et6 | 3 |
+----+---------------+------------+
// products
+----+--------------+
| id | name |
+----+--------------+
| 1 | Router-rb51 |
| 2 | Switch-sfx2 |
| 3 | Router-rb300 |
+----+--------------+
Now I have a collection of tickets like this:
$tickets = tickets::where(user_id, "$user_id")->get();
foreach( $tickets as $ticket ){
$ticket->{I need to get the name of product here}
}
I can write a relation in the tickets model like this:
public function unique_product()
{
return $this->hasOne(unique_product::class, 'id', 'unique_product_id');
}
And I need one more relation to the products table for getting the name of product (i.e. Switch-sfx2). How should I write that relation?
$tickets = tickets::where(user_id, "$user_id")->with('unique_product.product')->get();
You can take advantage eager loading using with().
but for using with('unique_product.product') You have to define the relation ships between unique_products and products.
In your UniqueProduct model create a new relationship
public function product()
{
return $this->BelongsTo(Product::class, 'id', 'product_id');
}
After that you can access the column of a name like
foreach( $tickets as $ticket ){
$ticket->unique_product->product->name
}

Laravel impossible where query

I'm working on a filter for some products. I have the majority of it working however I am encountering an error with an impossible where clause.
The table contains multiple rows for a single product and I am trying to match multiple criteria per product, which is causing it to fail.
If you have an opinion on this, or possibly a way to fix this, I would greatly appreciate it.
The database table looks like this:
--------------------------------------------
|id | FilterKey | filterValue | product_id |
--------------------------------------------
|1 | Colour | Gunmetal | 1 |
|2 | Colour | Silver | 1 |
|3 | Size | 750cc | 1 |
|4 | Size | 1000cc | 1 |
|5 | Colour | Red | 2 |
|6 | Colour | Blue | 2 |
|7 | Size | 750cc | 2 |
|8 | Size | 1000cc | 2 |
--------------------------------------------
And the filter looks like this:
public function scopeFilterProduct($query, $filters)
{
$this->filters = $filters;
if (count ($this->filters) === 1 && isset($this->filters[0]))
{
return $query;
}
$query->join('product_filters', 'products.id', '=', 'product_filters.product_id')->Where(function($query){
foreach ($this->filters as $filter => $vals)
{
$this->filter = $filter;
$this->vals = $vals;
$query->Where(function ($query){
$query->Where('filterKey', $this->filter);
$query->Where(function($query){
foreach ($this->vals as $val){
$query->orWhere('filterValue', $val);
}
$this->vals = null;
});
});
$this->filter = null;
};
});
return $query;
}
This then outputs the following SQL statement:
select
distinct
`products`.`id`
, `product_id`
from
`products`
inner join
`product_filters`
on
`products`.`id` = `product_filters`.`product_id`
where
(
(`filterKey` = 'Colour' and (`filterValue` = 'gunmetal'))
and
(`filterKey` = 'Size' and (`filterValue` = '750cc'))
)
and
`products`.`deleted_at` is null
If selected, as in the screenshot, then only 'product one' should be present on the page.
The scope you have added in my opinion is wrong. Even your database structure is incorrect in my opinion. Here is how i would structure this:
Filters Table
This model will hold all the filter values. For example, Colour, Size etc. Here is how the filter table will be structured:
-----------------
|id | name |
-----------------
|1 | Colour |
|2 | Size |
-----------------
So your eloquent model become something like this:
class Filter extends Model
{
protected $fillable = ['id', 'name'];
public function products()
{
return $this->belongsToMany(Product::class, 'products_filters');
}
}
Products Table
Your product models becomes:
class Product extends Model
{
public function filters()
{
return $this->belongsToMany(Filter::class, 'products_filters');
}
}
products_filters Table
After the above changes, here is how the table will be structured:
--------------------------------------------
|id | filter_id | filterValue | product_id |
--------------------------------------------
|1 | 1 | Gunmetal | 1 |
|2 | 1 | Silver | 1 |
|3 | 2 | 750cc | 1 |
|4 | 2 | 1000cc | 1 |
|5 | 1 | Red | 2 |
|6 | 1 | Blue | 2 |
|7 | 2 | 750cc | 2 |
|8 | 2 | 1000cc | 2 |
--------------------------------------------
Now you can simply query the filters table, then get associated products for all filters. After that you simply need to compile a list of unique products.
Unqiue products based on selected filters.
$ids = [];
$products = new \Illuminate\Support\Collection();
foreach($filters as $filter) {
foreach($filter->products as $product) {
if(!in_array($product->id, $ids)) {
$ids[] = $product->id;
$products->push($product);
}
}
}
return view('results', compact('products'));
In your view, you need to write:
#foreach($products as $product)
// Your product block HTML
#endforeach

Get total comments of article in PHP with NotORM

My table ofcomments looks like:
| ID | article_id | user_id | ...
|-------------------------------|
| 1 | 1 | 1 | ...
| 2 | 2 | 2 | ...
| 3 | 2 | 1 | ...
| 4 | 3 | 2 | ...
AndI need to get top 5 articles with the most comments. When I use this statement in SQL console SELECT 'article_id', count(*) as 'total' FROM 'comments' GROUP BY 'article_id' ORDER BY 'total' LIMIT 5, then I get everything I want. But I need to do this with NotORM and this is where I stucked at. This is my function to get these articles:
function getBestActive() {
$items = $this->db->comments()
->select("article_id, count(*) as 'total'")
->order("total DESC")
->limit(5);
$articles = array();
foreach($items as $item) {
$article = $this->db->article('id', $item['article_id'])->fetch();
$article['img'] = "thumb/{$article['uri']}.jpg";
$article['comments'] = $item['total'];
$articles[] = $article;
}
return $articles;
}
But it returns me array with only 1 article (the most commented) and I need the most 5 articles. Or is it possible to execute custom SQL statement with NotORM (that could be answer too)?
Oh now I see. I forget to add group() function. So using this selection everything works:
$items = $this->db->comments()
->select("article_id, count(*) as 'total'")
->group("article_id")
->order("total DESC")
->limit(5);

Eloquent query where column is in another table

I have two tables, posts and likes. I need to create a query, using Eloquent, that gets all posts that have been liked by a specific user_id.
In other words, it should be something like this:
SELECT * FROM posts p LEFT JOIN likes l ON p.id = l.post_id WHERE l.user_id = 2 ORDER BY l.created_at DESC
posts table:
+----+---------+------------+-------------+
| id | user_id | message | created_at |
+----+---------+------------+-------------+
| 1 | 2 | Hello! | <SOME TIME> |
| 2 | 3 | World! | <SOME TIME> |
| 3 | 2 | Something. | <SOME TIME> |
| 4 | 2 | Another. | <SOME TIME> |
+----+---------+------------+-------------+
likes table:
+----+---------+---------+-------------+
| id | post_id | user_id | created_at |
+----+---------+---------+-------------+
| 1 | 1 | 2 | <SOME TIME> |
| 2 | 2 | 2 | <SOME TIME> |
| 3 | 1 | 3 | <SOME TIME> |
| 4 | 3 | 2 | <SOME TIME> |
+----+---------+---------+-------------+
Here is my Postclass:
<?php
class Post extends Eloquent {
protected $table = 'posts';
public function likes()
{
return $this->hasMany('Like');
}
}
And the Like class:
<?php
class Like extends Eloquent {
protected $table = 'likes';
public function post()
{
return $this->belongsTo('Post');
}
}
How can I do this?
This should work:
$userId = //however you get the userid here.
$posts = Post::whereHas('likes', function ($q) use ($userId) {
$q->where('user_id', $user_id);
})->get();
You can use Laravel's DB class to perform joins on two or more tables, following is how your query will be executed in laravel:
$users = DB::table('posts')
->leftJoin('likes', 'posts.id', '=', 'likes.post_id')
->select('posts.*', 'likes.*')
->where('likes.user_id', '=', '2')
->orderBy('likes.created_at', 'desc')
->get();
Don't forget to use DB class on the top of your controller;
If you want to do it with eloquent, you should do the follwing:
$result = Post::whereHas('likes', function ($q) use($user_id)
{
$q->where('user_id', $user_id);
})
->orderBy('likes.created_at')
->get();

Categories