Magento 2 es una forma más rápida de cambiar las entradas de la galería de medios del producto mediante programación

8

Necesito hacer una actualización masiva de los datos del producto, pero lo que necesito hacer no se puede lograr con la importación del producto. Por ejemplo, necesito actualizar la galería de medios y las categorías para productos dados, pero la solución que obtuve lleva demasiado tiempo.

Una pequeña recapitulación: agregué un comando a la CLI de Magento 2 que, dado un archivo de configuración json, elimina, agrega, actualiza u ordena las entradas de la galería multimedia para un producto como este. Aquí pego un extracto del código:

/* $product is of type Magento\Catalog\Model\Product */

//get existing media gallery
$existingMediaGallery = $product->getMediaGallery();

/* 
   do stuff with media gallery (alter $existingMediaGallery)
   (add, remove, sort, ...)
*/

//set media gallery again
$product->setMediaGallery($existingMediaGallery);

//process media gallery
$mediaGalleryEntries = $product->getMediaGalleryEntries();
$this->getMediaGalleryProcessor()->clearMediaAttribute($product, array_keys($product->getMediaAttributes()));
if ($mediaGalleryEntries) {
  foreach ($mediaGalleryEntries as $k => $entry) {
    if (!isset($entry['removed']) && !empty($entry['types'])) {
      $this->getMediaGalleryProcessor()->setMediaAttribute($product, $entry['types'], $entry['file']);
    }
  }
}

//save product
$product->save();

Como se trata de una actualización masiva, la línea "$ product-> save ()" se llama muchas veces y siempre lleva de 2 a 4 segundos. Como necesito lanzar el código para miles de productos, necesito una forma más rápida de hacerlo.

Lo intenté con

$product->getResource()->saveAttribute($product, 'media_gallery');

y

$product->addAttributeUpdate('media_gallery', $mediaGallery, $storeId);

pero eso no funciona para la galería de medios (solo funciona para cada creo).

¿Hay alguna manera de guardar solo la galería de medios y persistir estos cambios más rápido?

(Lo que busco es algo así como un Magento\Catalog\Api\CategoryLinkManagementInterface::assignProductToCategoriesmétodo que guarda la asociación de categoría / producto más rápido que un producto completo guardado)

CaNNaDaRk
fuente

Respuestas:

0

Creo que está en el camino correcto: el producto de guardado está tardando mucho y necesita irse.

Ahora, con la actualización de imágenes, eso puede ser realmente complicado. Pero me gustaría pensar que puede ser una forma de separar el problema:

  • Supongo que necesita que los datos multimedia se almacenen en la base de datos y eso se puede hacer utilizando su método saveAttribute ... (muy rápido). Sin embargo, es posible que desee agregar algunos atributos en su script de actualización: vea los atributos 'imagen, small_image, thumbnail' (vea en la base de datos select * from eav_attribute where ((attribute_code like '%image%') or (attribute_code='thumbnail')) and entity_type_id=4))

  • ahora lo más complejo, pero aún puedo tener algunas ideas, es tratar la imagen físicamente hablando y los posibles datos de medios adicionales (título de la etiqueta de imagen, posición, etc.)

-> para este segundo punto: miraría la clase Magento \ Catálogo \ Modelo \ Producto \ Galería \ CreateHandler, ya que le mostrará cómo Magento mantiene todo funcionando con respecto a los datos multimedia.

Herve Tribouilloy
fuente
0

Hasta donde sé, no hay una manera de guardar entradas de medios sin guardar el producto. pero guardar el producto no debería llevar mucho tiempo con el productRepositoryInterface.

Creé un módulo similar y no tengo el mismo problema con guardar medios.

Aquí está mi solución para guardar medios:

 /**
     * Add Product media from folder.
     * @param $product
     * @param $productData
     * @return mixed
     */
    protected function setProductMedia($product, $productData)
    {
        $medias = [];
        $files = scandir(self::MEDIA_PATH);
        $mediaPath = '';
        foreach ($files as $file) {
            if ($file !== '.' && $file !== '..') {
                $path = realpath(self::MEDIA_PATH . $file);
                if ($path) {
                    if (basename($path, '.jpg') == trim($productData['productCode'])) {
                        $mediaPath = self::MEDIA_PATH . $file;
                        break;
                    }
                }
            }
        }

        if ((bool)$mediaPath) {
            $image = $this->_imageContent
               ->setBase64EncodedData(base64_encode(file_get_contents($mediaPath)))
               ->setType(image_type_to_mime_type(exif_imagetype($mediaPath)))
               ->setName(basename($mediaPath));

            $media = $this->_productAttributeMediaGalleryEntry
               ->setFile($mediaPath)
               ->setTypes(['thumbnail', 'small_image', 'image'])
               ->setLabel($productData['description'])
               ->setPosition(0)
               ->setMediaType('image')
               ->setContent($image)
               ->setDisabled(false)
               ->setPosition(0);

            $medias[] = $media;
            $product->setMediaGalleryEntries($medias);
       }

        return $product;
    }

Luego guardo el producto con productRepositoryInterface.

   try {
        $product = $this->_productRepository->get($productData['productCode']);
    } catch (NoSuchEntityException $e) {
        throw new NoSuchEntityException(__('Could Not Update Product Error: %1', $e->getMessage()));
    }

    $product = $this->setProductMedia($product, $productData);

    try {
       $this->_productRepository->save($product);
    } catch (InputException $exception) {
       $this->_logger->critical(__("Could not save product Error: %1", $exception->getMessage()));
    } catch (StateException $exception) {
       $this->_logger->critical(__("Could not save product, Error: %1",$exception->getMessage()));
    } catch (CouldNotSaveException $exception) {
       $this->_logger->critical(__('Could Not Save Product Error: %1' ,$exception->getMessage()));
    }

Se ahorra bastante rápido. Puedo ejecutar 10,000 productos en unos minutos. Eso incluye la búsqueda de los medios que se denominan como {sku} .jpg y se guardan en una sola carpeta.

djfordz
fuente
¿es posible establecer roles de imagen, es decir, -> setTypes (['thumbnail', 'small_image', 'image']) sin reemplazar toda la imagen?
paj