Problème d'utilisation de «avoir» dans la collection Magento


20

J'essaie de créer une collection personnalisée pour une grille dans le module d'administration Magento. J'ai créé une nouvelle méthode de collecte appelée "addAttributeHaving" qui fait juste ce qui suit:

public function addAttributeHaving($value)
{
    $this->getSelect()->having($value);
    return $this;
}

Voir le code de collection:

$collection->addFieldToSelect(
    array(
        'entity_id',
        'created_at',
        'increment_id',
        'customer_email',
        'customer_firstname',
        'customer_lastname',
        'grand_total',
        'status'
    )
);

$collection->getSelect()->joinLeft(array('sfop' => 'sales_flat_order_payment'), 'main_table.entity_id = sfop.parent_id', 'sfop.amount_authorized');
$collection->getSelect()->columns('sum(sfop.amount_authorized) AS AUTHD');
$collection->getSelect()->columns('grand_total - sum(sfop.amount_authorized) AS DIF_AU');
$collection->addFieldToFilter('main_table.state', array('in' => array('new','payment_review')));
$collection->addFieldToFilter('main_table.sd_order_type', array('neq' => 7));
$collection->addFieldToFilter('sfop.method', array('neq' => 'giftcard'));
$collection->addFieldToFilter('main_table.created_at', array('gt' => $this->getFilterDate()));
$collection->getSelect()->group(array('main_table.entity_id'));
$collection->addAttributeHaving('DIF_AU <> 0');
$collection->load(true,true);

$this->setCollection($collection);

Cela produit le SQL suivant qui s'exécute parfaitement et produit les résultats attendus lorsqu'il est exécuté en dehors de Magento.

[METHOD=Varien_Data_Collection_Db->printLogQuery] SELECT `main_table`.`entity_id`, `main_table`.`entity_id`, `main_table`.`created_at`, `main_table`.`increment_id`, `main_table`.`customer_email`, `main_table`.`customer_firstname`, `main_table`.`customer_lastname`, `main_table`.`grand_total`, `main_table`.`status`, `sfop`.`amount_authorized`, sum(sfop.amount_authorized) AS `AUTHD`, grand_total - sum(sfop.amount_authorized) AS `DIF_AU` FROM `sales_flat_order` AS `main_table` LEFT JOIN `sales_flat_order_payment` AS `sfop` ON main_table.entity_id = sfop.parent_id WHERE (main_table.state in ('new', 'payment_review')) AND (main_table.sd_order_type != 7) AND (sfop.method != 'giftcard') AND (main_table.created_at > '2013-04-07') GROUP BY `main_table`.`entity_id` HAVING (DIF_AU <> 0)

Cependant, lorsque j'essaie de charger la grille dans Magento, j'obtiens l'erreur suivante:

SQLSTATE [42S22]: Colonne introuvable: 1054 Colonne inconnue 'DIF_AU' dans 'clause d'avoir'

De plus, si je supprime la clause having (qui casse mes résultats), je peux utiliser la colonne DIF_AU pour une source de données dans la grille.


1
MISE À JOUR: J'ai pu retrouver le problème jusqu'à la méthode parent getSelectCountSql (). C'est en réalité là que le problème se produit lorsque vous essayez d'obtenir le nombre de collectes.
Anthony Leach Jr

1
Postez une réponse! De qui sd_order_typevient-il?
benmarks

1
Des trucs de type de commande personnalisé top secret qui ont été ajoutés aux tables plates. Je travaille toujours sur la réponse.
Anthony Leach Jr

1
"Les utilisateurs ayant moins de 10 points de réputation ne peuvent pas répondre à leur propre question pendant 8 heures après avoir posé la question. Vous pouvez répondre en 7 heures. D'ici là, veuillez utiliser des commentaires ou modifier votre question à la place." (solution à venir dans 7 heures).
Anthony Leach Jr

1
Quelqu'un donne un vote
positif à

Réponses:


12

Je vais effectivement répondre à ma propre question ici. Je sais, collant, mais je suis tombé sur la réponse en regardant de plus près la trace réelle de la pile. La collection se charge bien cependant, l'échec survient un peu plus tard lors de l'exécution lorsque nous essayons d'obtenir le nombre de collections dans Varien_Data_Collection_Db :: getSelectCountSql () . Le SQL qui en résulte est:

SELECT COUNT(*) FROM sales_flat_order AS main_table LEFT JOIN sales_flat_order_payment AS sfop ON main_table.entity_id = sfop.parent_id WHERE (main_table.state in ('payment_review')) AND (main_table.sd_order_type != 7) AND (sfop.method != 'giftcard') AND (main_table.created_at > '2013-04-07') GROUP BY main_table.entity_id HAVING (DIF_AU <> 0)

Vous remarquerez que l'instruction HAVING est jointe, mais nous n'avons plus de définition pour la colonne DIF_AU. Il semble que j'aurai besoin d'étendre un getSelectCountSql () personnalisé dans ma classe de collection pour obtenir le bon nombre d'enregistrements.

J'ai créé un getSelectCountSql () étendu dans la classe de collection personnalisée qui s'ajoute dans la colonne manquante requise pour l'instruction having.


public function getSelectCountSql()
  {
    $countSelect = parent::getSelectCountSql();
    $countSelect->columns('grand_total - sum(sfop.amount_authorized) AS DIF_AU');
    $countSelect->reset(Zend_Db_Select::GROUP);
    return $countSelect;
  }

1
Pas collant du tout… si vous trouvez d'abord la solution, c'est encouragé. D'autres trouveront cela utile sur la route. +1 :)
davidalger

Vous devez déposer un rapport de bug! magentocommerce.com/bug-tracking
benmarks

C'est un problème que j'ai également vu, et bien fait pour trouver une réponse. Cependant, je ne pense pas que votre solution soit correcte - car vous utilisez group by, votre SelectCountSql doit renvoyer le nombre de groupes. Vous avez donc besoin soit d'un compte (fetchAll ()), soit de réécrire votre requête en utilisant count(distinct main_table.entity_id)au lieu decount(*)
Benubird

Je pense que vous avez très probablement raison. Ce projet a été mis en veilleuse depuis cette publication et y revient tout juste. Dans une démo la semaine dernière, j'ai remarqué que le nombre d'enregistrements incorrect était signalé dans la grille. Rendra compte de mes découvertes une fois que je les aurai résolues.
Anthony Leach Jr

@AnthonyLeachJr des nouvelles de vos découvertes?
Simon

0

Tout d'abord $countSelect->reset(Zend_Db_Select::HAVING);, cela signifie qu'il sera réinitialisé à HAVINGpartir de votre collection. Cela signifie qu'il supprimera la clause having. Et ce n'est pas ce que vous voulez. Vous pouvez l'ajouter à la collection ( app/code/core/Mage/Catalog/Model/Resource/Product/Collection.php->_getSelectCountSql()ici.)

Mais le principal coupable c'est la getSize()méthode qui existe en lib/Varien/Data/Collection/Db.phpdossier.

J'ai essayé la solution ci-dessus mentionnée par @Anthony mais cela n'a pas fonctionné.

Maintenant, je l'ai fait ci-dessous.

public function getSize()
{
    if (is_null($this->_totalRecords)) {
        //$sql = $this->getSelectCountSql();
        $sql = $this->getSelect();
        $this->_totalRecords = count($this->getConnection()->fetchAll($sql, $this->_bindParams));
    }
    return intval($this->_totalRecords);
}

Vérifiez que je n'utilise même pas le getSelectCountSql(). Je suis en train de lire l'intégralité de SQL QUERY et de récupérer toutes les données et d'en renvoyer le nombre . C'est tout.


0

J'ai résolu ce problème ici: app / code / core / Mage / Catalogue / Model / Resource / Product / Collection.php: 943 ajoutez ceci: $ select-> reset (Zend_Db_Select :: HAVING);

Copiez simplement app / code / core / Mage / Catalogue / Model / Resource / Product / Collection.php dans app / code / local / Mage / Catalog / Model / Resource / Product / Collection.php

Mon code ressemble maintenant à ceci:

/**
 * Build clear select
 *
 * @param Varien_Db_Select $select
 * @return Varien_Db_Select
 */
protected function _buildClearSelect($select = null)
{
    if (is_null($select)) {
        $select = clone $this->getSelect();
    }
    $select->reset(Zend_Db_Select::ORDER);
    $select->reset(Zend_Db_Select::LIMIT_COUNT);
    $select->reset(Zend_Db_Select::LIMIT_OFFSET);
    $select->reset(Zend_Db_Select::COLUMNS);
    $select->reset(Zend_Db_Select::HAVING);

0

Cette solution fonctionnera si votre sélection a des noms de colonnes uniques car toutes les colonnes de la liste de sélection de sous-requête doivent avoir des noms uniques

Sous-requête: la sous-requête de table autorise les noms de colonne en double

public function getSelectCountSql()
{
    $this->_renderFilters();
    $select = clone $this->getSelect();
    $select->reset(Zend_Db_Select::ORDER);
    $select->reset(Zend_Db_Select::LIMIT_COUNT);
    $select->reset(Zend_Db_Select::LIMIT_OFFSET);        

    $countSelect = clone $this->getSelect();
    $countSelect->reset();
    $countSelect->from(array('a' => $select), 'COUNT(*)');
    return $countSelect;
}

PS: Cette réponse concerne les collections générales de magento. ne concerne pas uniquement la collection de produits.


0

Cela fonctionne

fonction publique getSize () {if (is_null ($ this -> _ totalRecords)) {// $ sql = $ this-> getSelectCountSql (); $ sql = $ this-> getSelect (); $ this -> _ totalRecords = count ($ this-> getConnection () -> fetchAll ($ sql, $ this -> _ bindParams)); } return intval ($ this -> _ totalRecords); }

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.