posts/ujLEIxCoB2wSNa8EWwDvW7OqPgUlGAYg6R7qOS7T.png

Funcionalidad de Favoritos ("Me gusta") en Laravel con overtrue/laravel-favorite

Agregar una característica de "Favoritos" o "Me gusta" permite a los usuarios marcar contenido que les interesa, mejorando la interacción en tu aplicación (piensa en marcar posts favoritos, productos deseados, etc.). Implementar esto desde cero implica manejar relaciones polimórficas complejas, pero el paquete overtrue/laravel-favorite lo ofrece ya hecho. Este paquete utiliza una relación polimórfica para que cualquier modelo (Post, Producto, Comentario, etc.) pueda ser marcado como favorito por los usuarios. Aquí explicamos cómo integrarlo en Laravel, cómo obtener conteos y verificaciones, y buenas prácticas de rendimiento (incluyendo uso opcional de caché).

Instalación y Configuración del Paquete

  1. Instalación: Ejecuta en tu proyecto:

    composer require overtrue/laravel-favorite
    

    Esto añadirá el paquete de favoritos.

  2. Publicar configuración y migraciones: El paquete incluye migraciones para la tabla de favoritos y posiblemente un archivo de config. Publica con:

    php artisan vendor:publish --provider="Overtrue\LaravelFavorite\FavoriteServiceProvider"
    

    Esto creará la migración (por ejemplo,

    create_favorites_table
    ) en tu proyecto. Revisa el archivo de migración para entender la estructura: típicamente contiene campos
    user_id
    (quién marca),
    favoriteable_id
    y
    favoriteable_type
    (el modelo marcado), timestamps, y quizás índices para eficiencia.

  3. Migrar la base de datos: Corre

    php artisan migrate
    . Se creará la tabla
    favorites
    (u nombre similar definido por el paquete) para almacenar cada "favorito" como una relación entre un usuario y un modelo (favoriteable).

Implementación de la Relación Polimórfica en Modelos

Overtrue/laravel-favorite funciona mediante traits que habilitan funcionalidad en tus modelos:

  • En tu modelo User (o aquel que represente al que marca favoritos), usa el trait

    Favoriter
    :

    use Overtrue\LaravelFavorite\Traits\Favoriter;
    
    class User extends Authenticatable {
        use Favoriter;
        // ...
    }
    

    Al usar

    Favoriter
    , el usuario obtiene métodos para marcar y desmarcar favoritos, así como relaciones con sus favoritos.

  • En cada modelo que pueda ser marcado como favorito (ej: Post, Video, Producto), usa el trait

    Favoriteable
    :

    use Overtrue\LaravelFavorite\Traits\Favoriteable;
    
    class Post extends Model {
        use Favoriteable;
        // ...
    }
    

    Esto permite que ese modelo "reciba" favoritos de usuarios, añadiendo la relación polimórfica correspondiente.

Tras esto, User podrá marcar favoritos y Post conocer qué usuarios lo han marcado, sin pasos adicionales.

Marcar y Desmarcar Favoritos (API del Paquete)

El paquete ofrece métodos muy simples para la acción de "favorito":

  • Marcar como favorito:

    $user->favorite($post);
    

    Esto crea un registro de favorito donde el usuario (p.ej. ID 1) marca el post (ID 2). Si el favorito ya existía, no duplica (generalmente la tabla tiene clave única compuesta).

  • Remover favorito:

    $user->unfavorite($post);
    

    Elimina el favorito existente. Úsalo, por ejemplo, cuando el usuario hace clic de nuevo para quitar de favoritos.

  • Toggle (alternar):

    $user->toggleFavorite($post);
    

    Marca o desmarca automáticamente: si el $post no estaba en favoritos del usuario, lo agrega; si ya lo estaba, lo quita. Útil para implementaciones de botón tipo "thumbs-up" que alternan.

Estas operaciones funcionan con cualquier modelo que use

Favoriteable
, gracias a la relación polimórfica. Internamente, el método sabe qué IDs usar y en qué tabla guardar.

Consultar Favoritos: Conteos y Verificaciones

Una vez tenemos usuarios marcando elementos, necesitaremos:

  • Verificar si un usuario marcó X como favorito: El trait provee:

    $user->hasFavorited($post);
    

    Retorna

    true
    /
    false
    según el usuario haya marcado ese $post. Inversamente, también puedes preguntarle al objeto:

    $post->hasBeenFavoritedBy($user);
    

    que es equivalente (útil quizá por legibilidad en ciertas circunstancias).

  • Obtener todos los favoritos de un usuario:

    $user->favorites();        // relación hasMany polimórfica (Favorite model)
    $user->getFavoriteItems(Post::class);
    

    El método

    getFavoriteItems(Model::class)
    devuelve un query builder con todos los modelos de ese tipo que el usuario ha marcado . Por ejemplo,
    $user->getFavoriteItems(Post::class)->get()
    te da una colección de Posts favoritos del usuario. Puedes incluso paginar o agregar condiciones a ese query (p.ej., filtrar favoritos por categoría). Si no especificas clase,
    favorites()
    te da la relación general, que puedes filtrar con
    ->withType(Model::class)
    .

  • Listar usuarios que marcaron un objeto: Desde el lado del modelo favorito:

    $post->favoriters;              // colección de User que lo marcaron
    $post->favoriters()->count();   // número de usuarios que lo han marcado
    

    favoriters()
    es la relación muchos a muchos polimórfica inversa. Un loop
    foreach($post->favoriters as $user)
    permitiría iterar por los usuarios fans de ese post.

  • Conteos rápidos con withCount: Laravel permite agregar conteos de relaciones fácilmente. Por ejemplo, para obtener una lista de posts con el número de veces que han sido marcados, puedes hacer:

    $posts = Post::withCount('favoriters')->get();
    foreach($posts as $post) {
        echo $post->favoriters_count;
    }
    

    Esto añade el atributo

    favoriters_count
    a cada Post. Similarmente,
    User::withCount('favorites')->get()
    daría cuántos favoritos ha hecho cada usuario (atributo
    favorites_count
    ).

El paquete también incluye un método útil para adornar colecciones con la información de si el usuario actual las ha marcado:

$user->attachFavoriteStatus($posts);

Si

$posts
es, por ejemplo, una colección de 10 Post, tras llamar a attachFavoriteStatus cada Post tendrá un atributo extra
has_favorited
true/false según ese $user los tenga en favoritos. Esto es genial para, por ejemplo, al listar artículos en una vista, saber cuáles mostrar con el ícono de corazón lleno o vacío sin consultas adicionales.
attachFavoriteStatus
funciona con colecciones, paginadores e incluso arreglos de modelos.

Performance y Caching: Buenas Prácticas

Cuando se manejan favoritos, especialmente en gran volumen, considera:

  • Eager Loading para evitar N+1: Si vas a comprobar en masa si ciertos posts son favoritos de un usuario (o viceversa), carga la relación de favoritos por adelantado. Ejemplo:

    // En lugar de loop con hasFavorited que consulta cada vez...
    $posts = Post::with('favoriters')->get();
    foreach($posts as $post) {
        $post->isFavoritedBy($user);
    }
    

    Aquí usamos

    with('favoriters')
    para cargar todos los favoriters de cada post en 2 queries (uno para posts, otro para favoriters relacionados) en lugar de 1 por post. De igual modo,
    User::with('favorites.favoriteable')->get()
    podría precargar todos los modelos marcados por cada usuario, si necesitaras esa info. La idea es utilizar las relaciones provistas en lugar de llamar
    hasFavorited
    en bucle sin carga previa (lo cual haría una consulta por iteración). Overtrue destaca esta técnica en su documentación para evitar problemas de rendimiento.

  • Índices en BD: Asegúrate de que la tabla de favoritos tenga índices adecuados en

    user_id
    y la combinación
    favoriteable_type, favoriteable_id
    . Generalmente la migración ya los incluye. Esto hará que contar o buscar por esas columnas sea rápido. Por ejemplo, el conteo de favoriters de un post (
    favoriters()->count()
    ) internamente hace un
    WHERE favoriteable_type='Post' AND favoriteable_id=...
    que con índices será eficiente.

  • Caching de conteos: Si anticipas altísima frecuencia de lectura de, digamos, el número de favoritos de un objeto (ej. mostrando "1000 users liked this" en muchos lugares), podrías implementar caching. Opciones: usar el propio

    withCount
    en consultas (Laravel puede cachear queries si configuras la caché de base de datos) o mantener un campo denormalizado
    favorites_count
    en la tabla del modelo y actualizarlo mediante eventos. De hecho, podrías escuchar los eventos
    Favorited
    y
    Unfavorited
    que el paquete emite para, por ejemplo, actualizar un contador en la tabla Post o invalidar una entrada en Redis que lleve el conteo. Esto es opcional y añade complejidad, recomendable solo si el conteo de favoritos se vuelve un cuello de botella comprobado.

  • Expirar caché al modificar: Si optas por cachear (por ejemplo, guardar en caché la lista de IDs favoritos de un usuario), recuerda siempre invalidar o actualizar la caché cuando un usuario agregue o quite un favorito. El paquete en sí no usa caché interna para favoritos, así que cualquier caching sería implementado por ti a nivel de aplicación.

En la mayoría de aplicaciones, simplemente usando las relaciones provistas y asegurando índices, overtrue/laravel-favorite funcionará eficientemente. Este paquete te ahorra construir la relación polimórfica manualmente y manejar la lógica de favoritos. Con él, añadir "me gusta" o favoritos es tan sencillo como usar unos cuantos métodos, y tienes acceso inmediato a consultas útiles (conteos, listas) sin escribir SQL personalizado.

En resumen, overtrue/laravel-favorite ofrece una solución elegante para incorporar funcionalidad de favoritos en Laravel. Aplica las buenas prácticas mencionadas (carga anticipada, índices, eventos para actualizaciones masivas si aplica) y podrás escalar esta característica manteniendo un rendimiento óptimo incluso con muchos usuarios y muchos favoritos registrados. ¡Tus usuarios apreciarán poder marcar sus contenidos preferidos y tú tendrás una implementación mantenible y limpia!

Share:

0 comentarios

Dejar un comentario