Po lewej dołącz do tabeli w zapytaniu dotyczącym kolekcji

27

Wykonuję następujące czynności, aby uzyskać niektóre zamówienia z systemu na eksport:

$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)));

Muszę dodać coś, co nie eksportuje, jeśli zamówienie entity_idznajduje się w niestandardowej tabeli, którą mam. Gdybym korzystał z SQL, zrobiłbym:

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

Ale nie jestem pewien, jak zmodyfikować kwerendę kolekcji, aby zrobić podobnie.

Uwaga: próbowałem

$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")

ale to zmienia to, więc jest to zapytanie i chcę zwrócić kolekcję sprzedaży / zamówienia.

Czuję, że brakuje mi czegoś prostego ...

EDYTOWAĆ

Ok, próbowałem tego:

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

Gdy echo (string)$orders->getSelect(), zwraca zapytanie, którego oczekiwałbym i nie zwraca żadnych wyników po uruchomieniu. $ordersjednak nadal zawiera elementy. Myślałem, że to połączenie miało w tym momencie zmodyfikować kolekcję?

webnoob
źródło

Odpowiedzi:

53

Aby zmienić zapytanie, możesz to zrobić

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

Ale aby dołączyć do stołu, możesz po prostu użyć $collection->joinTable()

joinTableistnieje tylko w Mage_Eav_Model_Entity_Collection, co oznacza: produkty, kategorie, zamówienia, faktury, kredyt, wysyłkę, klientów. (Dzięki @Fra za komentarz)

joinTable ()

Ale kolekcje magento mają metodę, joinTable()która zajęła mi 45 minut, aby wymieszać sposób ich użycia. Aby tego uniknąć, udostępniam to.

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

Parametry to:

public function joinTable($table, $bind, $fields = null, $cond = null, $joinType = 'inner')
  1. Tabela jest łatwa, jest to namespace/entityformat magento , którego używasz w konfiguracji, modelach zasobów i kolekcji. Możesz użyć tablicy formatuarray('alias' => 'namespace/entity')
  2. Bind oznacza instrukcję ON w twoim SQL. To była najtrudniejsza część i wyjaśnię ją szczegółowo później. Ważne jest, aby mieć płaski stół PRZED, a swój stół EAV PO znaku równości. Nie używaj main_table.przed atrybutem. Magento zrobi to za ciebie. Więcej na ten temat później.
  3. Pola to tablica . Jeśli używasz ciąg zamiast, to masz: 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. Możesz użyć tablicy formatu array('field1', 'field2', '...')lubarray('alias' => 'field1', '...')
  4. Warunek jest ** GDZIE Warunek ON ** w SQL.
  5. joinType. Mam nadzieję, że wiesz co to jest. Ale masz tylko wybór pomiędzy LEWĄ a WEWNĘTRZNĄ .app/code/core/Mage/Eav/Model/Entity/Collection/Abstract.php:793

Więcej na ten temat

Fabian Blechschmidt
źródło
1
Dzięki za te wspaniałe informacje. Czy na podstawie pierwszego punktu nie należy $orders->getSelect() ->joinLeft(array("t1" => $myTable), "main_table.entity_id = t1.entity_id", array("admin_field_id" => "t1.id")) ->where("t1.id is null")wykluczać elementów z mojej bieżącej listy?
webnoob
Myślę, że edytujesz kolekcję po załadowaniu. po prostu podłącz się do swojego skryptu za pomocą xdebug i sprawdź flagę isLoaded w modelu
Fabian Blechschmidt
2
warto wspomnieć, że metoda joinTable jest dostępna tylko dla Mage_Eav_Model_Entity_Collection
Fra
1

Znalazłem przyczynę tego.

Chciałem policzyć wartości, zanim zastosowałem lewe łączenie, więc dodałem

$totalOrderCount = count($orders);

spowodowało to jednak załadowanie kolekcji, co z kolei spowodowało, że zignorowałem lewe łączenie, nad którym pracowałem dalej. Podczas debugowania spojrzenie na var _isCollectionLoadedbyło dobrą wskazówką Fabiana.

Teraz robię to, aby uzyskać liczbę kolekcji:

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

To pozwala mi policzyć wyniki bez ładowania $orderskolekcji.

Uwaga: Prosimy o uwzględnienie wszelkich głosów poparcia dla powyższego postu Fabianów, ponieważ kierował mną w tej sprawie, ale czułem, że rozwiązanie uzasadnia własną odpowiedź.

webnoob
źródło