THELIA Forum

Welcome to the THELIA support and discusssion forum

Announcement

Rejoignez la communauté sur le Discord Thelia : https://discord.gg/YgwpYEE3y3

Offline


Bonjour,

Sur l'un de nos sites e-commerce, nous avons besoin d'ajouter un produit au panier quand la quantité d'un autre type de produit dépasse 30.

J'ai déjà réussi à parcourir mon panier en JS pour vérifier cette condition mais maintenant je ne sais pas quoi faire, et je ne sais même pas si c'est possible d'interagir sur le panier depuis le côté client.

Auriez-vous une idée de la marche à suivre ? J'ai regardé du côté des variables Smarty mais je ne vois rien qui ressemble à l'ajout d'un produit au panier.

Je vous montre à quoi ressemble le template cart.html :

<tbody class="cart-tab-body" id="cart-table-body">
                {assign 'warranty' 'false'}
                <div class="delete-all-item text-right">
                   <a href="{token_url path='/cart/delete/all' success_url={url path='/cart'}}" class="btn btn-vert">{intl l="Vider tout le panier" d="fo.lcv"}</a>
                </div>

                {loop type="cart" name="cartloop"}
                    {loop type="product" name="citerne_product" id=$PRODUCT_ID}
                        {if $TEMPLATE == 11}
                        {assign 'warranty' 'true'}
                        {/if}
                        <tr class="cart-tab-row row">
                    {/loop}
                        <td class="image col-sm-1">
                            <a href="{$PRODUCT_URL nofilter}">
                                {loop type="image" name="product-image" product=$PRODUCT_ID limit="1" force_return="true"}
                                    <img class="img-responsive" src="{$IMAGE_URL nofilter}" alt="Product #{$cart_count}">
                                {/loop}
                            </a>
                        </td>
                        <td class="product col-sm-4" id="product-name">
                        {$TITLE}
                            {loop type="product_sale_elements" name="citerne_garantie" id=$PRODUCT_SALE_ELEMENTS_ID}
                              {loop type="attribute_combination" name="declinaisons_noms" product_sale_elements=$ID}
                                <div>
                                    <i>{intl l="garantie" d="fo.lcv"} : {$ATTRIBUTE_AVAILABILITY_TITLE}</i>
                                </div>
                              {/loop}
                            {/loop}
                        </td>
                        <td class="unitprice col-sm-2">
                        {if $IS_PROMO == 1}
                            {assign "real_price" $TAXED_PROMO_PRICE}
                            {assign "real_total_price" $TOTAL_PROMO_TAXED_PRICE}
                            <div class="old-price">{format_money number=$TAXED_PRICE symbol={currency attr="symbol"}}</div>
                            <span>{format_money number=$real_price symbol={currency attr="symbol"}}</span>
                        {else}
                            {assign "real_price" $TAXED_PRICE}
                            {assign "real_total_price" $TOTAL_TAXED_PRICE}
                            <span>{format_money number=$real_price symbol={currency attr="symbol"}}</span>
                        {/if}
                        </td>
                        <td class="qty col-sm-2">
                            <form action="{token_url path="/cart/update"}" class="product-change form-inline" method="post">
                                    <input type="hidden" name="success_url" value="{url path='/cart'}">
                                    <input type="hidden" name="cart_item" value="{$ITEM_ID}">
                                    <select name="quantity" id="product-qty" class="form-control" >
                                        {if $STOCK < 50}
                                            {assign 'willmax' $STOCK}
                                        {else}
                                                {assign 'willmax' '50'}
                                        {/if}
                                        {for $will=1 to $willmax}
                                            <option {if $QUANTITY == $will}selected="selected"{/if}>{$will}</option>
                                        {/for}
                                   </select>
                                   <!--  <input name="quantity" class="form-control" type="number" min="1" max="{$STOCK}" value ="{$QUANTITY}"> -->
                                    <button type="submit" title="{intl l="Update Quantity"}" class=" btn btn-primary sr-only">{intl l="+"}</button>
                                </form>
                        </td>
                        <td class="subprice col-sm-2">
                            <span>{format_money number={$real_total_price} symbol={currency attr="symbol"}}</span>
                        </td>
                        <td class="delete col-sm-1">
                            <a href="{token_url path="/cart/delete/%item_id" item_id=$ITEM_ID success_url={url path='/cart'}}" class="product-change btn btn-link"><i class="sprite sprite-poubelle"></i></a>
                        </td>
                    </tr>
                {/loop}
            </tbody>

Et mon script :

<script>
    $(document).ready(function(){
        var count = 0;
        var table = document.getElementById("cart-table-body");
        for(var i = 0, row; row = table.rows[i]; i++){
            for(var j = 0, col; col = row.cells[j]; j++){
                if(col.innerText.match(/Tuyau.*/)){
                    var child5 = row.cells[3].childNodes[1].childNodes[5];
                        count = count + parseInt(child5.options[child5.selectedIndex].text);
                }
            }
        }
        if(count >= 30){
            console.log(count);
            //AJOUTER LE PRODUIT AU PANIER
        }

        (..)
    )};
</script>

Last edited by HeishPi (17-05-2019 15:24:28)


Développeur web Junior

Offline


Bonjour,

"via javascript" est-ce obligatoire ? Pourquoi ne pas intercepter un événement TheliaCartEvent côté serveur et réagir en fonction du contenu du panier (produit et/ou quantité spécifiques) ?
Petit exemple sur cette fiche produit : http://www.scoot-company.com/django-50cc-evasion-1.html quand le produit est ajouter au panier, 3 services liés à la mise en route du véhicule sont automatiquement ajoutés au panier.

Nicolas

Offline


Bonjour !

Ce n'est pas obligatoire mais c'est la seule idée qui m'est venue étant donnée que les quantités sont modifiables dans la vue Cart.html. Mais maintenant que je te lis, je me dis que le TheliaCartEvent fonctionne peut-être aussi en cas de modification du panier ?

Je vais regarder de ce côté là en tout cas, merci !

Last edited by HeishPi (07-05-2019 08:09:21)


Développeur web Junior

Offline


Bonjour,

Dans ce cas j'opterai pour la création d'un module.

Dans le fichier config.xml déclares le service qui prendra en charge ta logique métier

<service id="module.action.launching_cost" class="MyModule\Actions\MyCartProcessor">
      <tag name="kernel.event_subscriber"/>
</service>

Et le définir dans la classe MyCartProcessor comme ceci :

<?php

namespace MyModule\Actions;

use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Thelia\Action\BaseAction;
use Thelia\Core\Event\Cart\CartEvent as TheliaCartEvent;
use Thelia\Core\Event\TheliaEvents;
use Thelia\Log\Tlog;

use Thelia\Model\ProductQuery;
use Thelia\Model\CartItemQuery;
use Thelia\Model\ProductPriceQuery;
use Thelia\Model\ProductSaleElementsQuery;
use Thelia\Model\CartItem;
use Thelia\Model\Category;

/**
 *
 */
class MyCartProcessor extends BaseAction implements EventSubscriberInterface
{

    /**
     * Apply my business logic to the cart
     *
     * @params CartEvent $cartEvent
     */
    public function applyMyBusinessLogic(TheliaCartEvent $cartEvent)
    {
        // Get cart items
        $cartItems = $cartEvent->getCart()->getCartItems();

        foreach($cartItems as $cartItem)
        {
            // Get the product from a cart item
            $product = ProductQuery::create()->findOneById($item->getProduct()->getId());
            
            // Get the default category of the product
            $rootCategoryId = $category->getRoot($product->getDefaultCategoryId());

            //
    }



    /**
     * Subscribe to Thelia cart events
     *
     */
    public static function getSubscribedEvents()
    {
        return array(
            TheliaEvents::CART_ADDITEM => array("applyMyBusinessLogic", 64), // Called when an item is added to the cart
            TheliaEvents::CART_DELETEITEM => array("applyMyBusinessLogic", 64), // Called when an item is deleted to the cart
            TheliaEvents::CART_UPDATEITEM => array("applyMyBusinessLogic", 64), // Called when the cart is updated
        );
    }
}

Offline


Bonjour NOG !

J'ai avancé dans ce que tu m'avais suggéré, j'ai même réussi à en sortir une fonction qui remplissait son rôle mais je me suis aperçu que je m'y prenais mal. Je m'explique :

J'avais ce code là :

namespace Front\Action;

use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Thelia\Action\BaseAction;
use Thelia\Core\Event\Cart\CartEvent as TheliaCartEvent;
use Thelia\Core\Event\TheliaEvents;
use Thelia\Model\CartItem;
use Thelia\Model\ProductQuery;
use Thelia\Model\CartItemQuery;
use Propel\Runtime\Exception\PropelException;

/**
 *
 */
class VerifyPipeLengthAction extends BaseAction implements EventSubscriberInterface
{

    /**
     * @params CartEvent $cartEvent
     * @throws PropelException
     */
    public function applyMyBusinessLogic(TheliaCartEvent $cartEvent) {
        $items = $cartEvent->getCart()->getCartItems();

        foreach ($items as $item){
            $product = ProductQuery::create()->findOneById($item->getProductId());
            if(strpos($product->getTitle(), 'Spiral') !== false){
                $count = $item->getQuantity();
                if($count >= 30){
                    $numberOfProductToAdd = $count / 30;
                    $numberOfProductToAddParsed = intval($numberOfProductToAdd);
                    for($i = 0; $i <= $numberOfProductToAddParsed; $i++){
                        if(strpos($product->getTitle(), '25')){
                            $kitPompe = ProductQuery::create()->findOneByRef("LCVA005")->getId();//ref25
                        } else {
                            $kitPompe = ProductQuery::create()->findOneByRef("LCVA006")->getId();//ref50
                        }
                        //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
                        //Partie qui pose problème
                        $kit = CartItemQuery::create()->findOneById($kitPompe);
                        $cartEvent->getCart()->addCartItem($kit);
                        //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
                    }
                }
            }
        }
    }

        public static function getSubscribedEvents() {
            return array(
                TheliaEvents::CART_UPDATEITEM => array("applyMyBusinessLogic", 64), // Called when the cart is updated
            );
        }
    }
  • Je parcours les produits dans le panier, en m'arrêtant sur un nom bien précis.

  • Je regarde la quantité, si elle dépasse 30 (mètres de tuyaux), je dois ajouter mon produit (tous les 30 mètres).

  • Je vérifie la taille du tuyau actuel, et j'adapte le produit à ajouter en fonction.


Et ça fonctionnait mais je faisais la bêtise d'aller chercher un objet cartItem qui avait ce productId là, donc je récupérais aussi la quantité qu'il avait déjà dans cette autre cart.
Je me suis fait la réflexion qu'il valait mieux utiliser les méthodes basiques de Thelia qui rajoutent un produit dans le panier. C'est là que ça se gâte, je me sens bête et je suis pas sûr d'avoir trouvé la bonne méthode. J'ai vu le fichier Thelia\Action\Cart.php et sa fonction addItem mais je n'en comprends pas le fonctionnement, je ne sais pas quoi lui soumettre pour ajouter mon produit au panier.

public function addItem(CartEvent $event, $eventName, EventDispatcherInterface $dispatcher)
    {
        $cart = $event->getCart();
        $newness = $event->getNewness();
        $append = $event->getAppend();
        $quantity = $event->getQuantity();
        $currency = $cart->getCurrency();
        $customer = $cart->getCustomer();
        $discount = 0;

        if ($cart->isNew()) {
            $persistEvent = new CartPersistEvent($cart);
            $dispatcher->dispatch(TheliaEvents::CART_PERSIST, $persistEvent);
        }

        if (null !== $customer && $customer->getDiscount() > 0) {
            $discount = $customer->getDiscount();
        }

        $productSaleElementsId = $event->getProductSaleElementsId();
        $productId = $event->getProduct();

        // Search for an identical item in the cart
        $findItemEvent = clone $event;

        $dispatcher->dispatch(TheliaEvents::CART_FINDITEM, $findItemEvent);

        $cartItem = $findItemEvent->getCartItem();

        if ($cartItem === null || $newness) {
            $productSaleElements = ProductSaleElementsQuery::create()->findPk($productSaleElementsId);

            if (null !== $productSaleElements) {
                $productPrices = $productSaleElements->getPricesByCurrency($currency, $discount);

                $cartItem = $this->doAddItem($dispatcher, $cart, $productId, $productSaleElements, $quantity, $productPrices);
            } else {
                // We did no find any PSE... Something is wrong with the DB, just throw an exception.
                throw new TheliaProcessException("This item cannot be added to the cart: no matching product sale element was found.");
            }
        } elseif ($append && $cartItem !== null) {
            $cartItem->addQuantity($quantity)->save();
        }

        $event->setCartItem($cartItem);
    }

Peux-tu me dire quelle méthode tu utilises sur Scoot-company pour ajouter tes services au panier ?



PS : Mes excuses pour ce pavé smile


Développeur web Junior

Offline


Je me suis fait la réflexion qu'il valait mieux utiliser les méthodes basiques de Thelia qui rajoutent un produit dans le panier.

Mauvaise idée : il faut passer par le système d’évènements, c'est bien plus simple, et surtout ça permet à ton module de s'insérer correctement dans le fonctionnement de Thelia, et de permettre à d'autres modules de manipuler la demande d'ajout au panier.

Pour ajouter un élément au panier il te suffit de faire ceci (on suppose que $product est une instance de Product, et que $quantite est la quantité à ajouter) :

$eventAjout = new CartEvent($cart);

$eventAjout 
    ->setQuantity($quantite)
    ->setProduct($product)
    ->setProductSaleElementsId($product->getDefaultSaleElements())
    ->setAppend(false) // Pour forcer...
    ->setNewness(true) // ... un nouveau produit

    $dispatcher->dispatch(TheliaEvents::CART_ADDITEM, $eventAjout);

Et c'est tout !


OpenStudio Toulouse

Offline


J'ai oublié en effet dans mon extrait le code concernant l'ajout d'un article au panier.

Comme le rappelle Roadster il faut en effet faire appel au gestionnaire d'évènements de Thelia pour être un "bon citoyen" du système. La première règle du "Thelia CLub" est d'utiliser le gestionnaire d'évènements (Liste des évènements Thelia)

Offline


Ahah, je vais peut-être demander ma carte du club alors, parce que juste après avoir posté mon message et avant de lire Roadster, j'ai commencé à regarder ce que demandait comme argument un CartEvent et j'ai commencé à écrire ça :

$event = New CartEvent($cartEvent->getCart());
                    $event
                        ->setProduct($kitPompe->getId())
                        ->setQuantity($numberOfProductToAddParsed)
                        ->setProductSaleElementsId($kitPompe->getDefaultSaleElements()->getId())
                        ->setAppend(false)
                        ->setNewness(true);

                    $dispatcher = New EventDispatcher();
                    $dispatcher->dispatch(TheliaEvents::CART_ADDITEM, $event);

En revanche ça n'a pas d'effet, quand je modifie la quantité d'un autre item du panier (censé déclencher mon event). Avec un var_dump je vois que mon $dispatcher retourne des Array vides. J'ai dû mal comprendre l'utilisation du dispatcher.


Développeur web Junior

Offline


Le dispatcher est un service Symfony, qui n'existe qu'à un seul exemplaire, et est passé aux divers composants suceptibles de générer des évènements.

Il ne faut donc pas créer un nouveau dispatcher, mais utiliser le $dispatcher passé en argument de ta méthode.


OpenStudio Toulouse

Offline


J'obtiens cette erreur :
Catchable fatal error: Argument 2 passed to Front\Action\VerifyPipeLengthAction::applyMyBusinessLogic() must be an instance of Symfony\Component\EventDispatcher\EventDispatcher, string given in D:\Commun\Informatique\Sites\lcv3\local\modules\Front\Action\VerifyPipeLengthAction.php on line 28

Voilà ma fonction, modifiée :

namespace Front\Action;


use Symfony\Component\EventDispatcher\EventDispatcher;

use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Thelia\Action\BaseAction;
use Thelia\Core\Event\Cart\CartEvent as TheliaCartEvent;
use Thelia\Core\Event\Cart\CartEvent;
use Thelia\Core\Event\TheliaEvents;
use Thelia\Model\ProductQuery;
use Propel\Runtime\Exception\PropelException;

/**
 *
 */
class VerifyPipeLengthAction extends BaseAction implements EventSubscriberInterface
{
    /**
     * Apply my business logic to the cart
     *
     * @param CartEvent $cartEvent
     * @param EventDispatcher $dispatcher
     * @throws PropelException
     */
    public function applyMyBusinessLogic(TheliaCartEvent $cartEvent, EventDispatcher $dispatcher) {
        $items = $cartEvent->getCart()->getCartItems();

        foreach ($items as $item){
            $product = ProductQuery::create()->findOneById($item->getProductId());
            if(strpos($product->getTitle(), 'Spiral') !== false){
                $count = $item->getQuantity();
                if($count >= 30){
                    $numberOfProductToAdd = $count / 30;
                    $numberOfProductToAddParsed = intval($numberOfProductToAdd);
                    //verify if there's not already the right product
                    if(strpos($product->getTitle(), '25')){
                        $kitPompe = ProductQuery::create()->findOneByRef("LCVA005");//ref25
                    } else {
                        $kitPompe = ProductQuery::create()->findOneByRef("LCVA006");//ref50
                    }
                    //La bonne méthode
                    $event = New CartEvent($cartEvent->getCart());
                    $event
                        ->setProduct($kitPompe->getId())
                        ->setQuantity($numberOfProductToAddParsed)
                        ->setProductSaleElementsId($kitPompe->getDefaultSaleElements()->getId())
                        ->setAppend(false)
                        ->setNewness(true);

                    $dispatcher->dispatch(TheliaEvents::CART_ADDITEM, $event);                    
                }
            }
        }
    }

        /**
         * Subscribe to Thelia cart events
         *
         */
        public static function getSubscribedEvents() {
            return array(
                TheliaEvents::CART_UPDATEITEM => array("applyMyBusinessLogic", 64), // Called when the cart is updated
            );
        }
    }

Changer le type de la variable $dispatcher ne change rien. J'ai essayé :

  • Symfony\Component\EventDispatcher\EventDispatcher

  • Symfony\Component\EventDispatcher\EventDispatcherInterface

  • Symfony\Component\EventDispatcher\EventSubscriberInterface


Développeur web Junior

Offline


Normal, le 2eme argument d'une méthode d'un event listener est une string: le nom de l'event. La signature correcte est :

applyMyBusinessLogic(TheliaCartEvent $cartEvent, $eventName EventDispatcherInterface $dispatcher)

Exemple dans CartAction : https://github.com/thelia/thelia/blob/m … rt.php#L80


OpenStudio Toulouse

Offline


Effectivement, ça fonctionne maintenant ! Merci beaucoup à vous deux !

Je laisse ma fonction ici au cas où pour quelqu'un d'autre :

namespace Front\Action;


use Symfony\Component\EventDispatcher\EventDispatcher;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Thelia\Action\BaseAction;
use Thelia\Core\Event\Cart\CartEvent as TheliaCartEvent;
use Thelia\Core\Event\Cart\CartEvent;
use Thelia\Core\Event\TheliaEvents;
use Thelia\Model\ProductQuery;
use Propel\Runtime\Exception\PropelException;

/**
 *
 */
class VerifyPipeLengthAction extends BaseAction implements EventSubscriberInterface
{
    /**
     * Apply my business logic to the cart
     *
     * @param CartEvent $cartEvent
     * @param EventDispatcher $dispatcher
     * @throws PropelException
     */
    public function applyMyBusinessLogic(TheliaCartEvent $cartEvent, $eventName, EventDispatcherInterface $dispatcher) {
        $items = $cartEvent->getCart()->getCartItems();

        foreach ($items as $item){
            $product = ProductQuery::create()->findOneById($item->getProductId());
            if(strpos($product->getTitle(), 'Spiral') !== false){
                $count = $item->getQuantity();
                if($count >= 30){
                    $numberOfProductToAdd = $count / 30;
                    $numberOfProductToAddParsed = intval($numberOfProductToAdd);
                    //verify if there's not already the right product
                    if(strpos($product->getTitle(), '25')){
                        $kitPompe = ProductQuery::create()->findOneByRef("LCVA005");//ref25
                    } else {
                        $kitPompe = ProductQuery::create()->findOneByRef("LCVA006");//ref50
                    }
                    //La bonne méthode
                    $event = New CartEvent($cartEvent->getCart());
                    $event
                        ->setProduct($kitPompe->getId())
                        ->setQuantity($numberOfProductToAddParsed)
                        ->setProductSaleElementsId($kitPompe->getDefaultSaleElements()->getId())
                        ->setAppend(false)
                        ->setNewness(true);

                    $dispatcher->dispatch(TheliaEvents::CART_ADDITEM, $event);
                }
            }
        }
    }

        /**
         * Subscribe to Thelia cart events
         *
         */
        public static function getSubscribedEvents() {
            return array(
                TheliaEvents::CART_UPDATEITEM => array("applyMyBusinessLogic", 64), // Called when the cart is updated
            );
        }
    }

Développeur web Junior

Offline

Offline


Bravo bis.

Merci pour la publication du code complet, ce sera sûrement très utilise à d'autres utilisateurs du forum.
Peux-tu passer le post en [Résolu] ?

Last edited by Nog (10-05-2019 16:10:02)

Offline


Merci !
Oui, bien sûr. wink


Développeur web Junior

Offline


Bonjour à tous !

Je me permets de ré-ouvrir ce sujet parce que la fonction que j'ai fini par pondre me pose problème. J'aimerai qu'elle parcourt les items du cart, qu'elle vérifie si ce sont des tuyaux, si la quantité est au moins de 30 et si oui, elle ajoute un certain produit via la référence de ce dernier.
Il y a deux tailles de tuyaux, et si j'ai les deux dans mon panier et que je veux augmenter la quantité de chacun à 30 ou plus, je rencontre un problème : ma fonction s'arrête au premier tuyau qu'elle trouve et qui rentre dans mes conditions. Si j'ai la taille 1 en premier dans le panier, avec une quantité à 30 ou plus, elle ne traitera jamais le tuyau de taille 2 qui arrive après dans le panier.
Si je veux que ça s'opère sur les deux tailles, je suis obligé de réduire la taille du premier tuyau qui arrive dans le panier en dessous de 30, attendre que la page se recharge, et là je peux augmenter la taille du deuxième tuyau à 30 ou plus pour déclencher l'ajout du produit spécifique.

Je ne sais pas si c'est bien clair ce que j'explique... N'hésitez pas à me demander de reformuler.

Voici mon action :

/**
     * Apply my business logic to the cart
     *
     * @param CartEvent $cartEvent
     * @param EventDispatcher $dispatcher
     * @throws PropelException
     */
    public function applyMyBusinessLogic(TheliaCartEvent $cartEvent, $eventName, EventDispatcherInterface $dispatcher) {
        //Get all the items of the cart
        $items = $cartEvent->getCart()->getCartItems();
        foreach ($items as $item) {

            //We search through each item, get the product and verify with it's name if it's a pipe
            $product = ProductQuery::create()->findOneById($item->getProductId());
            if(strpos($product->getTitle(), 'nom de tuyau') !== false) {
                //If it's indeed a pipe, we verify it's more than 30 meters
                if($item->getQuantity()) {
                    //If so, we check wich pipe-size it is
                    if($product->getRef() === 'Référence tuyau taille 1') {
                        $kitRef = "Référence du produit à ajouter taille 1";
                    } else if($product->getRef() === 'Référence tuyau taille 2') {
                        $kitRef = "Référence du produit à ajouter taille 2";
                    }

                    $add = true;
                    //verify if there's not already the right product
                    foreach ($items as $itemInCart) {
                        $product = ProductQuery::create()->findOneById($itemInCart->getProductId());
                        if($product->getRef() === $kitRef) {
                            //If so, we don't do anything.
                            $add = false;
                        }
                    }
                    if($add === true) {
                        //If there's not already the right kit, we add it to the cart
                        $kitPompe = ProductQuery::create()->findOneByRef($kitRef);
                        $this->addKitToCart($cartEvent, $kitPompe, $dispatcher);
                    }
                }
            }
        }
    }

    /**
     * Add a product in parameter to the cart
     * 
     * @param $cartEvent
     * @param $kit
     * @param EventDispatcherInterface $dispatcher
     */
    public function addKitToCart($cartEvent, $kit, EventDispatcherInterface $dispatcher) {
        $event = New CartEvent($cartEvent->getCart());
        $event
            ->setProduct($kit->getId())
            ->setQuantity(1)
            ->setProductSaleElementsId($kit->getDefaultSaleElements()->getId())
            ->setAppend(false)
            ->setNewness(true);

        $dispatcher->dispatch(TheliaEvents::CART_ADDITEM, $event);
    }

    /**
     * Subscribe to Thelia cart events
     *
     */
    public static function getSubscribedEvents() {
        return array(
            TheliaEvents::CART_UPDATEITEM => array("applyMyBusinessLogic", 64), // Called when the cart is updated
            TheliaEvents::AFTER_CARTADDITEM=> array("applyMyBusinessLogic", 64), // Called when the cart is updated
        );
    }

Je me suis demandé si ça ne venait pas de l’événement d'ajout de produit, mais non il doit bien y avoir quelque chose dans mon algorithme qui l'empêche de continuer après avoir vu que le premier tuyau possédait déjà le produit spécifique à ajouter. Surtout que la fonction marche à merveille s'il n'y a qu'un seul tuyau avec une quantité de 30, ou bien s'il n'y qu'une seule taille de tuyau dans le panier.

J'ai passé plusieurs jours dessus sans voir ce que j'ai pu mal faire, je viens donc vous appeler à l'aide pour réclamer un point de vue différent smile

Merci d'avance !


Développeur web Junior

Offline


Après d'autres investigations, je me rends compte que mon premier foreach (qui parcourt les items du panier pour chercher s'il y a un tuyau) s'arrête après le premier tuyau qu'il trouve (qu'il ait besoin d'ajouter le produit spécifique ou non). Et je ne comprends absolument pas pourquoi. A mes yeux, y a aucune raison pour que la boucle sorte d'elle même de son fonctionnement.

Est-ce que ce serait une bizarrerie des eventslisteners de Thelia ?


Développeur web Junior

Offline


Non, tu as surement un problème algorithmique.

Vérifie si par hasard tu n'aurais pas une exception dans ta boucle.

Dans tous les cas, utilise un debugger, et fait un parcours pas à pas, tu vas trouver bien plus vite qu'en tâtonnant


OpenStudio Toulouse

Offline


Bon, effectivement, quelque chose n'allait pas dans mon algo, je ne sais toujours pas quoi... Mais en tout cas, changer la logique a résolu le problème ! Merci pour l'idée du debugger, c'est fou comme on oublie les choses les plus simples quand on passe des heures à s'arracher les cheveux sur les mêmes choses...

Je laisse ici le code qui a marché pour moi :

public function applyMyBusinessLogic(TheliaCartEvent $cartEvent, $eventName, EventDispatcherInterface $dispatcher) {
        //Get all the items of the cart
        $items = $cartEvent->getCart()->getCartItems();
        $itemRefs = array();
        $tab = array();
        foreach ($items as $item) {
            //We start by adding every reference there is in the cart in an array
            $itemRefs[] = $item->getProduct()->getRef();
            //We search through each item, get the product and verify with it's ref if it's a pipe
            $product = ProductQuery::create()->findOneById($item->getProductId());
            if(strpos($product->getRef(), 'ETUY') !== false) {
                //If it's indeed a pipe, we verify it's more than 30 meters
                if($item->getQuantity() > 30) {
                    //If so, we get the accessory that comes with it (automatically the right size)
                    $productToAdd = $product->getProductsRelatedByAccessory()->getFirst();
                    //And add it to our array of products to add.
                    $tab[] = $productToAdd;
                }
            }
        }
        //Then we check for each product to add, if it isn't already in the cart
        foreach ($tab as $toAdd){
            //If it is :
            if (in_array($toAdd->getRef(), $itemRefs)){
                //We do nothing
            } else {
                //Otherwise we add it to the cart
                $this->addKitToCart($cartEvent, $toAdd, $dispatcher);
            }
        }
    }

Développeur web Junior