Cómo utilizar symplify/vendor-patches en proyectos php?
Tags: php, webdev
Published: 2021-04-30 13:59:03


Es posible que alguna vez hayan encontrado un bug en una dependencia de un proyecto de php que utiliza composer, y el arreglo es simple y lo único que se requiere es cambiar 1 o 2 líneas de código en el paquete referenciado es decir en `/vendor/usuario/paquete-con-error`.

Como buen ciudadano del mundo open source, lo primero que se debe hacer es abrir un issue y crear un pull request con los cambios en el proyecto dependencia para que el dueño lo pueda aceptar y se arregle para todos los usuarios de ese paquete, pero no vamos a negar que este proceso toma bastante tiempo, y si necesitamos arreglar lo más pronto hay otras opciones.

Puedes crear un fork del proyecto en tu github y usar ese url de github en la version de composer.json, pero estarías tomando una responsabilidad manual de actualizar y aplicar el cambio cada vez que haya actualizaciones. Se puede copiar el paquete localmente que es más rápido pero con esto ya no hay actualizaciones.

O la mejor opción se puede usar "composer patches".

Hace un tiempo estaba trabajando en un proyecto laravel con el paquete de administración nova, y un addon para manejo de archivos `infinety-es/nova-filemanager` el paquete funcionaba muy bien con archivos públicos, pero para mi proyecto necesitaba guardar los archivos en un bucket privado de S3 y para descargarlos debía generar una url temporal con un tiempo de expiración máximo.

Analizando el código del paquete encontré 2 lugares donde se generaba la url del archivo para descarga en el archivo fuente `src/Http/Services/NormalizeFile.php` en la función [toArray](https://github.com/InfinetyEs/Nova-Filemanager/blob/master/src/Http/Services/NormalizeFile.php#L53) y en la función [getImage](https://github.com/InfinetyEs/Nova-Filemanager/blob/master/src/Http/Services/NormalizeFile.php#L148) lo único que había que hacer es realizar el siguiente cambio:

```diff
--- /dev/null
+++ ../src/Http/Services/NormalizeFile.php
@@ -50,7 +50,7 @@
             'mime' => $this->getCorrectMimeFileType(),
             'path' => $this->storagePath,
             'size' => $this->getFileSize(),
-            'url'  => $this->cleanSlashes($this->storage->url($this->storagePath)),
+            'url'  => $this->cleanSlashes($this->storage->temporaryUrl($this->storagePath, '+5 minutes')),
             'date' => $this->modificationDate(),
             'ext'  => $this->file->getExtension(),
         ]);
@@ -145,7 +145,7 @@
     private function getImage($mime, $extension = false)
     {
         if (Str::contains($mime, 'image') || $extension == 'svg') {
-            return $this->storage->url($this->storagePath);
+            return $this->storage->temporaryUrl($this->storagePath, '+5 minutes');
         }

         $fileType = new FileTypesImages();
```

## Cómo se cambia esas 2 líneas en /vendor?

Se hace en 4 simples pasos:

1. Instalar el paquete que controla los parches

```
composer require cweagans/composer-patches symplify/vendor-patches --dev
```

2. Se crea una copia del archivo a cambiar en /vendor por la extensión `.old`

Por ejemplo en mi caso cambie `vendor/infinety-es/nova-filemanager/src/Http/Services/NormalizeFile.php` a
`vendor/infinety-es/nova-filemanager/src/Http/Services/NormalizeFile.php.old`

3. Abrir el archivo original `vendor/infinety-es/nova-filemanager/src/Http/Services/NormalizeFile.php` y realizar los cambios necesarios. Se verifica que los cambios funcionen ya que solo el archivo `*.php` funciona no el `*.php.old`.

4. Generar el parche usando el comando:

```
vendor/bin/vendor-patches generate
```

La herramienta de symplify genera todos los parches en el directorio `/patches/`:

```
ls -l patches
.rw-r--r-- 883 marcelo 30 Apr  7:16 infinety-es-nova-filemanager-src-http-services-normalizefile-php.patch
```

Y también genera la configuración de parches al composer.json:

```
    ...
    "extra": {
        "laravel": [],
        "patches": {
            "infinety-es/nova-filemanager": [
                "patches/infinety-es-nova-filemanager-src-http-services-normalizefile-php.patch"
            ]
        }
    },
    ...
```

Y eso es todo, la siguiente vez que realicen `composer install`, el parche se aplica automáticamente.

Referencias: 

- [How to Patch a Package in Vendor, Yet Allow its Updates | Tomas Votruba](https://tomasvotruba.com/blog/2020/07/02/how-to-patch-package-in-vendor-yet-allow-its-updates/)