2011-04-05 10 views
16

Para un proyecto personal, necesito crear un foro usando PHP y MySQL. No me es posible usar un paquete de foro ya creado (como phpBB).Manejo de publicaciones no leídas en PHP/MySQL

Actualmente estoy trabajando con la lógica necesaria para construir una aplicación de este tipo, pero ha sido un día largo y estoy luchando con el concepto de manejar las publicaciones no leídas para los usuarios. Una solución que tenía era tener una tabla separada que contiene esencialmente todos los ID de correos y los ID de usuario, para determinar si han sido leídos:

tbl_userReadPosts: user_id, post_id, read_timestamp

Obviamente, si el ID de un usuario aparece en esta tabla, se Sé que han leído la publicación. Esto es genial, excepto si tenemos miles de publicaciones por día (lo cual es más que posible en el sistema que se propone), y miles de usuarios. Esta tabla se volvería enorme en cuestión de días, si no horas.

Otra opción sería rastrear la última actividad del usuario como una marca de tiempo, y luego recuperar todas las publicaciones realizadas después de que se actualizó su última actividad. Esto funciona en teoría, pero digamos que un usuario está escribiendo una publicación extremadamente larga y, mientras tanto, varios miembros también inician nuevos hilos o responden a publicaciones en otros hilos. Cuando el usuario envía su nueva publicación, su última actividad se actualizaría y, por lo tanto, no coincidiría con las realizadas en el ínterin.

¿Alguien tiene experiencia con esto, y cómo lo abordaron?

He comprobado en phpBB y parece que el sistema asigna una sesión personalizada a cada usuario, y funciona sobre esa base, pero la documentación es bastante escasa en cuanto a cómo se trata con las publicaciones no leídas.

Pensamientos y opiniones recibidas con gratitud, como siempre.

Respuesta

6

Perdón por la respuesta rápida pero solo tengo un segundo. Definitivamente no desea almacenar la información leída en la base de datos, como ya ha deducido, esta tabla se volvería gigantesca.

Algo entre lo que ya ha sugerido: almacene la última actividad de los usuarios, y junto con el almacenamiento de información de lo que han visto en la cookie, para determinar qué hilos/publicaciones ya han leído.

Esto descarga el almacenamiento a la cookie del lado del cliente, que es mucho más eficiente.

+0

Di todos los contestadores un +1 por su entrada. Me gusta tu sugerencia, John. Voy a tener un juego con este método (o combinación, más bien). ¡Gracias! – BenM

7

Una tabla que contiene todos los user_ids y post_ids es una mala idea, ya que crece exponencialmente. Imagine si su solución de foro creció a un millón de publicaciones y 50,000 usuarios. Ahora tiene 50 mil millones de registros. Eso será un problema.

El truco es usar una tabla como usted dijo, pero solo contiene las publicaciones que se han leído desde el inicio de sesión, de las publicaciones que se publicaron entre el último inicio de sesión y este inicio de sesión.

Todas las publicaciones realizadas antes del último inicio de sesión se consideran leídas.

IE, me conecté por última vez el 3/04/2011, y luego me conecté hoy. Todas las publicaciones realizadas antes del 4/3/2011 se consideran leídas (no son nuevas para mí). Todas las publicaciones entre 4/3/2011 y ahora no se leen a menos que se vean en la tabla de lectura. La tabla de lectura se vacía cada vez que inicio sesión.

De esta manera, su tabla de publicaciones de lectura nunca debe tener más de un centenar de registros para cada miembro.

3

En lugar de tener una nueva fila para cada usuario de publicación *, puede tener un campo en la tabla de usuarios que contenga una cadena separada por comas con identificadores posteriores que el usuario haya leído.

Obviamente, el usuario no necesita saber que hay publicaciones no leídas de hace 2 años, por lo que solo muestra "Nueva publicación" para las publicaciones realizadas en las últimas 24 horas y no está en la cadena separada por comas.

También podría resolver esto con una variable de sesión o una cookie.

2

Este método almacena el postID de acceso más reciente por separado para cada forumID.

No es tan detallada como una solución que realiza un seguimiento de cada publicación individualmente, pero reduce la cantidad de datos que necesita almacenar por usuario y aún proporciona una forma decente de realizar un seguimiento del historial de vistas de un usuario.

<?php 
    session_start(); 
    //error_reporting(E_ALL); 

    // debug: clear session 
    if (isset($_GET['reset'])) { unset($_SESSION['activity']); } 

    // sample data: db table with your forum ids 
    $forums = array(
     // forumID  forumTitle 
      '1'  => 'Public Chat', 
      '2'  => 'Member Area', 
      '3'  => 'Moderator Mayhem' 
    ); 

    // sample data: db table with your forum posts 
    $posts = array(
     // postID     forumID  postTitle 
      '12345' => array( 'fID'=>'1', 'title'=>'Hello World'), 
      '12346' => array( 'fID'=>'3', 'title'=>'I hate you all'), 
      '12347' => array( 'fID'=>'1', 'title'=>'Greetings!'), 
      '12348' => array( 'fID'=>'2', 'title'=>'Car thread'), 
      '12349' => array( 'fID'=>'1', 'title'=>'I like turtles!'), 
      '12350' => array( 'fID'=>'2', 'title'=>'Food thread'), 
      '12351' => array( 'fID'=>'3', 'title'=>'FR33 V1AGR4'), 
      '12352' => array( 'fID'=>'3', 'title'=>'CAPSLOCK IS AWESOME!!!!!!!!'), 
      '12353' => array( 'fID'=>'2', 'title'=>'Funny pictures thread'), 
    ); 

    // sample data: db table with the last read post from each forum 
    $userhist = array(
     // forumID  postID 
      '1'  => '12344', 
      '2'  => '12350', 
      '3'  => '12346' 
    ); 

    // reference for shorter code 
    $s = &$_SESSION['activity']; 

    // store user's history into session 
    if (!isset($s)) { $s = $userhist; } 

    // mark forum as read 
    if (isset($_GET['mark'])) { 
     $mid = (int)$_GET['mark']; 
     if (array_key_exists($mid, $forums)) { 
      // sets the last read post to the last entry in $posts 
      $s[$mid] = array_search(end($posts), $posts); 
     } 
     // mark all forums as read 
     elseif ($mid == 0) { 
      foreach ($forums as $fid=>$finfo) { 
       // sets the last read post to the last entry in $posts 
       $s[$fid] = array_search(end($posts), $posts); 
      } 
     } 
    } 

    // mark post as read 
    if (isset($_GET['post'])) { 
     $pid = (int)$_GET['post']; 
     if (array_key_exists($pid, $posts)) { 
      // update activity if $pid is newer 
      $hist = &$s[$posts[$pid]['fID']]; 
      if ($pid > $hist) { 
       $hist = $pid; 
      } 
     } 
    } 

    // link to mark all as read 
    echo '<p>[<a href="?mark=all">Read All</a>]</p>' . PHP_EOL; 

    // display forum/post info 
    foreach ($forums as $fid=>$finfo) { 
     echo '<p>Forum: ' . $finfo; 
     echo ' [<a href="?mark=' . $fid . '">Mark as Read</a>]<br>' . PHP_EOL; 
     foreach ($posts as $pid=>$pinfo) { 
      if ($pinfo['fID'] == $fid) { 
       echo '- Post: <a href="?post=' . $pid . '">' . $pid . '</a>'; 
       echo ' - ' . ($s[$fid] < $pid ? 'NEW' : 'old'); 
       echo ' - "' . $pinfo['title'] . '"<br>' . PHP_EOL; 
      } 
     } 
     echo '</p>' . PHP_EOL; 
    } 

    // debug: display session value and reset link 
    echo '<hr><pre>$_SESSION = '; print_r($_SESSION); echo '</pre>' . PHP_EOL; 
    echo '<hr>[<a href="?reset">Reset Session</a>]' . PHP_EOL; 
?> 

Nota: Obviamente este ejemplo es sólo para fines de demostración. Parte de la estructura y la lógica pueden necesitar cambios cuando se trata de una base de datos real.

1

Phpbb2 ha implementado esto bastante simple. Simplemente muestra todas las publicaciones desde su último inicio de sesión. De esta forma, no necesita almacenar ninguna información sobre lo que el usuario realmente ha visto o leído.

0

Algo que no se sugirió fue utilizar Big Data para almacenar ese tipo de información, es decir, NoSQL. Está hecho específicamente para manejar este tipo de datos.

Uso MongoDB pero puede encontrar una aplicación NoSQL que se adapte a sus necesidades. http://nosql.findthebest.com/

Esto le permitirá escalar a otros usos aplicables en lugar de solo en lo que está trabajando ahora. Por ejemplo, foros, publicaciones, tickets, notas, mensajes, etc.

Otra sugerencia es que puede almacenar alternativamente los datos en "Metadatos", similar a la sugerencia de csv, pero dándole una estructura más flexible y almacenable, utilizando serializar para comprimir los datos de su objeto para cargar y deserializar en tiempo de ejecución. Por lo tanto, funciona como una sesión que no caduca y que está asociada con user_id en lugar de session_id que puede cargarse según demanda y segregarse como prefiera. Por ejemplo, cuando se carga una página de foro para un usuario en particular.

por ejemplo:

(ejemplos codificados secos - ajustar para adaptarse a su propio esquema)

<?php 
/** 
array(
    "form_id1" => array("post_id1", "post_id2",), 
    "form_id2" => array("post_id1", "post_id2",) 
); 
*/ 

$this->user->metadata = unserialize(file_get_contents('/metadata/forums/' . $this->user->id)); 

if(!isset($this->user->metadata[$this->forum->id])){ 
    $this->user->metadata[$this->forum-id] = array(); 
} 
if(!in_array($this->post->id, $this->user->metadata[$this->forum->id])){ 
    $this->user->metadata[$this->forum-id][] = $this->post->id; 
} 
file_put_contents('/metadata/forums/' . $this->user->id, serialize($this->metadata);); 

Puede intercambiar file_x_contents con su RDBMS - por ejemplo:

<?php 
$getMetadata = "SELECT forums FROM user_metadata WHERE user_id = $this->user->id"; 
$dbrs = mysqli_query($getMetadata); 
$this->user->metadata = unserialize($dbrs['forums']); 
$dbrs->close(); 

$metadata = serialize($this->user->metadata); 
$saveMetadata = "UPDATE user_metadata SET forums = '$metadata' WHERE user_id = '$this->user->id'"; 
mysqli_query($saveMetadata); 

Usted también puede hacer otras cosas como buscar a través de regexp, segregarlo más (tema, categoría, etc.) o cambiar el método para que se base en usuarios que leen mensajes en el foro (forum-> post-> viewedby) en lugar de publicaciones en el foro el usuario lee (usuario-> metadata-> foros). Especialmente si ya tiene un "Total de vistas" de trabajo, pero esto sería más difícil de recuperar las publicaciones que un usuario en particular ha leído o no, mientras que el otro método es inverso, o incluso usar ambos métodos en conjunción .

Cuestiones relacionadas