This topic is locked

Management of a CHAT

7/2/2021 11:23:51 AM
PHPRunner Tips and Tricks
fhumanes author

img alt
At present, with teleworking, it becomes very necessary to have direct and immediate communication with the rest of the project team.

There are many commercial products with a variety of possibilities, but, for me, it was a challenge to make an application that could exchange messages with files immediately, simulating as much as possible, the famous whatsapp.

Actually the application is an excuse, because what I wanted to do is a Phprunner application that had some content update features (with notifications included) without continuously refreshing the page and for this, I have chosen to make an example of application Chat.

Functional objectives

The objectives that I marked me are:

  • To be possible, it will run on PC and mobile, with good features and interface in both.
  • I had notifications of new messages, without we had to refresh the page.
  • It had, in addition to the notification, updating of the information of the page, without having to do action by the user.
  • I would have communication from person to person, but also disposed of distribution groups of messages.
  • I would have Emoji. Because it is not possible to use short messages without emoji.
  • That also could be sent files (images, pdf, etc.)
  • That the interface of the application is very, very simple and that would have very dynamic screens (different presentations depending on situation and content).

DEMO: https://humanes.com/chat

Example users (login is the same as the password): admin, fhumanes, friend1, friend2.

To dispose of all the development information and even, to download the code, access my portal.

fhumanes author 7/2/2021

Application interface

img alt
You have included features of screens and application icon, to be able to install it in both Windows and mobile.

img alt
A very different interface has been defined to the usual phprunner to show all the contacts of the logged user. The image of group contact, square and red border and individual contact, round with blue border has been used. The order of appearance is by date of the last received message and a green ball will appear, with the messages that have not been read of that contact.

The total of unread messages appears at the header. This number will be updated when new messages arrive, without the user having to do anything.

img alt
Selected The contact shows the messages exchanged with it. The last one appears the first one. If it has never been shown, a green ball will appear on the left of the message. Along with the author, the date and time of the message appears. If the author and date is the same as the previous one, is not shown to facilitate reading.

On the right is the message in HTML, and under the handheld you will be the attached files that has said message.

Right now, it has a basic operation, but it can be expanded according to the needs of your project.

Both on this screen and in the previous one, the number of messages pending Read (Green Ball) is refreshed and the notifications of new messages at the lower right edge of the screen are displayed. If you click on the notification, the page is refreshed in which the user is and the new content is displayed.

Technical solution

The data model that I have used is this:

img alt

With this model it is facilitated that the same message is shown (with different states) for each of the recipients. It is the way not to duplicate the contents, this being the broadest information of the entire system.

In the "contact" table, the user's relationship information is maintained and the information of a group. We can appreciate in the code, that the information is displayed depending on the contact type. In all contact type cases, the "member" table is always used to contain all users of that contact.

In the table "message", the general data of the messages are available, but we help each other from several tables.

  • "recipients" to manage the information of all recipients and the status of that message for each recipient.
  • "contents" to store and manage the message (which can be large) and the attached files. The denormalization of this table is done to improve returns from the database manager.

The following plugins have been used in development (which you can download from this portal):

  • summernote.- To enter the text of the messages.
  • switch.- As an interface, for the decision in the contents.

Also, the JavaScript notify.js library has been used. https://github.com/jpillora/notifyjs as a manager of notifications. (On mobile devices, these notifications do not occur but do not generate error).

For those who are learning Phprunner, I recommend the revision of the code of this example. It is little code, but it is full of details, functionalities or uses that are not in the Phprunner manual and facilitates a lot of ideas to use in other projects.

Equity some examples of programming:

chat_ajax.php Program that resolves automatic requests that makes the browser without user interaction.

<?php
@ini_set("display_errors","1");
@ini_set("display_startup_errors","1");

require_once("include/dbcommon.php");
header("Expires: Thu, 01 Jan 1970 00:00:01 GMT");

$id_user = $_SESSION['id_user'];
$rs = DB::Query("SELECT count(*) count FROM recipients WHERE isRead = 0 AND user_id = $id_user");
$data = $rs->fetchAssoc();
$count = $data['count'];

$message = '*';
$rs2 = DB::Query("SELECT count(*) count FROM recipients WHERE isNotified = 0 AND user_id = $id_user order by dateAdd desc");
$data2 = $rs2->fetchAssoc();
$count2 = $data2['count'];

$rs2 = DB::Query("SELECT * FROM recipients WHERE isNotified = 0 AND user_id = $id_user order by dateAdd desc");

if ( $count2 <> 0 ){ // There are messages to notify
$data2 = $rs2->fetchAssoc();
$id_recipients = $data2['id_recipients'];
$data = array();
$keyvalues = array();
$data["isNotified"] = "1";
$keyvalues["id_recipients"] = $id_recipients;
DB::Update("recipients", $data, $keyvalues );

$id_contact = $data2['contact_id'];
$sql = <<<EOT
SELECT
contact.id_contact,
contact.administrator_id,
contact.isGroup,
if(contact.isGroup = 1, contact.nameGroup, user.name) AS name
FROM contact AS contact
JOIN member AS member ON ( member.contact_id = contact.id_contact )
JOIN user user ON ( member.user_id = user.id_user )
WHERE (contact.isDelete = 0 and user.id_user <> $id_user and contact.id_contact = $id_contact)
EOT;
$rs = DB::Query($sql);
$data = $rs->fetchAssoc();
$name = $data['name'];
$message = "You have received a new message from: '$name'";
}

echo "$count;$message;";
?>

Phprunner creates the mfhandler.php file to manage the rise and down of files. To eliminate restrictions on showing the users' photos I created the custom_mfhandler.php file.

To show at the header the total number of messages that are unread and schedule the refreshment of the data and notifications I have programmed notify_snnipet:

$id_user = $_SESSION['id_user'];
$rs = DB::Query("SELECT count(*) count FROM recipients WHERE isRead = 0 AND user_id = $id_user");

$data = $rs->fetchAssoc();

echo '   <b>Message Pending Reading:</b> <span id="pending_reading" class="badge badge-info">'.$data['count'].'</span>';

$js = <<<EOT

<script src="notify/notify.js"></script>
<script>
// -----------------------------------------------------------------------------------------------------
var site ='chat_ajax.php'; // To recover accountant new messages

var HttpClient = function() {
this.get = function(aUrl, aCallback) {
var anHttpRequest = new XMLHttpRequest();
anHttpRequest.onreadystatechange = function() {
if (anHttpRequest.readyState == 4 && anHttpRequest.status == 200)
aCallback(anHttpRequest.responseText);
}
anHttpRequest.open( "GET", aUrl, true );
anHttpRequest.send( null );
}
}

// -----------------------------------------------------------------------------------------------------
function onShowNotification () {
console.log('notification is shown!');
}

function onCloseNotification () {
console.log('notification is closed!');
}

function onClickNotification () {
window.location.reload(false);
console.log('notification was clicked!');
}

function onErrorNotification () {
console.error('Error showing notification. You may need to request permission.');
}

function onPermissionGranted () {
console.log('Permission has been granted by the user');
doNotification();
}

function onPermissionDenied () {
console.warn('Permission has been denied by the user');
}

function doNotification (response='') {
if (!Notify.needsPermission) {
var myNotification = new Notify('PHPRuner CHAT', {
body: 'Notice: '+response,
// tag: task,
notifyShow: onShowNotification,
notifyClose: onCloseNotification,
notifyClick: onClickNotification,
notifyError: onErrorNotification,
timeout: 10
});

myNotification.show();
} else if (Notify.isSupported()) {
Notify.requestPermission(onPermissionGranted, onPermissionDenied);
}
}

function loadlink(){
var client = new HttpClient();
client.get(site, function(response) {
console.log('Response: '+response);
resp = response.split(';');
if ( resp[1] != '*' ){
doNotification(resp[1]);
}
$('#pending_reading').text(resp[0]); // Update count total within reading
})
}
loadlink(); // This will run on page load
setInterval(function(){
loadlink(); // this will run after every 15 seconds
}, 15000);
</script>
EOT;
echo $js;

As you can see, events on notifications are completely controlled and the information changes control times can be adapted.

I'm not going to put much more code because all he is full of details, but for the "powerful" sample that can be phprunner, I leave the query's of the "contact" and "message" tables:

SELECT
id_contact,
contact.administrator_id,
contact.isGroup,
contact.nameGroup,
contact.user_id,
contact.photo,
contact.isDelete,
user1.name AS name1,
user2.name AS name2,
member.user_id AS member_user_id,
statistics.lastMessage,
(statistics.countMessage - statistics.sumRead) pendingMessage
FROM contact
LEFT OUTER JOIN `user` AS user1 ON contact.administrator_id = user1.id_user
LEFT OUTER JOIN `user` AS user2 ON contact.user_id = user2.id_user
INNER JOIN member ON contact.id_contact = member.contact_id
LEFT JOIN (
SELECT user_id, contact_id, max(dateAdd) lastMessage, count(isRead) countMessage, sum(isRead) sumRead
FROM recipients
group by user_id, contact_id) statistics
on (statistics.user_id = member.user_id and statistics.contact_id = contact.id_contact)

-----------------------------------------------------------------------------------------

SELECT
message.id_message,
message.author_id,
message.contact_id,
message.isDelete,
message.dateAdd,
SUBSTRING(message.dateAdd, 1, 10) AS dateCreation,
concat(SUBSTRING(message.dateAdd,1,16), ':00') AS timeCreation,
message.dateDelete,
contents.id_contents,
contents.message_id,
contents.text,
0 AS isAttached,
contents.attachedfiles,
recipients.id_recipients,
recipients.user_id,
recipients.isRead,
recipients.isNotified
FROM message
LEFT OUTER JOIN contents ON message.id_message = contents.message_id
LEFT OUTER JOIN recipients ON message.id_message = recipients.message_id

I hope you like the example, above all, that you are useful and for any questions or what you need, you can contact me through email fernandohumanes@gmail.com.

As always, I leave all the code so that or you can download and install in your Windows and you can make all the changes that your system requires.

fhumanes author 7/2/2021

Sorry, the link to the demo is poorly written.

The correct URL is: https://fhumanes.com/chat