Curso Laravel - Si no sabes como emplear el leftJoin: relaciones polimórficas opcionales 1-N
Hola a todos por aquí quería hacer rapidito un video en el cual creo que lo vas a considerar interesante si no has trabajado mucho con el join o con los leftjoin y demás ya que la mayoría de la documentación siempre se emplea el join eh obviando un poquito los demás Pero obviamente los demás también tienen cierta bueno tienen cierto papel en todo esto entonces a mí siempre he querido hacer este tipo de ejercicios pero en lo que es en el curso del Laravel básico o cualquiera de ellos como por más que sea los desarrollos que se hacen ahí son básicos para aquí la redundancia pudiera ser un desarrollo más avanzado Pero eso consumiría muchísimas horas y bueno por lo que siempre he comentado que esto a la final son cursos que tampoco compra tanta gente y realmente la competencia es un poco nula a veces no no no miro un poco más allá de crear cursos de por ejemplo de 100 horas también me parece una burrada entonces un poco todo eso entre que se haría muy largo el curso por hacer un proyecto un poco de mayor calibre o de que lo pudiera hacer un curso externo es decir otro curso paralelo al del árabe básico pero un poco lo mismo a la final es un poco más difícil de consumir porque la gente va por el del básico y usualmente un pequeño porcentaje se dirige al otro nunca termino haciendo estos desarrollos al menos a la fecha eso que esto cambia a futuro.
Este es mi proyecto de desarrollo libre que es el blog que también tiene la aplicación de Academia que poco a poco yo voy dándole más funcionalidades y por aquí quería comentarte algo interesante aquí puedes ver que es la parte de Api es decir en este caso una api que yo tengo ahí que es para que sea consumida mediante la aplicación en Vue y es para una parte de los libros que a la fecha no vendo los libros ahí los libros los vendo en la web de Amazon, LeanPub en gumRoad entre otros Apple y Google Play Google Book Apple Book y Google Book creo que lo dije bien Y ahorita también lo voy a colocar local a la plataforma y así puedo colocar precios un poco más como quien dice amigables un poquito menos por la comisión que me cobran estas plataformas y Bueno un poco de ganar para el cliente y también para mí obviamente entonces estoy trabajando un poco en esto y por aquí quería hablar para precisamente hacer esa parte del join l join Bueno un poquito más interactivo el asunto Entonces qué es esto Esta es la aplicación en vivo como te comentaba y aquí tengo el listado obviamente de ejemplo ya que est es Data de ejemplo de libros uno Bueno aquí mira es la la imagen la de la de Django y la de Livewire que tenemos acá entonces aquí puedes ver que el libro que haya adquirido por aquí aparece comprado y
aquí aparece adquirido mediante PayPal y aquí no aparece nada por lo tanto este usuario no ha comprado este libro es un poco donde vamos en todo esto Ahora te voy a mostrar un poquito Cómo es el esquema es decir qué es lo que tenemos en la a nivel de base de datos tenemos el de libro Obviamente que es para pintar la información básica del libro como la imagen el texto y todo lo demás bueno aquí tengo también otras relaciones por ejemplo con post Y eso pero esto no viene tanto al caso el importante y esto para los archivos a descargar el importante es este llamado file payment que indica si el mismo fue comprado no, Por lo tanto es una relación de tipo uno a muchos entre file payment solamente tiene un libro y los libros pueden tener muchos F payments entiéndase de que muchos usuarios pueden comprar este libro que espero que se ocurra por ejemplo entonces ahí es la relación por lo tanto esto puede estar cero o n veces y esta Va a estar siempre una relación de un a uno entonces es por esto que está la que yo considero interesante qué es lo que estamos haciendo aquí aquí yo lo que estoy haciendo es obtener el listado de todos los libros todos los libros que se encuentran publicados y es por eso que nosotros vemos por aquí bueno Select book aquí coloqué el típico Select luego Bueno te puedo explicar un poquito esto pero no viene el caso y por aquí el posted Yes es decir lo tradicional quedaría así Si le quitamos un momentico el join creo que queda bastante entendible es un poco lo normal y esto es un SELECT normal pero bueno le coloqué aquí el de RAW porque quiero darle aquí un formato a una fecha que tengo por ahí y colocarla aquí para que la pueda consumir fácil desde View no es nada raro del asunto y no es lo que yo quiero mencionar aquí el tema es del left joint como te comentaba esto es una relación que puede aparecer cero o uno veces y este es el único listado que yo tengo aquí de los libros es decir aquí puedes ver el detalle si lo quieres comprar y Bueno aquí es un pequeño plugin que tengo ahí y aquí te va a aparecer el plugin de PayPal en este caso si no has comprado el libro para que puedas comprarlo y este Sería bueno aquí no coloqué la parte de descargas porque es archivo de pruebas y no he subido los fields entonces aquí te aparecerían los botones para descargar el archivo pero aquí puedes ver que el comportamiento es distinto porque aquí otra vez te aparecerían los enlaces para descargarlo eso es un condicional que hice mediante Vue otra vez no viene tanto el caso pero lo que quería que entendieras es que por aquí estamos pasando la Data de Fill payment que es donde vamos con todo esto Entonces qué pasaría si yo aquí empleo un join en vez de un left join tal cual estamos haciendo voy a comentar todo esto porque aquí está la respuesta de todo porque obviamente está funcionando pero quiero que vayamos a ir viendo poco a poco el ejercicio si que colocamos el joint que es el que siempre empleamos el 99.99 por de los casos al menos en el curso qué es lo que pasaría en este caso:
Book
::select('books.*')
->join('file_payments', 'books.id', '=', 'file_payments.file_paymentable_id')
->where('posted', 'yes')
->get()
Bueno vamos a verlo en la práctica si venimos acá vas a ver que solamente te trae un libro por qué te trae un bendito libro por el tipo de relación los joins son excelentes si la relación Existe en este caso la de file payment que es la que estamos comentando Pero recuerda que es esa relación solamente va a existir si el usuario compra el libro si no lo compra no existe por lo tanto esto es un condicional tiene que existir el libro obviamente porque es la relación principal y tiene que existir el File payment.
Si el file payment no existe una Bueno si no existe esta sería simplemente no la trae y con esto tampoco nos trae la relación principal que sería la del libro cosa que no es lo que yo quiero porque otra vez yo aquí quiero mostrar todos los libros independientemente si lo ha comprado en la plataforma o no lo ha comprado en la plataforma por lo tanto esta es la desventaja que tenemos aquí en el join Y en este caso se emplean o podemos emplear el resto de los join que son el join el left join el right join y otros variantes yo más que todo trabajé con el left join porque el right join realmente nunca lo empleado pero es lo inverso a lo que te voy a explicar ahorita del left join qué demonios hace el left join vamos a comentar esto y voy a de comentarlo por aquí lo voy a dejar de esta forma:
Book::select('books.*')
->leftjoin('file_payments', 'books.id', '=', 'file_payments.file_paymentable_id')
->where('posted', 'yes')
->get()
Regresamos acá y mira que ahora ya aparece ambos tanto el que compré como el que no compré Entonces eso es lo que precisamente hace es lo que está indicando es esta relación como opcional la de la dependencia es la file payment la relación secundaria se pudiera decir ya que la principal sería aquí la de book obviamente Entonces aunque esta relación no exista él va a traer la relación principal y es por eso que por aquí no puedo acceder a los datos de pago y es por eso que aquí no aparece ninguna de esta información que es la que estamos preguntando por aquí ya que para pintar esto estoy preguntando es por la relación de tipo file payment que es la que no está trayendo ahorita porque no existe entonces Te pudieras preguntar Bueno pero aquí ya ya funciona el ejercicio todo perfecto Pues no porque a la final estamos preguntando por un File payment que está asociado obviamente un usuario el usuario que lo compró y es por eso que aquí ves este montón de de condiciones que tengo aquí cosa que yo no puedo colocar aquí a las fuerzas claro lo pudiera colocar por aquí abajo por ejemplo aquí indicar para que me traiga el file payment en base a esta relación e bueno otra vez me traiga el book con el File payment que también el File payment user ID corresponde al usuario autenticado que es lo que estoy colocando por aquí y esto bueno Esto es es una relación de tipo polimórfica que maneja aquí entonces más me divertido la cosa entonces lo que pasaría es que no traería el otro por qué no trae el otro:
Book::select('books.*')
->leftjoin('file_payments', 'books.id', '=', 'file_payments.file_paymentable_id')
->where('posted', 'yes')
->where('file_payments.user_id', auth()->user()->id)
->where("file_paymentable_type", Book::class)
->get()
Fíjate que solamente está trayendo el que yo compré no trae el otro porque esta es una relación de fuerza aquí estoy colocando otra vez como si fuera un join en la práctica porque al indicar estas estos filtros que tenemos acá estoy indicando recuerda el orden en el cual se ejecuta todo esto y lo pudiste ver primero está haciendo la conexión con el join perfecto pero esto actúa como una especie de filtro una especie de filtro una vez realizado esta operación por lo tanto él me va a filtrar y aquí la redundancia todas todos los libros con su relación de File payments que no cumplan esta condición porque si esto no existe que no va a existir en la que el usuario no ha comprado Entonces no lo va a traer porque el que está aquí justamente Antes de antes de hacer el get es decir otra vez primero se realiza la conexión traemos el libro traemos la relación y luego de eso que tenemos los dos registros en este caso es que se aplicaría estas condiciones por lo tanto una de ellas la que no ha comprado el usuario no tiene la relación de File payment es decir sería nula y automáticamente no trae nada y es por eso que solamente vemos una en la práctica para nosotros para este ejercicio en particular ojo muy importante está funcionando como si fuera un join entonces aquí puedes ir viéndole un un poquito el chiste todo esto como te digo esto Me cuesta hacerlo en el curso Porque no tenemos una relación así tan compleja y bueno puedes ver que la práctica funciona así claro aquí varía un poquito depende un poco la Data que tengas y demás Pero eso es lo que está pasando entonces tú dices pues nada Entonces vamos a ir un poco a lo burro y vamos a indicar que nos traiga ya sea que el payment user ID sea el de este usuario o que sea nulo y aquí por eso es que coloco la de or null en este caso Recuerda que estamos colocando como un callback Y esto es para que en la consulta aquí tengamos cualquier cosa en el we we Boot igual a un aquí colocamos un ant que sería cuando colocamos aquí los we y por aquí colocamos estos paréntesis para que primero se ejecute la relación las condiciones que tenemos aquí adentro y evitemos así tener aquí Otra condición y aquí or y Otra condición y no y no sabemos qué es lo que va a devolver siempre es mejor colocar aquí los paréntesis para colocar como quien dice lo que tiene que cumplir la relación en este caso sería el user ID igual a un o que sea nulo en lo que estamos indicando aquí el user ID es más o menos lo que estoy colocando acá y aquí lo mismo pero con el tipo entonces voy a quitar
Esto vamos a ver qué pasa vuelvo acá recargo y creo que murió para ver por qué murió porque murió porque murió ah no estoy colocando aquí la relación el join o join:
Where y where or
Y mira que funciona otra vez que perfecto buenísimo Entonces cuál es el problema ahora cuál es el problema que se me olvidó Ah ya creo que me acordé del problema e déjame aquí Buscar la base de datos que no sé dónde el la tengo derecho em para ver para ver para ver msql sql esto obviamente es un usuario autenticado por aquí lo puedes ver en sería el usuario uno creo que tengo dos al menos aquí okay Tengo estos dos usuarios y aquí tenemos el de Bueno aquí puedes ver un numerito uno y dos yo estoy trabajando con el usuario uno que sería el que yo coloque aquí admin vamos a ir a la relación de file payment si la encuentro aquí está y…
Relación polimorfica
En caso de que te preguntes la llame así no directamente Boot porque precisamente ahorita con el tema de los cursos yo coloqué los cursos Que obviamente ya tengo toda esta cuestión de pagos y ahorita quise hacer la de libros pero la de los cursos la llamé aquí directamente para los Bueno lo llamé tutoriales como equivalente entonces la relación directamente a los cursos y Qué pasa cuando quiero hacer la de libros tuviera que copiar y pegar todo y Qué pasa si luego Quiero vender no sea cositas en Blender entonces tengo que copiar y pegar y hacer todas esas relaciones otra vez Cuándo puedo aprovechar aquí las relaciones polimórficas tal cual has visto hasta este punto y simplemente con las mismas le voy variando Cuál es la cuál es la clase modelo porque las al final la estructura de la compra es exactamente lo mismo tenemos un recurso que queremos comprar que es una relación. Aparte ya sea books ya sea cursos ya sea Blender ya sea no sea animalitos lo que tú quieras y una relación de tipo F payment donde se encuentra la relación de pago entiendas el identificador del usuario entiendas el Cuál es el método de pago Que de momento es PayPal pero luego voy a colocar también la de stripe ya que la del bendito eh Cómo se llama aquí la de MercadoLibre que se utiliza mucho para acá Bueno está bloqueado para Venezuela Entonces no no puedo abrirme una cuenta entonces al demonio el en ID el precio y todo lo demás es lo mismo independientemente de lo que quieras comprar entonces es por eso que preferí hacer una para una relación de tipo polimórfica y es por eso que ves aquí que utilizo aquí la de book ya que al la final se Tiene ciertas cositas diferentes porque el tratamiento de un curso es diferente al tratamiento de un libro y tengo que crear aquí el recurso bueno específico eso era por si te lo preguntas.
Bueno aquí tenemos la relación y fíjate que es el usuario uno tal cual puedes ver voy a colocar el usuario 2 que es el que tiene en este caso que te lo preguntes eso por aquí lo cambié creo que lo cambió a ver si actualizó file payments Aquí está regreso acá y no no lo trae creo que esta también serviría Pero había algo ahora no me acuerdo qué era Ah precisamente porque no lo trae ese es el problema Es decir esto sería peor que que la solución anterior suponte que todo el bueno que que espero que suceda Así que varios usuarios me compren varios cursos digo varios libros Entonces ya directamente no aparezcan es decir…
Cuando venga un usuario nuevo venga a ver aquí los libros ya no va a aparecer ninguno porque si este libro también lo hubiera comprado a otro usuario de momento puedes ver que no lo ha comprado lo que me refiero en la data de prueba solamente tenemos un f payment que es el del libro uno el el de dango y es por eso que no aparece porque ahora Estamos preguntando Fíjate lo que estamos haciendo aquí es preguntando si hay un fail payment para mí para el usuario uno no lo hay porque lo cambié para el usuario dos por dar un ejemplo o que es nulo ninguna de estas se cumple por lo tanto ya no lo trae entonces peor todavía porque ni siquiera estamos listando un libro que otra vez recuerdas que esto es para que el usuario lo compre pero si no lo estoy listando Porque alguien lo compró no tiene sentido para mí Entonces tampoco funciona entonces a la final como puedes concluir hacer estos filtros en este nivel no tiene sentido a lo mejor pudiéramos colocar otro we pero ya estás viendo que esto se está yendo al demonio simplemente para esto y a la final tú dices Oye mejor traigo todos los libros en otra consulta los pagos de los libros y hago un un match que es una ladilla hacer eso mediante el for en Vue entonces puedes ver que esto no tiene sentido entonces aquí tú te pudieras considerar no es mejor que pueda colocar esos filtros directamente en el join que es justamente donde tenemos que colocarlos ya que si lo colocamos en este nivel por cuarta vez creo que lo he comentado lo que hace es trae la relación principal trae la relación secundaria si existe y luego aplicamos estos filtros sobre toda esa Data que ya tenemos y es ahí el problema justamente Esto entonces es por eso que aquí tampoco esto se debería de emplear para este caso en particular y deberíamos de emplearla por aquí que era lo que tenía aquí originalmente voy a comentar esto y voy a descomentar lo por acá qué es lo que estamos haciendo acá Aquí sí estamos trayendo otra vez es lo mismo que tenemos aquí es similar al we solo que en este caso aplicado left joint en la cual estamos colocando un closure y por aquí estamos colocando lo que es la la primera relación que es preguntar por el Book ID que no te lo expliqué antes aquí también la tenemos es lo mismo el Book ID por el no sé cómo pronunciar esto ya lo siento pero este Recuerda que es la el campo de la relación polimórfica Ese fue el nombre que le coloqué no sé si está bien pero bueno creo quei sigue la sintaxis pero ya se fue el demonio esto tiene que coincidir por lo comentado antes porque así funciona una relación polimórfica en la cual colocamos un campo eh de tipo entero para representar la lo que sería la fk en una relación de tipo uno a muchos en este caso pero en este caso como quien dice polimórfica y de ahí el nombre Porque puede ser cualquier cosa en este caso Solamente le estoy empleando para el book y es por eso que pregunto tanto aquí por el tipo que sea la del tipo Bot Class que Recuerda que es esta cosita que se guarda aquí es esto aquí El Fill payment aquí aparecería el modelo y aquí aparecería el identificador de ese recurso en particular es decir esto sería el libro porque es los que estamos colocando aquí con identificador de uno qué es lo que yo tengo por acá entonces aquí pero la final es preguntar por el el si si fuera una relación normal es decir no polimórficas ahí estuviéramos colocando el Book ID se igual a File el Book ID igual al file payment book ID pero otra vez todo esto es empleando relaciones polimórficas.
Condiciones mediante el closure del leftjoin
Aquí quitaríamos Esto entonces si lo hacemos de esta forma el filtro lo estamos haciendo es localmente en el join para la relación de tipo file payment y no estamos afectando la principal que sería la de book que si estamos afectando con estos en este nivel entonces aquí sí podemos colocar los que nos venga en gana aquí colocamos como te digo lo que es el la conexión inicial mediante join Bueno sería solamente esto y por aquí todos los filtros adicionales que amos colocar que es el file payment user ID que corresponde al usuario autenticado y aquí lo comentar Bueno este para que sea más organizado pudiera colocarlo aquí arriba as si se entiende mejor aquí esto y a la final esta otra cosita aquí que si el usuario ha devuelto el libro pero bueno realmente para esto no hace nada porque no no no hace nada no lo tengo implementado pero está ahí Entonces ahora sí puedes ver Qué falla y ya todo el mundo feliz:
Book::select('books.*')
->leftJoin('file_payments', function ($leftJoin) {
$leftJoin
->on('books.id', 'file_payments.file_paymentable_id')
->where("file_paymentable_type", Book::class)
->where('file_payments.user_id', auth()->user()->id)
->where('file_payments.unenroll');
})
->where('posted', 'yes')
->get()
Aquí me comí el punto y coma y aquí puedes ver que si funciona y aquí ahora para ver qué pasó con mi Data diablos Ah claro verdad que la cambié disculpa Es que uno uno mismo se enreda recuerda que ahorita ese usuario no ha comprado nada pero aquí aparecen los dos y por lo tanto si vuelvo a asignar el de file payment al usuario uno que es el que tengo aquí autenticado por aquí va a aparecer la información de pago Así que finalmente por los dioses pude hacer esta conexión en la cual simplemente quería obtener todo el listado de los libros en este caso que yo tengo publicados eso S tiene que conservarse aquí obviamente porque los libros tienen que estar publicados si no están publicados Entonces no lo voy a colocar a la venta pero lo que es el detalle de lo que es la relación secundaria hay que manejarlo que es el la moraleja de todo esto las condiciones de la de la relación secundaria que en este caso es esta si tienes si tienes condiciones como estas la tenemos que manejar es localmente al join y no la podemos colocar de manera global a lo que sería la consulta y ya vimos un ejemplo de por qué esto varios ejemplos de por qué esto así que era un poco lo que te quería comentar por acá y también el uso del left joint que tal cual pudiste ver aquí no podemos colocar el joint porque si no aquí estamos colocando esto a fuerzas que si no cumple esto Entonces no va a devolver nada y con eso nos mata el book también cosa que no queremos y es por eso que empleamos el f join en caso de que te preguntes Y qué demonios hace el right join bueno justamente lo contrario si el libro no existe en este caso y aquí tenemos por casualidad la vida algún pago cosa que no lo podemos hacer por el tipo de relación ahorita pero suponte que aquí Tenemos aquí yo nada más tengo dos libros y un pago suponte que yo tengo aquí un libro que es digo un pago que es para el libro 3 que no existe Entonces eso también nos los traería al listado por lo tanto lo que hace es lo inverso si por si este lo que hace es devolver la relación principal independientemente si tiene una relación secundaria o no el right join lo que hace es devolver las la relación secundaria independientemente de si tenemos la relación principal yo no lo he utilizado realmente pero bueno existe ahí en caso de que sea necesario según el modelo de datos que estés trabajando tu lógica de negocio que es lo importante eh te puede ser útil pero realmente yo creo que más primero join luego left join y ya ahi sería el resto que realmente no no lo he utilizado mucho en mi vida entonces bueno se me alargó un poquito más el video de la cuenta pero espero que te haya resultado provechoso este ejercicio así que pues nada nos vemos en otro video.
- Andrés Cruz
Desarrollo con Laravel, Django, Flask, CodeIgniter, HTML5, CSS3, MySQL, JavaScript, Vue, Android, iOS, Flutter