En este tutorial crearemos un componente de carga de imágenes de VueJS para que los usuarios puedan cargar una imagen para usarla como avatar en la aplicación. El objetivo es recrear el mecanismo de carga de una imagen a través de un formulario html, sin embargo, todo se hará en un componente de Vue. Esto permitirá la actualización de la imagen en tiempo real en el navegador, además de almacenar la imagen y configurar la ruta de la imagen del avatar en la base de datos de una sola vez. Hay mucho que cubrir, así que vamos directamente a subir una imagen al servidor usando VueJS.


Preparar la base de datos

Al cargar una imagen, normalmente almacena la imagen en algún tipo de medio de almacenamiento, como los sistemas de archivos locales, Amazon S3 o incluso Rackspace Cloud Storage. Con respecto a la base de datos, es la ruta a la imagen que suele almacenar allí. En otras palabras, una representación en cadena de cómo llegar a la imagen. Para nuestros propósitos, agregaremos una columna a la tabla de usuarios llamada avatar_path. Para hacer esto, crearemos y ejecutaremos esta migración.

vagrant @ homestead: ~ / Code / forumio $ php artisan make: migración add_avatar_path_to_users_table --table = users

vagrant @ homestead: ~ / Code / forumio $ php migrar artesanal
Migrando: 2018_02_27_193627_add_avatar_path_to_users_table
Migrado: 2018_02_27_193627_add_avatar_path_to_users_table

Las migraciones son flexibles de esta manera. Podemos configurar un archivo de migración para simplemente agregar una columna sin la necesidad de revertir el esquema y los datos existentes en la base de datos. Si miramos la tabla de usuarios, aquí vemos lo que necesitamos. Una nueva columna donde podemos almacenar la ruta del archivo de imagen que comienza con un valor nulo.
add_avatar_path_to_users_table


Un usuario puede cargar una prueba de avatar

Ahora lo que haremos es crear una clase de prueba de AddAvatarTest y el primer método de prueba será test_a_user_may_add_an_avatar_to_their_profile ().

  • Dado que tenemos un usuario registrado
  • Dado que tenemos un disco para almacenar (falso)
  • Cuando enviamos una solicitud de publicación json a la API
  • Entonces la ruta del archivo debe coincidir con el avatar_path del usuario
  • Entonces el disco debe contener esa ruta de archivo

Ahora podemos empezar a trabajar en la prueba para ver qué tenemos que hacer para que pase.

vagrant @ homestead: ~ / Code / forumio $ phpunit --filter test_a_user_may_add_an_avatar_to_their_profile
PHPUnit 6.5.5 por Sebastian Bergmann y colaboradores.

E 1/1 (100%)

Tiempo: 1,36 segundos, memoria: 10,00 MB

Hubo 1 error:

1) Pruebas \ Característica \ AddAvatarTest :: test_a_user_may_add_an_avatar_to_their_profile
Symfony \ Component \ HttpKernel \ Exception \ NotFoundHttpException: POST http: // localhost / api / users / 1 / avatar

La excepción NotFoundHttpException significa que nos falta una ruta. Bien, podemos agregar una nueva ruta para admitir la carga de archivos en nuestro archivo de rutas web.php. Agregue esto al final de ese archivo. Es una solicitud de publicación al espacio de nombres api que tiene un comodín de usuario que hace referencia a una clase UserAvatarController con un método de store () que tiene un middleware de autenticación y una ruta con nombre de 'avatar'. Jajaja Lo siento, sigue la sentencia.

El primer error se solucionó, ejecutemos la prueba para ver qué sigue.

vagrant @ homestead: ~ / Code / forumio $ phpunit --filter test_a_user_may_add_an_avatar_to_their_profile
PHPUnit 6.5.5 por Sebastian Bergmann y colaboradores.

E 1/1 (100%)

Tiempo: 1,23 segundos, memoria: 10,00 MB

Hubo 1 error:

1) Pruebas \ Característica \ AddAvatarTest :: test_a_user_may_add_an_avatar_to_their_profile
ReflectionException: Class App \ Http \ Controllers \ Api \ UserAvatarController no existe

Eso suena bien. Tenemos una ReflectionException que indica que la clase UserAvatarController no existe. ¡Vamos a crearlo!

vagrant @ homestead: ~ / Code / forumio $ php artisan make: controller Api / UserAvatarController
Controlador creado con éxito.

Eso debería solucionar el error número 2, veamos qué sigue.

vagrant @ homestead: ~ / Code / forumio $ phpunit --filter test_a_user_may_add_an_avatar_to_their_profile
PHPUnit 6.5.5 por Sebastian Bergmann y colaboradores.

E 1/1 (100%)

Tiempo: 894 ms, memoria: 10,00 MB

Hubo 1 error:

1) Pruebas \ Característica \ AddAvatarTest :: test_a_user_may_add_an_avatar_to_their_profile
BadMethodCallException: el método [store] no existe en [App \ Http \ Controllers \ Api \ UserAvatarController].

Ahora vemos que nos falta el método store () en ese controlador. Dejamos que los resultados de la prueba nos guíen en cada paso siguiente. Podemos agregar ese método ahora. El método de almacenamiento también necesitará realizar algún trabajo. Así que pensemos en lo que queremos que haga. Bueno, en primer lugar, debemos validar que el usuario haya proporcionado una imagen en la solicitud. A continuación, vamos a hacer uso de una política que crearemos en un momento para determinar si el usuario tiene los permisos para subir esta imagen. Por último, configuraremos avatar_path para que se almacene en el directorio público de avatares. Así que agreguemos este código así.

Ejecutemos la prueba y veamos qué sucede.

vagrant @ homestead: ~ / Code / forumio $ phpunit --filter test_a_user_may_add_an_avatar_to_their_profile
PHPUnit 6.5.5 por Sebastian Bergmann y colaboradores.

F 1/1 (100%)

Tiempo: 1,44 segundos, memoria: 10,00 MB

Hubo 1 falla:

1) Pruebas \ Característica \ AddAvatarTest :: test_a_user_may_add_an_avatar_to_their_profile
Error al afirmar que nulo coincide con el 'http: //localhost/avatars/ntyWkGe7Xvph8dxNZXPQe8HgEELzgZHW3G4B5BFe.jpeg'.

/home/vagrant/Code/forumio/tests/Feature/AddAvatarTest.php:41

¡FALLOS!
Pruebas: 1, afirmaciones: 1, fallos: 1.

Bueno, esto es interesante. Parece que el archivo en sí se está almacenando, pero la ruta del objeto de usuario es nula. Bien, probablemente necesitemos permitir que esa columna se llene. Es probable que el manejo masivo de excepciones proteja eso ahora mismo. Entonces, en el modelo User.php podemos agregar.

Ok, ¡nos vemos bien ahora!
test_a_user_may_add_an_avatar_to_their_profile ahora está pasando


Crear una política de usuario

Usaremos un objeto de política para establecer permisos para que los usuarios actualicen su avatar. Por supuesto, no queremos que alguien pueda actualizar la imagen de avatar de un usuario diferente, por lo que tener una política de usuario asegurará que esta base esté cubierta.

vagrant @ homestead: ~ / Code / forumio $ php artisan make: policy UserPolicy
Política creada con éxito.

La regla aquí es simplemente que la identificación del usuario que inició sesión coincide con la del usuario que se actualiza. Si coinciden, entonces es la misma persona y estamos listos para comenzar.

Cada vez que crea una nueva política, deberá registrarla en AuthServiceProvider para que entre en vigencia.

Ahora, con una política de usuario, podremos mostrar de forma selectiva un área de carga solo para los usuarios que tengan permisos para verla. Ahora, antes de avanzar demasiado, agreguemos solo un par de pruebas más a la clase AddAvatarTest. Esto garantizará que solo los miembros puedan cargar una imagen de avatar y que se debe proporcionar una imagen válida.

Este conjunto de pruebas está pasando, así que estamos bien.
Aprobación de la suite AddAvatarTest


Vinculación del directorio de almacenamiento al directorio público

Antes de comenzar a construir la interfaz, sabemos que vamos a necesitar tener acceso a las imágenes en el directorio público. Pero espera, Laravel almacena imágenes en el directorio de almacenamiento. ¿Asi que que hacemos? ¡Creamos un enlace simbólico!

Esto es lo que hace:

vagrant @ homestead: ~ / Code / forumio $ php almacenamiento de ayuda artesanal: enlace
Uso:
  almacenamiento: enlace
Ayuda:
  Cree un enlace simbólico de "público / almacenamiento" a "almacenamiento / aplicación / público"

Ahora podemos ejecutarlo.

vagrant @ homestead: ~ / Code / forumio $ php almacenamiento artesanal: enlace

En Filesystem.php línea 228:

  symlink (): operación no admitida

¡Ups! No se preocupe, esto se debe a que Windows es el sistema operativo host en mi caso. Al igual que en este tutorial de envío de formularios, tendremos que crear manualmente el enlace simbólico en el sistema operativo host.

C: \> mklink / DC: \ localdev \ forumio \ public \ storage C: \ localdev \ forumio \ storage \ app \ public
enlace simbólico creado para C: \ localdev \ forumio \ public \ storage << === >> C: \ localdev \ forumio \ storage \ app \ public

Establecer un avatar predeterminado

Cuando un usuario se registra por primera vez para obtener una cuenta, es posible que no tenga ganas de cargar una imagen de avatar. En ese caso, deberíamos proporcionar una imagen predeterminada para que el diseño se vea coherente. Podemos agregar esta función al modelo User.php. Obtiene el avatar de imagen de los usuarios, y si no está presente, usará el predeterminado.


El cargador de imágenes de VueJs

Ahora podemos comenzar a abordar la parte frontal y construir el componente para cargar una imagen como avatar. De hecho, haremos esto en dos pasos. Primero crearemos el componente ImageUpload.vue.
Componente ImageUpload de vuejs
El componente tendrá el siguiente marcado.

La segunda parte del cargador de imágenes de Vue será el componente AvatarForm.vue.
componente de formulario de avatar de vuejs


Registrar el componente Vue

Podemos registrar el componente AvatarForm.vue usando la línea resaltada a continuación en app.js.


Establecer una imagen predeterminada

Para hacer referencia a una imagen predeterminada, necesitamos almacenar una en el servidor. Podemos colocar un archivo default.png en public / images / avatars como este.
imagen de avatar predeterminada


Mostrando un avatar

En el archivo threads / show.blade.php ahora podemos hacer referencia al avatar como se ve aquí.

¡Luciendo bastante bien!
avatar ahora se muestra en el archivo de vista


Adición del cargador de imágenes a la página de perfiles

Finalmente, ingresaremos al archivo de vista profiles / show.blade.php y agregaremos el componente <avatar-form> Vue. Esto debería permitirnos seleccionar fácilmente una imagen y hacer que persista en el servidor mientras actualizamos la imagen del avatar instantáneamente en la interfaz de usuario.

Ahora iniciamos sesión como Tom y visitamos su página de perfil. Podemos hacer clic en el botón elegir archivo y ver la actualización del avatar de la imagen en tiempo real. Lo bueno es que no solo se actualizó en tiempo real en el navegador, la imagen también se almacenó en el almacenamiento además de la ruta del archivo que se almacenó en la base de datos. Esto significa que cuando se vuelve a cargar la página, la imagen persistirá.
ejemplo de carga de imagen de vue js


Cómo funciona el componente de carga de imágenes de VueJs

No hablamos mucho sobre cómo funciona el código dentro de los componentes de Vue, así que repasemos cómo funciona.

El usuario elige una imagen que provoca que se active el changeevento. Esto da como resultado onChangeque se llame a la función.

Dentro del onChangemétodo, primero verificamos si se ha proporcionado un archivo. Si no, simplemente regresamos.

Si se seleccionó un archivo, lo colocaremos en la filevariable

Luego, el objeto Lector de archivos de Javascript se utiliza para leer el contenido del archivo proporcionado. Específicamente, el método readAsDataURL () se usa para determinar la representación de la imagen del archivo en una cadena codificada en base64. A continuación, se establece como fuente de la imagen, que es lo que permite que la imagen se actualice instantáneamente en el navegador.

En este punto loaded, se activa un evento que AvatarForm.vue escuchará.

Ahora, en AvatarForm.vue, el loadedevento se detecta y activa el onLoadmétodo.

El onLoadmétodo establece la fuente del avatar para la actualización de la imagen en tiempo real y luego almacena la ruta del archivo en la base de datos.

El persistmétodo hace uso de la interfaz FormData de Javascript para crear un conjunto de pares clave / valor que representan los campos del formulario y sus valores, que luego se envían como una solicitud de publicación al punto final del servidor que habíamos configurado usando axios.


Resumen de carga de imágenes de VueJS

Eso resume bastante bien cómo funciona el ciclo de vida de la carga de una imagen de avatar en VueJs. Este tutorial nos hizo crear la API de back-end en Laravel para admitir el almacenamiento de una imagen en el servidor, así como el uso de VueJs en conjunto con los objetos Javascript FileReader y FormData para crear un componente de carga de imágenes elegante que se procesa en tiempo real y al mismo tiempo persiste en la base de datos.