Con Eloquent puedes construir un sistema de calificaciones flexible y escalable sin duplicar lógica. Aquí verás cómo las relaciones polimórficas permiten que una sola tabla pivot conecte múltiples modelos, cómo estructurar la migración, el modelo Rating y dos traits reutilizables: CanRate y CanBeRated. El resultado: un único flujo para puntuar productos, páginas o categorías con pruebas que pasan.
¿Qué resuelven las relaciones polimórficas en Eloquent?
Las relaciones polimórficas permiten que un modelo pertenezca a más de un tipo de modelo. Con un ejemplo de rating, un usuario o invitado puede puntuar un producto, una página o una categoría con una sola relación. Así evitas múltiples tablas intermedias y repeticiones.
¿Cómo funciona el concepto de morph en Eloquent?
Un par de columnas define la relación: <nombre>_id y <nombre>_type.
Con morphs('ratable') y morphs('qualifier') identificas quién es calificado y quién califica.
Se usa una única tabla pivot para todos los tipos relacionados.
¿Qué roles intervienen en el rating?
Ratable: la entidad que recibe la calificación, por ejemplo, un producto.
Qualifier: la entidad que califica, por ejemplo, un usuario.
Score: el valor de la calificación almacenado en la tabla pivot.
¿Cómo se implementa el sistema de rating con morphs?
Primero se crea la migración para la tabla intermedia y luego el modelo Rating que extiende Pivot. Esto habilita timestamps, score y los tipos polimórficos.
¿Cómo crear la migración de ratings con morphs?
Ejecuta el comando: php artisan make:migration para crear la tabla.
Define id, timestamps, score y los morphs para las dos entidades.
php artisan make:model Rating: genera el modelo para la tabla intermedia.
¿Cómo usar traits para calificar y ser calificado?
Para mantener el diseño flexible, se usan traits: uno para quienes califican (CanRate) y otro para quienes son calificados (CanBeRated). Allí se centraliza la relación morphToMany, alias, timestamps, columnas pivot y filtros por tipo.
¿Cómo implementar el trait CanRate con morphToMany?
La relación ratings($model = null) arma dinámicamente la clase objetivo con get_class o getMorphClass.
Usa morphToMany con: clase relacionada, nombre de la relación, tabla ratings, qualifier_id y ratable_id.
Define alias con as('rating'), agrega withTimestamps() y columnas pivot: score y ratable_type.
Filtra por ratable_type y qualifier_type para asegurar consistencia.
Expone métodos rate($model, $score) y hasRated($model) para operar y validar no calificar dos veces.
Esta clase si me decepcionó, no tiene una buena explicación y es mucho código sin sentido.
Dejo el repositorio del proyecto con Laravel 8:
sin ánimos de ofender pero tienes razón @RetaxMaster, hay muchas veces en las que hay muchos copypaste en las que no se ha explicado todavía la función o a veces los métodos estan estructurados de formas totalmente distintas de un momento a otro y hace que la clase sea más difícil de entender de lo que realmente es... al día de hoy todavía no la entiendo del todo XD por lo que he tenido que recurrir a leer mucho mas la documentación y probar con distintos ejemplos diferentes por internet
Gracias por el aporte, si la verdad tienes razon...
Ok, voy a intentar dar mi explicación de lo que está pasando en esta clase, es importante tener en cuenta que se establecerá una relación polimorfa muchos a muchos (MaM) por lo que tienen que tener nociones de la relación MaM, para entender las relaciones polimorfa les dejó el siguiente video que encontré dentro de los aportes de esta clase y utiliza un ejemplo de relaciones polimorfas uno a muchos: relaciones polimorfas uno a muchos.
.
Primera parte - Relación a establecer
Primero que nada hay que entender que es lo que vamos a relacionar a nivel de base de datos, esto es una entidad que pueda calificar (un usuario, un invitado, una sesión, etc) con una entidad que pueda ser calificada (producto, categoría, etc.), como muchos usuarios podrían calificar muchos productos y muchos productos podrían ser calificados por muchos usuarios vemos que se forma una relación MaM, según teoría de bases de datos relacionales, esta relación se puede alcanzar mediante tres tablas - una tabla usuarios, una tabla productos y una tabla intermedia o pivote ratings.
.
Segunda parte - Migración de tabla Ratings
Esta tabla tendrá 5 columnas importantes, el score, rateable_type, rateable_id, qualifier_type y qualifier_id, los últimos cuatro pueden inferirse por las instrucciones $table->morphs('rateable') y $table->morphs('qualifier'). Así que, ¿qué significan esas columnas?, bueno si vieron el video del inicio de mi comentario espero hayan entendido que se rateable_type y qualifier_type hacen referencia al modelo que recibe calificación y al modelo que dictó dicha calificación, respectivamente - y rateable_id/qualifier_id hacen referencia a el registro especifico dentro de la tabla de cada type que recibe/dicta la calificación.
.
Tercera parte - Modelo Rating
El modelo Rating extenderá de Pivot y no de Model puesto que como ya expliqué nuestra tabla es una de tipo intermedia o pivote, no se porqué se indica el uso de campos auto-incrementables (lo siento :(), y se indica la tabla a la que nos relacionaremos. Después es como definir cualquier relación de Laravel, tenemos que indicar el nombre del método para acceder a la relación y retornar la relación polimorfa que no toma argumentos porque como puede relacionarse a varios Modelos la función MorphTo se encarga de determinarlo.
.
Cuarta parte - Previo al Trait Can Rate
Aquí es donde el titulo avanzado del curso toma sentido jeje, en un sistema diferente a este (llamemosle un sistema normal) lo que se haría sería establecer la otra parte de la relación polimorfa en los modelos específicos, por ejemplo en el caso del modelo User describiríamos la relación de la siguiente forma:
lo cual le indicaría a Laravel como establecer la relación polimorfa desde Usuario con Rating. En un sistema como el del profe (llamemoslo un sistema avanzado) quisiéramos "volverlo más flexible" citando a Sergio, por lo que podemos tomar ventaja de los Traits para delegar la responsabilidad de establecer la otra parte de la relación polimorfa a una clase en especifico y así poder darle la posibilidad a cualquier clase que queramos de poder calificar, si quieren saber más acerca de que es, como hacer y como usar un Trait les dejo el siguiente enlace: Traits.
.
Quinta parte - Trait Can Rate
Bueno, ahora que entendemos un poco la motivación de porque se usará un Trait esta parte es la que más me costó jeje,el método ratings de la clase CanRate es lo que referí como la otra parte de la relación polimorfa ya que se encargará de relacionar el modelo que le pasen por parámetro dentro de la tabla ratings usando el qualifier_id y rateable_id como llaves foráneas para después retornar los ratings (con timestamps) donde el rateable_type sea el modelo objetivo y el qualifier_type sea el modelo que invoco la relación.
Bueno, ahora ¿Cómo invocaremos la relación? con el método rate del trait CanRate, lo que hace éste método es tomar dos parámetros, modelo y calificación, el primero hará referencia que modelo se va a calificar con el puntaje que se pasa en calificación, por lo que al momento de invocar la relación ratings del Trait CanRate podemos encadenar el método attach (más información del método attach) para básicamente indicar que se escriba en la tabla pivote el id que tenga el modelo relacionado al score ya antes mencionados.
.
espero haberles ayudado y no confundido más, jeje.
Muy buen aporte, lo recomendaría como documentación necesaria para entender mejor esta clase
Excelente aporte, aunque he trabajado proyectos reales en donde el nivel de complejidad a sido facil al momento de usar relaciones polimorficas, excepto en este video.
Me has salvado.
Por más avanzado que sea un curso, a este le falta demasiada planeación, estructuración y enriquecimiento de conceptos del framework. Es importante resaltar que el profesor es bueno pero se nota que el TEAMPLATZI sacó este curso de afán.
Por mucho es más sencillo el que viene en la documentación, justo el link que compartes.
Fue interesante conocer otra forma de trabajar con este tipo de relaciones.
He hecho ya alguna vez de relaciones polimórficas de muchos a muchos y les aseguro que no es tan complejo, además, el profesor no sigue convenciones que recomienda laravel, y aunque no sea algo obligatorio es una línea que se sigue para no desorientar a muchas personas que vienen por esa línea. LA VERDAD MUY DECEPCIONANTE ESTE CURSO, EL DE API REST BASICO FUE MUCHO MAS INTERESANTE GRACIAS AL PROFESOR QUE SE ESMERÓ EN EXPLICAR DE FORMA CLARA
caramba, no esta muy clara la clase !
a este punto no sé si dejar el curso aquí e ir a tomar el de Eloquent y luego regresar … o continuar …
Solo para agregar, para los que lean este comentario. El curso de Eloquent es básico, el cual no toca este tema.
por decir lo menos, el curso de Eloquent me dejó un sinsabor... (voy a pensar que fue el formato del mismo)
La verdad es que he tenido que arreglar muchos errores, por que el profesor se salta mucho código y recurrir a repositorios de los que ya han hecho este curso para entender bien... y este tema tan enredado que me dan ganas de dejar el curso hasta aqui..
Ese me mismo pensamiento pasó por mi mente, creo que algo anda mal con esta parte del curso 🤔
que complejo me ha parecido
Tienes toda la razón, cada vez me gusta menos este curso :(
ciertamente … ahora, el modelo de ratings que el prof ha planteado para el proyecto tampoco es que es sencillo (de un posible simple M:M pasó a algo como M:M:M) 🤪 está bien completo, quizás allí reside la complejidad de la implementación … #quieroPensarQueEsPorEso 🤔
Excelente explicación! Creo que para poder entender esta clase, la audiencia debe tener conocimientos no solo de cómo usar la mágia de laravel, si no, POO y manajar muy bien las relaciones en laravel.
Muy mala Clase, empezó bien con la explicación, pero al parecer se había extendido mucho y le toco hacer copy-paste, lo malo es la falta de explicación de algunos de estos códigos.
a pesar de ser un curso Avanzado se debería de tomar el tiempo de poder explicar cada cosa que pone en el código.
Sobre el reto, > hacer que los usuarios se puedan calificar entre ellos:
El modelo user debe usar los dos traits creados:
classUserextendsAuthenticatable{ use CanRate; use CanBeRated;
y he aqui un posible test para dicha funcionalidad:
Hola, si se encuentran algo desorientados les dejo el siguiente enlace que explica con un ejemplo sencillo qué es, como se crea y como usar un Trait en Laravel:
jaja es la primera vez que veo estas relaciones polimórficas en laravel se me complica mucho, pero esta muy interesante así que terminare aprendiendo y a dominar este tema si o si
No es para nada dificil, solo en este curso es dificil...
esta clase daba para tres o cuatro videos :/ al final no esta bien explicado por querer meter todo en un solo video
El problema que veo aqui es que no sigue las convenciones de laravel
Las relaciones polimorficas permite que un modelo se relacion a varios otrso modelos
jaja nunca me habia planteado un relación polimórfica!Gran dato, gracias!!