Evitar guardar en un bucle en acción masiva

13

He creado mi propio módulo CRUD que contiene una acción de edición en línea similar a la de las páginas CMS.
Todo funciona bien, pero cuando ejecuto phpsniffer con el estándar EcgM2 recibo esta advertencia:

Modelo LSD método save () detectado en bucle

¿Cómo puedo evitar esto?
Nota: La misma advertencia aparece si "olfateo" el archivo principal vinculado anteriormente.
Aquí está mi executemétodo en caso de que alguien lo necesite. Pero es muy similar al del controlador de página CMS

public function execute()
{
    /** @var \Magento\Framework\Controller\Result\Json $resultJson */
    $resultJson = $this->jsonFactory->create();
    $error = false;
    $messages = [];

    $postItems = $this->getRequest()->getParam('items', []);
    if (!($this->getRequest()->getParam('isAjax') && count($postItems))) {
        return $resultJson->setData([
            'messages' => [__('Please correct the data sent.')],
            'error' => true,
        ]);
    }

    foreach (array_keys($postItems) as $authorId) {
        /** @var \Sample\News\Model\Author $author */
        $author = $this->authorRepository->getById((int)$authorId);
        try {
            $authorData = $this->filterData($postItems[$authorId]);
            $this->dataObjectHelper->populateWithArray($author, $authorData , AuthorInterface::class);
            $this->authorRepository->save($author);
        } catch (LocalizedException $e) {
            $messages[] = $this->getErrorWithAuthorId($author, $e->getMessage());
            $error = true;
        } catch (\RuntimeException $e) {
            $messages[] = $this->getErrorWithAuthorId($author, $e->getMessage());
            $error = true;
        } catch (\Exception $e) {
            $messages[] = $this->getErrorWithAuthorId(
                $author,
                __('Something went wrong while saving the author.')
            );
            $error = true;
        }
    }

    return $resultJson->setData([
        'messages' => $messages,
        'error' => $error
    ]);
}
Marius
fuente

Respuestas:

5

En ese caso, debe hacerlo con save()sus entidades, por lo que definitivamente tendrá que llamar a ese método.

El archivo nativo de Magento que vinculó no es el único que hace eso, especialmente las clases de acción de acciones masivas.

La única alternativa es agregar un saveAttributemétodo a su modelo de recursos CRUD basado en el implementado en app/code/Magento/Sales/Model/ResourceModel/Attribute.php:

public function saveAttribute(AbstractModel $object, $attribute)
{
    if ($attribute instanceof AbstractAttribute) {
        $attributes = $attribute->getAttributeCode();
    } elseif (is_string($attribute)) {
        $attributes = [$attribute];
    } else {
        $attributes = $attribute;
    }
    if (is_array($attributes) && !empty($attributes)) {
        $this->getConnection()->beginTransaction();
        $data = array_intersect_key($object->getData(), array_flip($attributes));
        try {
            $this->_beforeSaveAttribute($object, $attributes);
            if ($object->getId() && !empty($data)) {
                $this->getConnection()->update(
                    $object->getResource()->getMainTable(),
                    $data,
                    [$object->getResource()->getIdFieldName() . '= ?' => (int)$object->getId()]
                );
                $object->addData($data);
            }
            $this->_afterSaveAttribute($object, $attributes);
            $this->getConnection()->commit();
        } catch (\Exception $e) {
            $this->getConnection()->rollBack();
            throw $e;
        }
    }
    return $this;
}

De esta manera, en lugar de llamar a lo siguiente:

$this->authorRepository->save($author);

Deberías poder hacer algo como esto:

$author->getResource()->saveAttribute($author, array_keys($authorData));

Como se indica en los comentarios, tendrá que modificar ese método un poco si no necesita verificar la AbstractAttributeinstancia para que coincida con sus necesidades

Raphael en Digital Pianism
fuente
Costuras razonables. Gracias. Lo intentaré y volveré con los resultados.
Marius
@Marius solo tenga en cuenta que este método es ligeramente diferente del saveAttributemétodo EAV , ya que acepta una serie de "códigos de atributos" para guardar en lugar de un solo código de atributo
Raphael en Digital Pianism el
1
Me he dado cuenta de eso. Incluso lo modifiqué un poco para que no acepte una instancia AbstractAttributecomo parámetro, porque no lo necesito en mi entidad plana. Funciona sin problemas. Gracias de nuevo.
Marius