ejemplo - remove html tags php
Sistema de notificaciones mediante php y mysql. (3)
Bueno, esta pregunta tiene 9 meses de edad, así que no estoy seguro de si OP todavía está en necesidad de una respuesta, pero debido a los muchos puntos de vista y la generosa recompensa, también me gustaría agregar mi mostaza (dicho en alemán ...).
En este post, intentaré hacer un ejemplo simple explicado sobre cómo comenzar a construir un sistema de notificación.
Edit: Bueno, ok, esto resultó ser mucho más largo de lo que esperaba. Me cansé mucho al final, lo siento.
WTLDR;
Pregunta 1: tener una bandera en cada notificación.
Pregunta 2: Almacene todas las notificaciones como un único registro dentro de su base de datos y agrúpelas cuando se soliciten.
Estructura
Supongo que las notificaciones serán algo así como:
+---------------------------------------------+
| ▣ James has uploaded new Homework: Math 1+1 |
+---------------------------------------------+
| ▣ Jane and John liked your comment: Im s... |
+---------------------------------------------+
| ▢ The School is closed on independence day. |
+---------------------------------------------+
Detrás de las cortinas esto podría verse algo así:
+--------+-----------+--------+-----------------+-------------------------------------------+
| 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. |
+--------+-----------+--------+-----------------+-------------------------------------------+
Nota: No recomiendo agrupar las notificaciones dentro de la base de datos, ya que en el tiempo de ejecución esto mantiene las cosas mucho más flexibles.
- No leído
Cada notificación debe tener una marca para indicar si el destinatario ya ha abierto la notificación. - Recipiente
Define quién recibe la notificación. - Remitente
Define quién activó la notificación. - Tipo
En lugar de tener todos los mensajes en texto sin formato dentro de su base de datos, cree tipos. De esta manera, puede crear controladores especiales para diferentes tipos de notificación dentro de su backend. Reducirá la cantidad de datos almacenados dentro de su base de datos y le dará aún más flexibilidad, le permitirá traducir fácilmente las notificaciones, los cambios de mensajes pasados, etc. - Referencia
La mayoría de las notificaciones tendrán una referencia a un registro en su base de datos o su aplicación.
Todos los sistemas en los que he estado trabajando tienen una relación de referencia simple de 1 a 1 en una notificación, puede tener 1 a n, tenga en cuenta que continuaré mi ejemplo con 1: 1. Esto también significa que no necesito un campo que defina a qué tipo de objeto se hace referencia porque esto está definido por el tipo de notificación.
Tabla SQL
Ahora, al definir una estructura de tabla real para SQL, tomamos algunas decisiones en términos del diseño de la base de datos. Voy a ir con la solución más simple que se verá algo así:
+--------------+--------+---------------------------------------------------------+
| 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. |
+--------------+--------+---------------------------------------------------------+
O para la gente perezosa, el comando SQL create table para este ejemplo:
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;
Servicio PHP
Esta implementación depende completamente de las necesidades de su aplicación. Nota: Este es un ejemplo, no el estándar de oro sobre cómo construir un sistema de notificación en PHP.
Modelo de notificación
Este es un modelo base de ejemplo de la notificación en sí, nada especial, solo las propiedades necesarias y los métodos abstractos messageForNotification
y messageForNotifications
que esperábamos que se implementaran en los diferentes tipos de notificación.
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);
}
}
Tendrá que agregar un constructor , captadores , configuradores y ese tipo de cosas por usted mismo en su propio estilo, no voy a proporcionar un sistema de notificación listo para usar.
Tipos de notificaciones
Ahora puede crear una nueva subclase de Notification
para cada tipo. Este siguiente ejemplo manejaría la acción similar de un comentario:
- A Ray le ha gustado tu comentario. (1 notificación)
- A John y Jane les gustó tu comentario. (2 notificaciones)
- A Jane, Johnny, James y Jenny les gustó tu comentario. (4 notificaciones)
- A Jonny, James y otros 12 les gustó tu comentario. (14 notificaciones)
Ejemplo de implementación:
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
}
}
Gerente de notificaciones
Para trabajar con sus notificaciones dentro de su aplicación, cree algo como un administrador de notificaciones:
class NotificationManager
{
protected $notificationAdapter;
public function add(Notification $notification);
public function markRead(array $notifications);
public function get(User $user, $limit = 20, $offset = 0) : array;
}
La propiedad notificationAdapter
debe contener la lógica en comunicación directa con su backend de datos en el caso de este ejemplo mysql.
Creando notificaciones
Usar los activadores mysql
no es incorrecto, porque no hay una solución incorrecta. Lo que funciona, funciona ... Pero recomiendo encarecidamente que la base de datos no maneje la lógica de la aplicación.
Así que dentro del administrador de notificaciones es posible que desee hacer algo como esto:
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(),
]);
}
}
Detrás del método add
del notificationAdapter
puede haber un comando de inserción de mysql en bruto. El uso de este adaptador de abstracción le permite cambiar fácilmente de mysql a una base de datos basada en documentos como mongodb, lo que tendría sentido para un sistema de notificación.
El método isDoublicate
en notificationAdapter
debería simplemente verificar si ya existe una notificación con el mismo recipient
, sender
, type
y reference
.
No puedo señalar lo suficiente que esto es sólo un ejemplo. (También tengo que acortar los próximos pasos, esta publicación es ridículamente larga -.-)
Entonces, asumiendo que tienes algún tipo de controlador con una acción cuando un maestro carga la tarea:
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);
}
}
Creará una notificación para cada alumno de maestro cuando él suba una nueva tarea.
Leyendo las notificaciones
Ahora viene la parte difícil. El problema con la agrupación en el lado de PHP es que tendrá que cargar todas las notificaciones del usuario actual para agruparlas correctamente. Esto sería malo, bueno, si solo tiene unos pocos usuarios, probablemente todavía no haya problemas, pero eso no lo hace bueno.
La solución fácil es simplemente limitar el número de notificaciones solicitadas y solo agruparlas. Esto funcionará bien cuando no haya muchas notificaciones similares (como 3-4 por 20). Pero digamos que la publicación de un usuario / estudiante recibe alrededor de cien "me gusta" y solo seleccionas las últimas 20 notificaciones. El usuario solo verá que a 20 personas les gustó su publicación y esa sería su única notificación.
Una solución "correcta" sería agrupar las notificaciones que ya se encuentran en la base de datos y seleccionar solo algunas muestras por grupo de notificación. De lo que solo tendría que inyectar el conteo real en sus mensajes de notificación.
Probablemente no haya leído el texto a continuación, así que permítame continuar con un fragmento de código:
select *, count(*) as count from notifications
where recipient_id = 1
group by `type`, `reference_id`
order by created_at desc, unread desc
limit 20
Ahora sabe qué notificaciones deben existir para el usuario dado y cuántas notificaciones contiene el grupo.
Y ahora la parte de mierda. Todavía no pude encontrar una mejor manera de seleccionar un número limitado de notificaciones para cada grupo sin hacer una consulta para cada grupo. Todas las sugerencias aquí son muy bienvenidas.
Entonces hago algo como:
$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;
}
Ahora continuaré asumiendo que el método get
notificationAdapter
implementa esta agrupación y devuelve una matriz como esta:
[
{
count: 12,
items: [Note1, Note2, Note3, Note4, Note5]
},
{
count: 1,
items: [Note1]
},
{
count: 3,
items: [Note1, Note2, Note3]
}
]
Debido a que siempre tenemos al menos una notificación en nuestro grupo y nuestro pedido prefiere notificaciones No leídas y Nuevas , podemos usar la primera notificación como muestra para la representación.
Para poder trabajar con estas notificaciones agrupadas necesitamos un nuevo objeto:
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);
}
}
Y finalmente podemos juntar la mayoría de las cosas. Así es como podría verse la función de obtención en el NotificationManager
:
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;
}
Y realmente finalmente dentro de una posible acción del controlador:
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);
}
Quería implementar un sistema de notificación para nuestra escuela, es una aplicación web php / mysql que no está abierta al público, por lo que no recibe mucho tráfico. "500-1000 visitantes diarios".
1. Mi enfoque inicial fue usar desencadenadores MYSQL:
Usé un AFTER INSERT trigger
Mysql AFTER INSERT trigger
para agregar registros a una tabla llamada notifications
. Algo como.
''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);''
Este tipo de magia negra funcionó muy bien, pero no pude hacer un seguimiento de si esta notificación es nueva "para mostrar el recuento de notificaciones nuevas para el usuario". Así que agregué una página llamada notificaciones.
Las notificaciones se recuperan con algo como
SELECT n.* from notifications n
JOIN user_class on user_class.class_id = n.class_id where user_class.user_id = X;
Nota: la tabla user_class vincula al usuario con la clase "user_id, class_id, subject_id" -subject es nulo a menos que el usuario sea un profesor ''
Ahora mis próximos retos son.
- ¿Cómo hacer un seguimiento de las notificaciones nuevas vs viejas por usuario?
- ¿Cómo puedo agregar notificaciones que son similares al usuario en una fila?
por ejemplo, si 2 usuarios comentaron algo, entonces no inserte una nueva fila, simplemente actualice la anterior con algo como ''userx y 1 otro comentado en hw''.
Muchas gracias
Editar
Según la respuesta a continuación, para establecer una marca de lectura / no leída en la fila, tendré que tener una fila para cada estudiante, no solo una fila para toda la clase ... lo que significa editar el disparador a algo como
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
Puede resolver el problema con la creación de una tabla NotificationsRead, que contiene el ID del usuario y el ID de la notificación que el usuario deseaba marcar como leída. (De esta manera, puede mantener a cada alumno y al maestro separados). Luego, puede unirse a esa tabla a la tabla de su notificación y sabrá si debe considerarse vieja o nueva.
La respuesta de geggleto fue correcta sobre la segunda parte, puede capturar las notificaciones con SELECT *, COUNT(*) AS counter WHERE ... GROUP BY ''type''
entonces sabrá cuántos del mismo tipo tiene allí y puede prepararse El ''userx y 1 otro comentó sobre hw'' a la vista.
También le sugiero que no almacene todo el texto que desea mostrar, sino que almacene la información requerida, como: from_id, class_id, type, name y así, de esta forma puede cambiar los mecanismos más fácilmente si lo necesita, y Tiene que almacenar menos.
Responder:
Introduzca una variable leída / no leída en la notificación. Luego puede extraer solo notificaciones no leídas haciendo ... DONDE status = ''UNREAD'' en su sql.
Realmente no puedes ... querrás enviar esa notificación. Lo que puede hacer es agregarlos aunque use GROUP BY. Es probable que desee agruparse en algo único como una nueva tarea, por lo que podría ser algo así como ... GRUPO POR
homework
.id