I am currently making a website where I require a very advanced search engine. I want the users to be able to say Person # company or Product # Category. How would I detect the # sign or any special characters, filter them out and make individual variables based on the returned string. So $a = Person and $b = company.
You can use explode() to split a string:
$items = explode('#', 'Person # Company', 2);
if(count($items) === 2) {
// Person # Company
$person = trim($items[0]);
$company = trim($items[1]);
// Do your searching here...
} else {
// Search normally, not Person # Company.
}
Send it across as a get request formatted as a=Person&b=company etc. The other way is exactly what you said, loop through the string and examine the chars one by one. When you encounter an # sign you know that the letters before it (not including spaces) are the value of a and everything after the # (not including spaces) is the value of b.
Sorry I tried to be as clear as I could.
This is very simple to achieve;
function searchForPersonAtCompany($searchQuery) {
global $db;
$queryComponents = explode('#', $searchQuery, 2);
if (count($queryComponents) != 2) {
// '#' was not specified in the search query, return an empty array.
return array();
}
$person = $queryComponents[0];
$company = $queryComponents[1];
$sql = 'SELECT p.id AS personId, c.id AS companyId FROM people p JOIN companies c ON p.company = c.id WHERE p.name LIKE :person AND c.name LIKE :company';
$stmt = $db->prepare($sql);
$stmt->bindValue(':person', $person);
$stmt->bindValue(':company', $company);
$stmt->execute();
return $stmt->fetchAll();
}
You didn't specify your database schema, so I had to guess that you have a people table and a companies table, with people related to the companys table with the company field.
Table: People
id | name | company
--------------------------------------------
1 | Alice | 1
2 | Bob | 1
3 | Charles | 2
Table: Companies
id | name
--------------------------------------------
1 | Company A
2 | Company B
You will have to adapt the code for your purposes, but using my testing data, the following should work;
searchForPersonAtCompany('Alice#Company A');
searchForPersonAtCompany('Charles#Company B');
Notes:
This is a very simple implementation of your search, you might be better looking into a database based search engine which can handle more complicated queries for the future.
I have used PDO as the connection to my database (bindValue, exec, etc), you might be using something different. :person and :company are just variables in the SQL.
Related
I wanted to implement a notification system for our school, it's a php/mysql webapp that is not opened for public, so it doesn't receive much traffic. "daily 500-1000 visitor".
1. My initial approach was using MYSQL triggers:
I used a Mysql AFTER INSERT trigger to add records to a table named notifications. Something like.
'CREATE TRIGGER `notify_new_homwork` AFTER INSERT ON `homeworks`
FOR EACH ROW INSERT INTO `notifications`
( `from_id`, `note`, `class_id`)
VALUES
(new.user_id,
concat('A New homework Titled: "',left(new.title,'50'),
'".. was added' )
,new.subject_id , 11);'
This kind of black magic worked very well, yet i couldn't keep track of if this notification is new "to show count of new notifications for user".
so i added a page named notifications.
Notifications are retrieved with something like
SELECT n.* from notifications n
JOIN user_class on user_class.class_id = n.class_id where user_class.user_id = X;
Note: table user_class link user to class "user_id,class_id,subject_id" -subject is null unless user is a teacher'
Now my next challenges are.
how to keep track of new vs old notifications per user?
how can i aggregate notifications that are similar to user into one row ?
example if 2 user commented on something, then do not insert a new row, just update the old one with something like 'userx and 1 other commented on hw'.
Thanks alot
Edit
As per answer below, to set a read/unread flag on row, i will need to have a row for each student not just a row for the whole class.. which means editing the trigger to something like
insert into notifications (from_id,note,student_id,isread)
select new.user_id,new.note,user_id,'0' from user_class where user_class.class_id = new.class_id group by user_class.user_id
Well this question is 9 months old so i'm not sure if OP is still in the need of an answer but due the many views and the tasty bounty I would like to also add my mustard (German saying..).
In this post I will try to make a simple explained example on how to start building a notification system.
Edit: Well ok this turned out way, way, way longer than I expected it to be. I got really tired in the end, i'm sorry.
WTLDR;
Question 1: have a flag on every notification.
Question 2: Still store every notification as a single record inside your database and group them when they are requested.
Structure
I assume that the notifications will look something like:
+---------------------------------------------+
| ▣ James has uploaded new Homework: Math 1+1 |
+---------------------------------------------+
| ▣ Jane and John liked your comment: Im s... |
+---------------------------------------------+
| ▢ The School is closed on independence day. |
+---------------------------------------------+
Behind the curtains this could look something like this:
+--------+-----------+--------+-----------------+-------------------------------------------+
| unread | recipient | sender | type | reference |
+--------+-----------+--------+-----------------+-------------------------------------------+
| true | me | James | homework.create | Math 1 + 1 |
+--------+-----------+--------+-----------------+-------------------------------------------+
| true | me | Jane | comment.like | Im sick of school |
+--------+-----------+--------+-----------------+-------------------------------------------+
| true | me | John | comment.like | Im sick of school |
+--------+-----------+--------+-----------------+-------------------------------------------+
| false | me | system | message | The School is closed on independence day. |
+--------+-----------+--------+-----------------+-------------------------------------------+
Note: I don't recommend to group the notifications inside the database, do that on runtime this keeps things a lot more flexible.
Unread
Every notification should have a flag to indicate if the recipient has already opened the notification.
Recipient
Defines who receives the notification.
Sender
Defines who triggered the notification.
Type
Instead of having every Message in plain text inside your database create types. This way you can create special handlers for different notification types inside your backend. Will reduce the amount of data stored inside your database and gives your even more flexibility, enabled easy translating of notification, changes of past messages etc..
Reference
Most notifications will have a Reference to a record on your database or your application.
Every system I have been working on had a simple 1 to 1 reference relationship on a notification, you might have an 1 to n keep in mind that I will continue my example with 1:1. This also means that I don't need a field defining what type of object is referenced because this is defined by the notification type.
SQL Table
Now when defining a real table structure for SQL we come to a few decisions in terms of the database design. I will go with simplest solution which will look something like this:
+--------------+--------+---------------------------------------------------------+
| column | type | description |
+--------------+--------+---------------------------------------------------------+
| id | int | Primary key |
+--------------+--------+---------------------------------------------------------+
| recipient_id | int | The receivers user id. |
+--------------+--------+---------------------------------------------------------+
| sender_id | int | The sender's user id. |
+--------------+--------+---------------------------------------------------------+
| unread | bool | Flag if the recipient has already read the notification |
+--------------+--------+---------------------------------------------------------+
| type | string | The notification type. |
+--------------+--------+---------------------------------------------------------+
| parameters | array | Additional data to render different notification types. |
+--------------+--------+---------------------------------------------------------+
| reference_id | int | The primary key of the referencing object. |
+--------------+--------+---------------------------------------------------------+
| created_at | int | Timestamp of the notification creation date. |
+--------------+--------+---------------------------------------------------------+
Or for the lazy folks the SQL create table command for this example:
CREATE TABLE `notifications` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`recipient_id` int(11) NOT NULL,
`sender_id` int(11) NOT NULL,
`unread` tinyint(1) NOT NULL DEFAULT '1',
`type` varchar(255) NOT NULL DEFAULT '',
`parameters` text NOT NULL,
`reference_id` int(11) NOT NULL,
`created_at` int(11) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
PHP Service
This implementation depends completely on the needs of your application, Note: This is an example not the golden standard on how to build an notification system in PHP.
Notification model
This is an example base model of the notification itself, nothing fancy just the needed properties and the abstract methods messageForNotification and messageForNotifications we expected being implemented in the different notification types.
abstract class Notification
{
protected $recipient;
protected $sender;
protected $unread;
protected $type;
protected $parameters;
protected $referenceId;
protected $createdAt;
/**
* Message generators that have to be defined in subclasses
*/
public function messageForNotification(Notification $notification) : string;
public function messageForNotifications(array $notifications) : string;
/**
* Generate message of the current notification.
*/
public function message() : string
{
return $this->messageForNotification($this);
}
}
You will have to add a constructor, getters, setters and that kind of stuff by yourself in your own style, i'm not going to provide a ready to use Notification system.
Notification Types
Now you can create a new Notification subclass for every type. This following example would handle the like action of a comment:
Ray has liked your comment. (1 notification)
John and Jane liked your comment. (2 notifications)
Jane, Johnny, James and Jenny liked your comment. (4 notifications)
Jonny, James and 12 others liked your comment. (14 notifications)
Example implementation:
namespace Notification\Comment;
class CommentLikedNotification extends \Notification
{
/**
* Generate a message for a single notification
*
* #param Notification $notification
* #return string
*/
public function messageForNotification(Notification $notification) : string
{
return $this->sender->getName() . 'has liked your comment: ' . substr($this->reference->text, 0, 10) . '...';
}
/**
* Generate a message for a multiple notifications
*
* #param array $notifications
* #return string
*/
public function messageForNotifications(array $notifications, int $realCount = 0) : string
{
if ($realCount === 0) {
$realCount = count($notifications);
}
// when there are two
if ($realCount === 2) {
$names = $this->messageForTwoNotifications($notifications);
}
// less than five
elseif ($realCount < 5) {
$names = $this->messageForManyNotifications($notifications);
}
// to many
else {
$names = $this->messageForManyManyNotifications($notifications, $realCount);
}
return $names . ' liked your comment: ' . substr($this->reference->text, 0, 10) . '...';
}
/**
* Generate a message for two notifications
*
* John and Jane has liked your comment.
*
* #param array $notifications
* #return string
*/
protected function messageForTwoNotifications(array $notifications) : string
{
list($first, $second) = $notifications;
return $first->getName() . ' and ' . $second->getName(); // John and Jane
}
/**
* Generate a message many notifications
*
* Jane, Johnny, James and Jenny has liked your comment.
*
* #param array $notifications
* #return string
*/
protected function messageForManyNotifications(array $notifications) : string
{
$last = array_pop($notifications);
foreach($notifications as $notification) {
$names .= $notification->getName() . ', ';
}
return substr($names, 0, -2) . ' and ' . $last->getName(); // Jane, Johnny, James and Jenny
}
/**
* Generate a message for many many notifications
*
* Jonny, James and 12 other have liked your comment.
*
* #param array $notifications
* #return string
*/
protected function messageForManyManyNotifications(array $notifications, int $realCount) : string
{
list($first, $second) = array_slice($notifications, 0, 2);
return $first->getName() . ', ' . $second->getName() . ' and ' . $realCount . ' others'; // Jonny, James and 12 other
}
}
Notification manager
To work with your notifications inside your application create something like a notification manager:
class NotificationManager
{
protected $notificationAdapter;
public function add(Notification $notification);
public function markRead(array $notifications);
public function get(User $user, $limit = 20, $offset = 0) : array;
}
The notificationAdapter property should contain the logic in direct communication with your data backend in the case of this example mysql.
Creating notifications
Using mysql triggers is not wrong, because there is no wrong solution. What works, works.. But I strongly recommend to not let the database handle application logic.
So inside the notification manager you might want to do something like this:
public function add(Notification $notification)
{
// only save the notification if no possible duplicate is found.
if (!$this->notificationAdapter->isDoublicate($notification))
{
$this->notificationAdapter->add([
'recipient_id' => $notification->recipient->getId(),
'sender_id' => $notification->sender->getId()
'unread' => 1,
'type' => $notification->type,
'parameters' => $notification->parameters,
'reference_id' => $notification->reference->getId(),
'created_at' => time(),
]);
}
}
Behind the add method of the notificationAdapter can be a raw mysql insert command. Using this adapter abstraction enables you to switch easily from mysql to a document based database like mongodb which would make sense for a Notification system.
The isDoublicate method on the notificationAdapter should simply check if there is already a notification with the same recipient, sender, type and reference.
I cannot point out enough that this is only a example. (Also I really have to shorten the next steps this post is getting ridiculously long -.-)
So assuming you have some kind of controller with an action when a teacher uploads homework:
function uploadHomeworkAction(Request $request)
{
// handle the homework and have it stored in the var $homework.
// how you handle your services is up to you...
$notificationManager = new NotificationManager;
foreach($homework->teacher->students as $student)
{
$notification = new Notification\Homework\HomeworkUploadedNotification;
$notification->sender = $homework->teacher;
$notification->recipient = $student;
$notification->reference = $homework;
// send the notification
$notificationManager->add($notification);
}
}
Will create a notification for every teacher's student when he uploads a new homework.
Reading the notifications
Now comes the hard part. The problem with grouping on the PHP side is that you will have to load all notifications of the current user to group them correctly. This would be bad, well if you have only a few users it would probably still be no problem, but that doesn't make it good.
The easy solution is to simply limit the number of notifications requested and only grouping these. This will work fine when there are not many similar notifications (like 3-4 per 20). But lets say the post of a user / student gets about a hundred likes and you only select the last 20 notifications. The user will then only see that 20 people liked his post also that would be his only notification.
A "correct" solution would be grouping the notifications already on the database and selecting only some samples per notification group. Than you would just have to inject the real count into your notification messages.
You probably didn't read the text below so let me continue with a snippet:
select *, count(*) as count from notifications
where recipient_id = 1
group by `type`, `reference_id`
order by created_at desc, unread desc
limit 20
Now you know what notifications should be around for the given user and how many notifications the group contains.
And now the shitty part. I still could not find out a better way to select a limited number of notifications for each group without doing a query for every group. All suggestions here are very welcome.
So I do something like:
$notifcationGroups = [];
foreach($results as $notification)
{
$notifcationGroup = ['count' => $notification['count']];
// when the group only contains one item we don't
// have to select it's children
if ($notification['count'] == 1)
{
$notifcationGroup['items'] = [$notification];
}
else
{
// example with query builder
$notifcationGroup['items'] = $this->select('notifications')
->where('recipient_id', $recipient_id)
->andWehere('type', $notification['type'])
->andWhere('reference_id', $notification['reference_id'])
->limit(5);
}
$notifcationGroups[] = $notifcationGroup;
}
I will now continue assuming that the notificationAdapters get method implements this grouping and returns an array like this:
[
{
count: 12,
items: [Note1, Note2, Note3, Note4, Note5]
},
{
count: 1,
items: [Note1]
},
{
count: 3,
items: [Note1, Note2, Note3]
}
]
Because we always have at least one notification in our group and our ordering prefers Unread and New notifications we can just use the first notification as a sample for rendering.
So to be able to work with these grouped notifications we need a new object:
class NotificationGroup
{
protected $notifications;
protected $realCount;
public function __construct(array $notifications, int $count)
{
$this->notifications = $notifications;
$this->realCount = $count;
}
public function message()
{
return $this->notifications[0]->messageForNotifications($this->notifications, $this->realCount);
}
// forward all other calls to the first notification
public function __call($method, $arguments)
{
return call_user_func_array([$this->notifications[0], $method], $arguments);
}
}
And finally we can actually put most of the stuff together. This is how the get function on the NotificationManager might look like:
public function get(User $user, $limit = 20, $offset = 0) : array
{
$groups = [];
foreach($this->notificationAdapter->get($user->getId(), $limit, $offset) as $group)
{
$groups[] = new NotificationGroup($group['notifications'], $group['count']);
}
return $gorups;
}
And really finally inside a possible controller action:
public function viewNotificationsAction(Request $request)
{
$notificationManager = new NotificationManager;
foreach($notifications = $notificationManager->get($this->getUser()) as $group)
{
echo $group->unread . ' | ' . $group->message() . ' - ' . $group->createdAt() . "\n";
}
// mark them as read
$notificationManager->markRead($notifications);
}
Answer:
Introduce a read/unread variable on the notification. You can then pull only unread notifications by doing ... WHERE status = 'UNREAD' in your sql.
You can't really... you will want to push that notification. What you can do is still aggregate them though by using GROUP BY. You would likely want to group on something unique like a new homework so it might be something like ... GROUP BY homework.id
You can solve the issue with making a NotificationsRead table, containing the ID of the user and the ID of the notification the user wanted to mark as read.
(This way you can keep each students and the teacher separated.)
Then you can join that table to your notification's table and you will know if it should be considered old or new.
geggleto's answer was right about the second part, you can grab the notifications with SELECT *, COUNT(*) AS counter WHERE ... GROUP BY 'type' then you will know how many of the same type you have there and you can prepare the 'userx and 1 other commented on hw' on view.
I'd also suggest you not to store the whole text you want to display, store the required information instead, like: from_id, class_id, type, name and so - this way you can change mechanisms easier later if you need to, and you have to store less.
For those who are looking for a way to not use an app, you can use vanilla PHP and MySQL without using an application. Upon adding a piece of homework, you can add a notification. (yes I know this is open to SQL injection but I'm using regular MySQL for simplicity sake)
SQL for when someone adds homework:
$noti_homework = "INSERT INTO homework(unread, username, recipient, topic) VALUES(true, user_who_added_hw, user_who_receives_notification, homework_name);
Then you can check whether the notification is unread:
$noti_select = "SELECT FROM homework WHERE recipient='".$_SESSION['username']."' AND unread='true'";
$noti_s_result = $conn->query($noti_select);
$noti_s_row = $noti_s_result = $noti_s_result->fetch_assoc();
if ($noti_s_row['unread'] == true) {
}
Finally, you can echo the notification if it's true.
if ($noti_s_row['unread'] == true) {
echo $noti_s_row['username'] . " has sent out the homework " . $noti_s_row['homework'] . ".";
}
The method for liking a comment is pretty similar and in fact a lot easier.
$noti_like = "INSERT INTO notification_like(unread, username, recepient), VALUES(true, user_who_followed, user_who_recieves_notification);
You then just follow the same pattern of echoing the rows like so:
$noti_like = "INSERT INTO notification_like(unread, username, recipient), VALUES(true, user_who_followed, user_who_receives_notification);
$noti_like_select = "SELECT FROM notification_like WHERE recipient='".$_SESSION['username']."' AND unread='true'";
$noti_l_result = $conn->query($noti_like_select);
$noti_l_row = $noti_s_result = $noti_l_result->fetch_assoc();
if ($noti_l_row['unread'] == true) {
echo $noti_l_row['username'] . " has liked your topic!";
}
Then for getting amount of notifications:
$count_like = "SELECT COUNT(*) FROM notification_like WHERE recipient='".$_SESSION['username']."' AND unread='true'";
$num_count = $count_like->fetch_row();
$count_hw = "SELECT COUNT(*) FROM homework WHERE recipient='".$_SESSION['username']."' AND unread='true'";
$num_count_hw = $count_hw->fetch_row();
Using PHP you can echo the two variables, $num_count and $num_count_hw.
$num_count_real = $num_count[0];
$num_count_hw_real = $num_count_hw[0];
echo $num_count_real + $num_count_hw_real;
None of this code is tested FYI. Hope this helped :)
I've made a user group and a user table in my database, called test and user_test. Every user has a field called groups which countains at least one number, but could also contain multiple numbers, for example 1,2,3. The user group table exists of id and group_name.
What I've been trying to do for so long now is to get data from all groups that this user is assigned to. For example, if one user is assigned to groups 1,2,3 (as its shown in the database), it will print out the name of each group with those id. So perhaps it'd print out group 1 group 2 group 3.
$user_test = $this->mysqli->query("SELECT user_id,groups FROM user_test WHERE user_id = '1'");
while($user_test_fetch = $user_test->fetch_array()) {
$groups = $user_test_fetch["groups"];
}
if(strlen($groups) > 1) { // user has more than 1 group
// ???
} else { // user does not have more than 1 group
$search = "id = '".$groups . "'";
}
$group_data = $this->mysqli->query("SELECT * FROM test WHERE ".$search."");
while($group_data_fetch = $group_data->fetch_array()) {
echo $group_data_fetch["group_name"];
}
Or if you have any other way you'd do this task, please feel free to show me! I'm just simply trying to learn how to do this task (preferably, as efficient as possible).
Pretty simple.
If it is stored in the 1,2,3 format. And assuming a single one is called 1 and id is an INT or BIGINT (otherwise this query will slow down if it is a VARCHAR)
Change
if(strlen($groups) > 1) { // user has more than 1 group
// ???
} else { // user does not have more than 1 group
$search = "id = '".$groups . "'";
}
to
$search = "id IN (".$groups.");
this single line will work with a single group or a set of groups, as long as it is separated by a comma (Because SQL loves commas)
Assume I have users database and base_u_group default will be 0 which are not under any groups.
1)base_users
|base_u_id|base_u_username|base_u_group|
------------------------------------------
| 1 | username 1 | 0 |
| 2 | username 2 | 2, 3, 4 |
| 3 | username 3 | 4 |
| 4 | username 4 | 3,5 |
List down all the users. $checkBox will be automatically checked when belong to that edit group.
echo "<tr>";
echo "<td>". $count .". ".$row_User['base_u_username']. "</td>";
echo "<td align=\"center\"><input type=\"checkbox\" class = \"group\" name=\"userList[]\" value=".$row_User['base_u_id']." ".$checkBox."/></td>";
echo "</tr>";
My problem is how do I insert selected check boxes data without duplication for example: 3, 3, 4, 5 --> 3, 4, 5
and when the check boxes are unchecked, it will delete that group in my base_u_group , for example unchecked the check box for username 2 of group 3
2, 3, 4 --> 2, 4
$gid indicates the selected edit group.
This is what I did so far:
<?php
$userGroup = $_POST['userList'];
foreach($userGroup as $a)
{
$selSQL = base_executeSQL("SELECT * FROM base_users WHERE base_u_id='".$a."'");
while($row_SQL = base_fetch_array($selSQL))
if($row_SQL['base_u_group'] != "0")
{
$data = explode(", ",$row_SQL['base_u_group']);
for($i=0; $i<count($data);$i++)
{
//insert to user group if base_u_group does not find the group ID
if($gid <> $data[$i])
base_executeSQL("UPDATE base_users SET base_u_group='".$gid. ", ". $row_SQL['base_u_group']."' WHERE base_u_id='".$a."'");
}
}
//if the user does not belong to any groups: base_u_group = 0
else
base_executeSQL("UPDATE base_users SET base_u_group='".$gid."' WHERE base_u_id='".$a."'");
}
?>
EDIT: deletion of groups
$data = explode(", ",$row_SQL['base_u_group']);
$ok = true;
for($i=0; $i<count($data);$i++)
{
//insert to user group if base_u_group does not find the group ID
if($gid == $data[$i])
{
$arr = array_merge(array_diff($data,array($gid)));
$newArray = implode(", ",$arr);
base_executeSQL("UPDATE base_users SET base_u_group='".$newArray."' WHERE base_u_id!='".$row_SQL['base_u_id']."' AND base_u_domain='local'");
$ok = false;
}
}
if (ok) base_executeSQL("UPDATE base_users SET base_u_group='".$gid. ", ". $row_SQL['base_u_group']."' WHERE base_u_id='".$a."'");
If you want to stick with your current database design, then your approach is actually the easiest you can do. Moving this logic to MySQL would be very hard, and would have no advantages over your solution. Seems like your approach already handles all the requirements you posted for the adding a group to the user, and deleting the group is pretty much the same logic.
However, I would highly suggest changing your database design. Remove base_u_group column completely, and create a new table user_groups with two columns user_id and group_id. Make a unique key consisting of both of them. Now to add a group, just INSERT into that table, and the unique key will prevent you from inserting the same group twice. Deleting from a group is now also as trivial as deleting from that table. To get all the groups for the user, just execute SELECT group_id FROM user_groups WHERE user_id=$user_id (well, with proper escaping, or via a prepared statement).
You might also make user_id be a foreign key to your current table, so that it disallows inserting invalid user_ids. Also, if you have a table for groups, adding a foreign key from user_groups to that table would help avoid invalid group ids as well.
EDIT: Apparently I misunderstood part of your question. I thought you already have a working solution, and were asking for a better one. I can immediately see an issue in your solution, that causes duplicates, it is easy to fix, just make the following changes to your code:
$data = explode(", ",$row_SQL['base_u_group']);
$ok = true;
for($i=0; $i<count($data);$i++)
{
//insert to user group if base_u_group does not find the group ID
if($gid == $data[$i]) $ok = false;
}
if (ok) base_executeSQL("UPDATE base_users SET base_u_group='".$gid. ", ". $row_SQL['base_u_group']."' WHERE base_u_id='".$a."'");
To see why your code is wrong, think what happens if $data = {1, 2} and $gid is 2 (in which case you obviously don't want to add it). You iterate over every element of $data, so on the first iteration your $data[i] is 1. Since 1 != 2, you update your table and add another 2 at the end
With my changes, I first iterate over all elements of data, and make sure none of them is equal to $gid, and only if that's the case I run a query once to append $gid at the end.
Unfortunately, from your code it is not clear what kind of request you issue for delete, but the logic will be similar. You would go over every element of data, and if any of them is equal to what you want to delete, then just just remove it from data and break from the loop. Then implode your data and store it into the database with an UPDATE query.
Firstly, I havent been able to find anything useful on the subject, anywhere really.
I'm trying to make something somewhat simular to a forum,
A small explanation,
(And yes, I know its not seo, but I'm only looking for functionality atm.)
Lets say you go to example.com/?1, Then the database entry with the ID of 1 would be displayed on the index page, If you go to example.com/?3 then the DB entry with the ID of 3 would be displayed, etc..
DB Structure
----------------------------------------
| id | label | description | parent_id |
|---------------------------------------
| 1 | General | NULL | 0 |
| 2 | Public | NULL | 1 |
| 3 | Private | NULL | 1 |
----------------------------------------
PHP Code
if ($stmt = $mysqli->prepare("SELECT id, label, description, parent_id FROM categories")) {
$stmt->execute(); // Execute the query.
$stmt->store_result();
$stmt->bind_result($id, $label, $desc, $parent); // Get variables from result.
while ($stmt->fetch()) {
if(isset($id)) {
echo "Hello, This is the $label category";
}
}
}
What i'm missing is a way to get the users current "isset" (.com/?10, .com/?5, ETC) Before the query is run so i can check for that isset in the DB and get the correct values, right now it's outputting all rows in the DB, I would highly appreciate any help with it :)
If you know of a better way of doing something like this(without using a framework), please let me know!
From a terminology standpoint, it sounds like you are interested in understand what parameters are passed in the request's query string.
In your case, you are doing something a little weird in that be having URI format like /?* where * is integer ID value, you would actually be passing a variably named parameter. Since you don't know what the parameter name is, you would have to do something like
$ids_in_query_string = array_keys($_GET);
To store the key names which infer which ID(s) were requested.
What I would suggest is to form your query string like /?id=*, that way you always know which key in $_GET to check against. For example:
$id = null;
if (!empty($_GET['id']) && is_numeric($_GET['id'])) {
$id = $_GET['id'];
}
if (!is_null($id)) {
// perform your query for selected ID
} else {
// do something else
}
I made a simple following-follower system with php(pdo) and mysql. My problem is,
Let's say there is a user name Mike with ID number 99. And Mike has two followers, Greg(id = 77) and Jenny(id = 88)
Greg's following list looks like this (1,2,3,4,99), and Jenny's following list looks like this (5,6,99,7)
What I am trying to do is, when Mike(99) deletes his account, I want to remove id number 99 from Greg(77) and Jenny(88)'s following lists.
Table called 'mytable' has 3 fields. id(INT), following_list(text), follower_list(text).
I've been struggling with this problem for a few days. Can anyone please give me some advice? Thank you so much in advance!!!
Below is my update function
public function update_following_list(){
// $this->myid is Mike's id number(99) who is about to delete his account
// Selecting the list of people following Mike
$query = "SELECT 'follower_list' FROM 'mytable' WHERE 'id' = $this->myid";
$result = $this->dbc->query($query);
foreach($result as $row){
$this->follower_list = $row['follower_list'];
// When I echo $this->follower_list, I get 77,88
// Now querying Greg(77) and Jenny(88)'s following_lists, which have Mike's id number(99) in them.
$query = "SELECT 'following_list' FROM 'mytable' WHERE 'id' IN ($this->follower_list)";
$result = $this->dbc->query($query);
foreach($result as $row){
$this->following_list = $row['following_list'];
// When I echo $this->following_list, I get both Greg(1,2,3,4,99) and Jenny(5,6,99,7)'s following lists
// Here, I am turning following list into array by using explode
$this->following_array = explode(",", $this->following_list);
foreach($this->following_array as $key => $value){
if($value == $this->myid){
// Removing Mike(99)'s id number from Greg and Jenny's following lists
unset($this->following_array[$key]);
// Add back commas, which will then become string
$this->new_following_list = implode(",", $this->_following_array);
// When I echo $this->new_following_list, I get both Greg(1,2,3,4) and Jenny(5,6,7)'s new list without Mike(99)'s id number
// My problem starts here. I was able to remove Mike's id number from Greg and Jenny's lists. But I am having a trouble updating Greg and Jenny's following lists with new following lists.
// The update query below does not work...
$query = "UPDATE 'mytable' SET 'following_list' = $this->new_following_list WHERE 'id' IN ($this->follower_list)";
$result = $this->dbc->query($query);
} // End of if($value == $this->myid)
} // End of foreach($this->following_array as $key => $value)
}
}
} // End of function
This will not scale properly. It's better to normalize your data model like this:
following
user_id | following_user_id
---------------------------
77 | 1
77 | 2
77 | 3
77 | 4
77 | 99
88 | 5
88 | 6
88 | 7
88 | 99
And add two indexes:
UNIQUE(user_id, following_user_id)
INDEX(following_user_id)
To get followers of 99:
SELECT * FROM following WHERE following_user_id=99;
To see who 77 follows:
SELECT * FROM following WHERE user_id=77;
I think your database setup is not optimal. Store comma-separated values in one field, screams for a binding table and some normalization !!
You should have your comma separated value list to be a table/relation, e.g.:
followTable:/ user_id | follows
Deletion of mike's id is then as simple as:
DELETE FROM followTable WHERE follows = 99 OR user_id = 99
The latter makes sure the links between Mike and his followers are being deleted also.