Rejoindre à gauche une table sur une requête de collection


27

Je fais ce qui suit pour retirer certaines commandes du système pour l'exportation:

$orders = Mage::getModel('sales/order')->getCollection()
    ->addFieldToFilter('status', $statusToExport)
    ->addFieldToFilter('store_id', $this->processingStoreId)
    ->addFieldToFilter('updated_at', array('gteq' => date('Y-m-d H:i:s', $lastSyncTime)));

J'ai besoin d'ajouter quelque chose là où il n'exporte pas si la commande entity_idest dans une table personnalisée que j'ai. Si j'utilisais SQL, je ferais:

left join myTable as mt on main_table.entity_id = mt.entity_id
where mt.entity_id is null

Mais je ne sais pas comment modifier la requête de collection pour faire une chose similaire.

Remarque: j'ai essayé

$orders = $orders->getSelect()
    ->joinLeft(
        array("t1" => $myTable),
        "main_table.entity_id = t1.entity_id",
        array("admin_field_id" => "t1.id")
    )
    ->where("t1.id is null")

mais cela le change donc c'est une requête et je veux que la collection de vente / commande soit retournée.

Je sens que je manque quelque chose de simple ...

MODIFIER

Ok, j'ai essayé ceci:

$orders->getSelect()
    ->joinLeft(
        array("t1" => $myTable),
        "main_table.entity_id = t1.entity_id",
        array("admin_field_id" => "t1.id")
    )
    ->where("t1.id is null");

Lorsque je fais écho, (string)$orders->getSelect()il renvoie la requête à laquelle je m'attendais et ne renvoie aucun résultat lorsque je l'exécute. $orderscependant, contient toujours des éléments. Je pensais que cette jointure était destinée à modifier la collection à ce stade?

Réponses:


53

Pour modifier la requête, vous pouvez le faire

$collection->getSelect()->doWhateverYouWantWithSelectObject();
foreach($collection as $order) {} // order collection

Mais pour rejoindre une table, vous pouvez simplement utiliser $collection->joinTable()

joinTablen'existe que sur Mage_Eav_Model_Entity_Collection, cela signifie: produits, catégories, commandes, factures, creditmemo, expédition, clients. (Merci @Fra pour le commentaire)

joinTable ()

Mais les collections magento ont une méthode joinTable()qui m'a pris 45 minutes pour comprendre comment il est utilisé. Pour éviter cela pour vous, je le partage.

$productCollection->joinTable(
    array('bonus' => 'mycompany/bonus'), 'product_id=entity_id',
    array('bonus_id' => 'bonus_id')
);

Les paramètres sont:

public function joinTable($table, $bind, $fields = null, $cond = null, $joinType = 'inner')
  1. Le tableau est simple, c'est le namespace/entityformat magento , que vous utilisez dans votre configuration, les modèles de ressources et la collection. Vous pouvez utiliser un tableau du formatarray('alias' => 'namespace/entity')
  2. Bind signifie, l'instruction ON dans votre SQL. C'était la partie la plus difficile et je l'expliquerai en détail plus tard. Il est important d'avoir votre table plate AVANT et votre table EAV APRÈS le signe égal. Ne pas utiliser main_table.avant l'attribut. Magento le fera pour vous. Plus d'informations à ce sujet plus tard.
  3. Les champs sont un tableau . Si vous utilisez une chaîne à la place, vous obtenez ceci: Warning: Invalid argument supplied for foreach() in /var/www/magento-1.6.2.0/app/code/core/Mage/Eav/Model/Entity/Collection/Abstract.php on line 775. Vous pouvez utiliser un tableau du format array('field1', 'field2', '...')ouarray('alias' => 'field1', '...')
  4. La condition est un ** Condition ON ** dans le SQL.
  5. joinType. J'espère que vous savez de quoi il s'agit. Mais vous n'avez que le choix entre GAUCHE et INTÉRIEUR .app/code/core/Mage/Eav/Model/Entity/Collection/Abstract.php:793

Plus sur ce sujet


1
Merci pour ces bonnes informations. Sur la base de votre premier point, ne devrait pas $orders->getSelect() ->joinLeft(array("t1" => $myTable), "main_table.entity_id = t1.entity_id", array("admin_field_id" => "t1.id")) ->where("t1.id is null")exclure les éléments de ma liste actuelle?
webnoob

Je pense que vous modifiez la collection après le chargement. connectez-vous simplement à votre script avec xdebug et vérifiez le drapeau isLoaded à l'intérieur du modèle
Fabian Blechschmidt

2
vaut la peine de mentionner que la méthode joinTable n'est disponible que pour Mage_Eav_Model_Entity_Collection
Fra

1

J'ai trouvé la raison de cela.

Je voulais un décompte de valeurs avant d' appliquer la jointure gauche, j'ai donc ajouté

$totalOrderCount = count($orders);

cependant, cela a provoqué le chargement de la collection, ce qui à son tour signifiait qu'il ignorait la jointure gauche que je faisais plus loin. Pendant le débogage, regarder le var _isCollectionLoadedétait un bon conseil de Fabian.

Je fais maintenant cela à la place pour obtenir le nombre de la collection:

$countOrdersObjs = clone $orders;
$totalOrderCount = count($countOrdersObjs);
unset($countOrdersObjs);

Cela me permet de compter les résultats sans charger la $orderscollection.

Remarque: veuillez appliquer des votes positifs au message de Fabians ci-dessus, car il m'a guidé à ce sujet, mais je pensais que la solution justifiait sa propre réponse.

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.