Différence entre getSize () et count () sur la collection

82

J'ai entendu à plusieurs reprises que les deux sont les mêmes. Mais je suis confronté à un problème étrange: dans la collection de produits du module CatalogSearch, count () renvoie le nombre de produits correct, tandis que getSize () renvoie zéro.

Donc, fondamentalement, voici ce que je reçois:

$collection->count(); //correct count
$collection->getSize(); //0

Mais je veux que getSize () ait un compte correct, car il décide si la pagination et les produits doivent être affichés dans la page de recherche ou non. J'utilise les conditions de jointure interne, de jointure gauche et où uniquement dans la collection pour être plus spécifique.

Des idées pourquoi je reçois ce problème étrange?

Merci

MISE À JOUR:

Ma question précédente, Comment cloner la collection dans Magento? Je voulais effectuer deux opérations différentes sur une collection. La première collection affiche getSize () correct, mais si getSize () vaut zéro, j'ai supprimé la clause WHERE et créé une nouvelle condition WHERE. Après cela, j'obtiens le code SQL brut correct auquel je m'attendais, et son exécution dans MySQL fournit également un ensemble correct d'enregistrements, mais seul getSize () sur la collection donne un décompte nul.

Donc, fondamentalement, il se peut que je doive recharger la collection, car getSize () utilise l’ancien compte. Logique?

MagExt
la source

Réponses:

84

La plupart (sinon la totalité) des collections s’étendent Varien_Data_Collection_Db. Voici les 2 méthodes de cette classe

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

public function count() //inherited from Varien_Data_Collection
{
    $this->load();
    return count($this->_items);
}

Il existe une différence. Pour getSize()la collection n'est pas chargé. Car count()c'est. Habituellement, les modèles de collection utilisent la même getSize()méthode que ci-dessus et ne remplacent que getSelectCountSql().
Dans getSelectCountSql()la limite est réinitialisé afin d'obtenir le nombre total d'enregistrements disponibles pour les filtres définis ( whereinstruction). Voyez comment les getSelectCountSql()travaux

public function getSelectCountSql()
{
    $this->_renderFilters();
    $countSelect = clone $this->getSelect();
    $countSelect->reset(Zend_Db_Select::ORDER);
    $countSelect->reset(Zend_Db_Select::LIMIT_COUNT);
    $countSelect->reset(Zend_Db_Select::LIMIT_OFFSET);
    $countSelect->reset(Zend_Db_Select::COLUMNS);
    $countSelect->columns('COUNT(*)');
    return $countSelect;
} 
Marius
la source
3
Génial! Alors, quelle devrait être ma prochaine étape pour recharger la collection afin qu’elle soit correcte getSize()? Merci!
MagExt
Honnêtement, je ne sais pas pourquoi vous obtenez ce résultat. Dans le CatalogSearchmodule, rien ne remplace getSize()ou getSelectCountSql(). Cela devrait fonctionner par défaut, sauf si vous avez ajouté du code personnalisé. Pouvez-vous publier la façon dont vous construisez la collection?
Marius
mis à jour la question.
MagExt
3
Il n'y a aucun moyen de réinitialiser _totalRecords. Vous pouvez essayer de cloner la collection avant d'appeler getSize()la collection d'origine. Peut-être que ça va marcher.
Marius
vous pouvez aussi faire quelque chose comme ça pour avoir un "reset":$sql = $collection->getSelectCountSql(); return $collection->getConnection()->fetchOne($sql);
koosa
14

Faites attention. C'est correct, mais les méthodes sont écrasées Varien_Data_Collection_Dbcomme décrit par Marius.

Il suffit de regarder dans

// \Varien_Data_Collection::getSize
public function getSize()
{
    $this->load();
    if (is_null($this->_totalRecords)) {
        $this->_totalRecords = count($this->getItems());
    }
    return intval($this->_totalRecords);
}

// \Varien_Data_Collection::count
public function count()
{
    $this->load();
    return count($this->_items);
}

Donc, il devrait être le même à ce niveau bas. Les deux méthodes chargent la collection et comptent les éléments.

MISE À JOUR

Oh, je vois un problème: getSize () met en cache les _totalRecords, cela signifie qu’il n’est pas recalculé. Vérifiez où _totalRecordsest situé?

Fabian Blechschmidt
la source
Oui, je l'ai regardé, mais je ne peux pas comprendre pourquoi les deux génèrent des comptes différents pour la même collection? Des idées sur la façon de recharger une collection ou quelque chose pour obtenir un décompte correct getSize()?
MagExt
a mis à jour l'entrée
Fabian Blechschmidt
1
getSize()ne charge pas la collection pour les enregistrements provenant de la base de données. Non, sauf si vous substituez la méthode et lui dites de charger la collection.
Marius
_totalRecords est protégé, donc je ne peux pas l'appeler dans mon fichier personnalisé avec collection. echo count($collection->load()->getItems());donne le compte correct, mais encore une fois je veux getSize()travailler.
MagExt
5

Cette réponse apparaît dans Google pour "magento getSize false" et des recherches similaires. J'aimerais donc ajouter un scénario qui pourrait être utile à quelqu'un.

Lorsque vous avez une déclaration de groupe dans votre requête et que vous effectuez une

SELECT COUNT(DISTINCT e.entity_id) ... GROUP BY ( at_id_art.value )

Mysql retournera un compte pour CHAQUE des groupes, donc Varien_Data_Collection_Db :: getSize () retournera la mauvaise réponse, car cette fonction extrait la première ligne:

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

Quand il peuplera

$this->_totalRecords = $this->getConnection()->fetchOne($sql, $this->_bindParams);

Il sélectionne la première ligne et renvoie donc le total du premier groupe comme taille totale.

J'ai fini par trouver ce code à compter, basé sur les valeurs uniques des attributs de ma requête.

$select = clone $collection->getSelect();
$group = $select->getPart(Zend_Db_Select::GROUP);
$select->reset(Zend_Db_Select::GROUP)->reset(Zend_Db_Select::COLUMNS)->columns("COUNT(DISTINCT {$group[0]})");
$totalCount = $collection->getConnection()->fetchOne($select);
changeling
la source
2

Juste au cas où vous vous retrouveriez ici, voici une autre solution simple à essayer:

System -> Index Management

et sélectionnez-les tous (même s’ils indiquent «Vert, pas de réindexation nécessaire» et forcez-les à se réindexer.

Cela a résolu mon getSize()problème vide , ce qui a permis aux demandes de base de données spéciales et nouvelles de trouver les produits, de remplir les conditions du "si" et de les rendre correctement.

BVRoc
la source
0

Quand count($collection)était différent de $collection->getSize()ce que j'avais aux reindexproduits, alors tout a bien fonctionné.

Zsolti
la source
-1

Il y a une différence principale pour getSize (), la collection de produits n'est pas chargée. Pour count (), la collection de produits entière sera chargée. Donc, pour les gros catalogues, il n'est pas conseillé d'utiliser la fonction de comptage dans une collection.

Nayan Baraiya
la source
Déjà dit dans Marius post ...
sv3n