Éviter de sauvegarder dans une boucle en action de masse

13

J'ai créé mon propre module CRUD qui contient une action d'édition en ligne similaire à celle des pages CMS
Tout fonctionne bien, mais lorsque je lance phpsniffer avec la norme EcgM2, j'obtiens cet avertissement:

La méthode modèle LSD save () détectée en boucle

Comment puis-je éviter ça?
Remarque: le même avertissement apparaît si je "renifle" le fichier principal lié ci-dessus.
Voici ma executeméthode au cas où quelqu'un en aurait besoin. Mais il est très similaire à celui du contrôleur de page 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
la source

Réponses:

5

Dans ce cas, vous devez accéder à save()vos entités, vous devrez donc certainement appeler cette méthode.

Le fichier natif Magento de base que vous avez lié n'est pas le seul à le faire, en particulier les classes d'actions d'actions de masse.

La seule alternative consiste à ajouter une saveAttributeméthode à votre modèle de ressource CRUD basée sur celle implémentée dans 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 cette façon, au lieu d'appeler ce qui suit:

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

Vous devriez pouvoir faire quelque chose comme ceci:

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

Comme indiqué dans les commentaires, vous devrez modifier un peu cette méthode si vous n'avez pas besoin de vérifier l' AbstractAttributeinstance pour répondre à vos besoins

Raphael chez Digital Pianism
la source
Coutures raisonnables. Merci. Je vais essayer et je reviendrai avec les résultats.
Marius
@Marius gardez juste à l'esprit que cette méthode est légèrement différente de la saveAttributeméthode EAV car elle accepte un tableau de "codes d'attribut" à enregistrer au lieu d'un seul code d'attribut
Raphael au Digital Pianism
1
Je l'ai remarqué. Je l'ai même un peu modifié pour qu'il n'accepte pas et comme instance de AbstractAttributeparamètre, car je n'en ai pas besoin dans mon entité plate. Cela fonctionne bien. Merci encore.
Marius