PHP & MySQL Join - php

I'm relatively new to coding in general, first year CS student and all of that. I'm using PHP to display a list of school classes categories and a list of assignment posts within each category. The desired output would be something like this:
CATEGORY 1
-Assign Post 1
-Assign Post 2
CATEGORY 2
-Assign Post 0
Using join gives me partial functionality, because it gets all the assign posts, but when I loop through and post the data it posts the Category title more than once. I then tried using group_by but it's only posting one post per category.
I'm not gonna post all my code, simply the db queries. I'll happily post the other code if you think the problem may be there.
//Select our classes, and get assignments from each class
$this->db->select('*');
$this->db->from('categories');
$this->db->join('assignments', 'categories.cat_id = assignments.assign_cat_id');
$this->db->group_by("cat_id");
//Return the classes and assignments in an array
$query = $this->db->get();
return $query->result_array();
Not to tricky right? Any help is of course appreciated :).
UPDATE
I have figured out that group_concat will post the assignment names, and then I can explode the results. Is this the only way, or is there a way to get it to post in a nice friendly array. The only reason I ask is I feel this adds un-necessary code in my view file, where I'm exploding the data.
Thank you!

Dont use group by ...use sort by Category id and while showing/or preparing array of data you can club records as per category..you cant achive this by single SQL

Related

PHP - Sort and order an array of objects by category name

I am learning PHP and have decided to code my own OOP MVC framework. Now, I have realized several times already that it might not be the smartest move but I mean to see this out to the end. And then onwards...
My issue is creating a listing sidebar based on categories and a second based on year-month-postname.
I am officially stuck on the first one, let alone the second damn option. I have included some code and description of what I have tried. The lack of OOP info on the net is daunting or maybe it is because I am searching for the wrong thing, I dont know. But the tutorials have not given me any insight as to how to actually do this in a way where my database is in a model file and my class logic is in the class file.
Sorting logic should be like this Array-Object-Propertyname-Value.
The value, as I hope is easy to understand in my example below, is the category name eg Javascript, PHP, HTML. By that category i wish to sort my blog posts. But not in the way that requires me to manually input the category names to the code. I want to allow users to enter categories if they so choose.
I also wish to display the blog posts inside said category, lets say 5 most recent. But that should not be too hard with a
for($i=0,$i<5,i++)
nested inside whatever solution in the end will work for the category sort.
I have tried MySQLI procedural solutions ranging from multiple google searches and tutorials. Can do it, but dont want to do it procedurally. Tried foreach loop and nesting multiple foreach loops - simply cannot get either the problem of having duplicates based on the shared category name or if trying to group in the SQL query, it simply groups results with same category and then displays only the first one in the group. While loops with mysqli procedural work but with pdo in my case they produce infinite loops, no matter the condition I try to set.
So foreach is the way to go I believe. I have read up on loops and array sorting but I've yet to find a solution. I thought of sorting by key because that is what i need but to no applicable solutions.
It's easy to display the category names and dates and all that. But with category I always get duplicates.
Ive tried some logic where as to assign category names as variables but only to have them all be different variables, meaning still having duplicates or only rewriting the variable with each iteration.
Also, array sorts havent worked because I havent gotten any to work with sorting either on property or if converting Objects to a multidimensional array. Granted that may be because I am a beginner and not understood the syntax but I am not going to post them all here I think.
If you think an array sorting function will do the trick then perhaps give me an example and I will look into it with some new perspective hopefully.
PDO query :
'SELECT * FROM postTable
INNER JOIN userTable ON postTable.postUserId = userTable.id
INNER JOIN postCategories ON postTable.postCategoryId = postCategories.categoryName
ORDER BY postTable.postDate DESC'
Tried also to add
GROUP BY categoryName
but that resulted in only one entry per category shown when using var_dump. Sidenote - same is when grouping by creation date. Is there another layer added to the array when using group in the SQL command and I missed that in the docs?
PDO returns to view file :
$this->stmt->fetchAll(PDO::FETCH_OBJ);
this all gets passed into an array of
$results
and then that is sent to the php on the view page where the resulting array has this structure with var_dump.
array() {
[0]=>
object(stdClass)# () {
["categoryName"]=>
string() "Help"
}
[1]=>
object(stdClass)# () {
["categoryName"]=>
string() "Me"
}
and so on.
Note - also tried using -
fetchAll(PDO::FETCH_ASSOC);
But ive had similar failures with attempting any sorting or limiting to just one category name displayed but all entries under said category being displayed correctly and not just one per category.
I will be checking back when i finish work tomorrow so in about 20-22 hours from the time of posting.
If you need any more info just let me know and I'll post it.
You can order by multiple columns. Use:
ORDER BY categoryName, postDate DESC
This will keep all the posts in the same category together, and in decreasing date order within each category.
See How can i list has same id data with while loop in PHP? for how you can output the results, showing a heading for each category.
If you just want to get the 5 latest posts in each category, see Using LIMIT within GROUP BY to get N results per group?

laravel get eloquent data using its relations Ids

I have three main mySQL tables:
users
tags
news_articles
I also have many to many tables to connect them as needed.
I want to grab all the articles that share the same tags as users so I can personalise their experience.
(example): say a user has tags for "Trump" or "Brexit" I want to grab all the news articles that also have Trump or Brexit.
I could grab the whole data pool and make calculations but that might get unnecessarily server intensive so is there a way of doing it through Eloquent?
Also is Eloquent capable of tallying the user tags to determine which tags the user is most interested in before grabbing the articles or would that need a workaround after?
Thanks in advance.
Christophvh's response did work for me in the end. After some more time with Eloquent I found plenty more ways of doing this.
A way I would go about this now for anyone who happens to be stuck:
By creating a tags method in my User and Article models to return all related tags I can then do the following.
$userTags = $user->tags()->pluck('name')->get()->toArray();
$articles = Article::whereHas('tags', function($tag) use ($userTags) {
$tag->where('name', $userTags)->get();
})->get();
The above code should:
Get only the name field of all tags belonging to a user and store them in an array.
Grab all articles where their related tags name field contain any tag in the $userTags variable
To create a priority tags list I would just need to run array_count_values($userTags) and order it by the returned values, then pass the new ordered $userTags array into the Eloquent query.

Create A List From a Category Section in mysql

I was wondering if mysql has a way to look at a column and only retrieve the results when it finds a unique column once. For example
if the table looks like this:
id name category
1 test Health
2 carl Health
3 bob Oscar
4 joe Technology
As you can see their are two rows that could have the same category. Is their a way to retrieve the result where the array will one only return the category once?
What I am trying to do is get all the categories in the database so I can loop through them later in the code and use them. For example if I wanted to created a menu, I would want the menu to list all the categories in the menu.
I know I can run
SELECT categories FROM dbname
but this returns duplicate rows where I only need the cateogry to return once. Is there a way to do this on the mysql side?
I assume I can just use php's array_unique();
but I feel like this adds more overhead, is this not something MYSQL can do on the backend?
group by worked perfectly #Fred-ii- please submit this as answer so I can get that approved for you. – DEVPROCB
As requested by the OP:
You can use GROUP BY col_of_choice in order to avoid duplicates be shown in the queried results.
Reference:
https://dev.mysql.com/doc/refman/5.5/en/group-by-handling.html
By using database normalization, you would create another table with an unique id and the category name and by that link those two together, like
select * from mytable1
on mytable1.cat = mytable2.id
group by mytable1.cat
You can ofcourse also use group by without multiple tables, but for the structure, I recommend doing it.
You can use select distinct:
SELECT DISTINCT categories
FROM dbname ;
For various reasons, it is a good idea to have a separate reference table with one row per category. This helps in many ways:
Ensures that the category names are consistent ("Technology" versus "tech" for instance).
Gives a nice list of categories that are available.
Ensures that a category sticks around, even if no names currently reference it.
Allows for additional information about categories, such as the first time it appears, or a longer description.
This is recommended. However, if you still want to leave the category in place as it is, I would recommend an index on dbname(categories). The query should take advantage of the index.
SELECT id, name from dbname GROUP BY categoryname
Hope this will help.
You can even use distinct category.

get post content and display in a page by matching the page name and post category name

I am writing some little hacks for wordpress by giving myself some used cases. I think that is the best way to learn this
I have created a scenario where I am checking if the page name is 'x' then fetch contents of posts categorized as 'y' in the page x. Works fine as long as I hard code the page names like this
if(is_page('x')){
query_posts('category_name=y');
}
Now I am thinking what if I generalize the x and retrieve all the categories and push them in an array. Iterate through the array and look for match like
if(pageName == postCategoryName){
query_posts('category_name=the correct category');
}
I believe I would basically have to create the post categories with the same name as the page name
Conceptually I am good with this but when it is coming to the syntax I am getting a bit lost. How should I approach this?
This could be achieved by getting the slug of the current page and then finding the same slug in a category.
e.g. if you were on the Geography page
$slug = basename(get_permalink());
$slug would contain geography so you can query that by:
query_posts("category_name={$slug}");
And that should return the posts in the category.

Mysql parent child tables reducing database calls or merge in PHP

If I had 2 tables, say blog_category and blog, each "blog" can belong in a particular category only so a 1-1 relationship based on a key called "blog_category_id".
Now in my code I would do something like:
//Loop through categories such as
foreach($categories as $cat):
//then for each category create an array of all its posts
$posts = $cat->getPosts(); // This would be another DB call to get all posts for the cat
//do stuff with posts
endforeach;
Now to me this seems like it could end up quite expensive in terms of DB calls depending on the size of $categories. Would this still be the best solution to do this? Or would I be able to do something in the code and first retrieve all the categories, then retrieve all the blogs and map them to their corresponding category via the id somehow? This would in theory be only 2 calls to the DB, now size wise the result set for call 2 (the blogs) would definitely be larger, but would the actual DB call be as expensive?
I would normally go for the first option, but I'm just wondering if there would be a better way of approaching this or is it more likely that the extra processing in PHP would be more costly in terms of performance? Also specifically from an MVC perspective, if the model returns the categories, but it should also return the corresponding blogs for that category, I'm not sure how best to structure this, from my understanding, shouldn't the model return all the data required for the view?
Or would I be better off selecting all categories and blogs using inner joins in the first query and create the output I need of this? Perhaps by using a multi-dimensional array?
Thanks
You can use a simple SQL query to get all categories and posts like the following:
SELECT *
FROM posts p
JOIN categories c ON c.id = p.blog_category_id
ORDER BY c.category_name ASC,
p.posted_date DESC
Then when you loop over the returned records assign the current category id to a variable, which you can use to compare against the next records category. If the category is different then print the category title before printing the record. It is important to note that for this to work you need to get the posts ordered by category first and then post so that all posts in the same category are together.
So for example:
$category_id = null;
foreach($posts as $post) {
if($post['blog_category_id'] != $category_id) {
$category_id = $post['blog_category_id'];
echo '<h2>' . $post['category_name'] . '</h2>';
}
echo '<h3>' . $post['post_title'] . '</h3>';
echo $post['blog_content'];
}
Note: as you have not posted up the schema of these two tables I have had to make up column names that are similar to what I would expect to see in code like this. So the code above will not work with your code without some adjustments to account for this.
The best solution depends on what you are going to do with data.
Lazy loading
Load data when you need it. It's a good solution when you have, for instance, 20 categories and you load posts for only 2 of them. However, if you need to load posts for all of them it won't be efficient at all... It's called a n+1 queries (and it's really bad).
Eager loading
On the other hand, if you have to access to almost all of your posts, you should do an eager loading.
-- Load all your data in a query
SELECT *
FROM categories c
INNER JOIN posts p ON c.id = p.category_id;
// Basic example in JSON of how to format your result
{
'cat1': ['post1', 'post2'],
'cat2': ['post5', 'post4', 'post5'],
...
}
What to do?
In your case I would say an eager loading because you load everything in a loop. But if you don't access to the most of your data, you should re-design your model to perform a lazy loading in such a way that the SQL query to load posts for a specific category is actually performed when a view try to access them.
What do you think?

Categories