THELIA Forum

Welcome to the THELIA support and discusssion forum

Announcement

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

Offline


Bonjour,
  J'essaye de rajouter un champs "fournisseur_ref_id" à mes produits. Pour ça j'ai créé un module qui me permet de créer des fournisseurs et des référence produits par fournisseurs. Maintenant je veux associer ses références produits à mes produits.
Pour ce faire je me suis basé sur le module CustomBirthDate.

Donc j'ai configurer mon EventListner et mes hooks dans config.xml:

<?xml version="1.0" encoding="UTF-8" ?>

<config xmlns="http://thelia.net/schema/dic/config"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://thelia.net/schema/dic/config http://thelia.net/schema/dic/config/thelia-1.0.xsd">

    <loops>
        <loop name="fournisseur.view" class="MonStock\Loop\FournisseurLoop" />
        <loop name="fournisseur.ref.view" class="MonStock\Loop\FournisseurRefLoop" />
    </loops>

    <forms>
        <form name="fournisseurcreation.form" class="MonStock\Form\FournisseurCreationForm" />
        <form name="fournisseurupdate.form" class="MonStock\Form\FournisseurUpdateForm" />

        <form name="fournisseurrefcreation.form" class="MonStock\Form\FournisseurRefCreationForm" />
        <form name="fournisseurrefupdate.form" class="MonStock\Form\FournisseurRefUpdateForm" />
    </forms>

    <commands>
    </commands>

    <services>
        <service id="monstock.services" class="MonStock\EventListeners\MonStockEventListener" scope="request">
            <argument id="request" type="service"/>
            <tag name="kernel.event_subscriber"/>
        </service>
    </services>
    
    <hooks>
        <hook id="monstock.menu.hook" class="MonStock\Hook\MonStockHook">
            <tag name="hook.event_listener" event="main.in-top-menu-items" type="back" method="onMainTopMenuTools" />
        </hook>

        <hook id="addreference.hook" class="MonStock\Hook\MonStockHook" scope="request">
            <tag name="hook.event_listener" event="product-edit.bottom" type="back" method="onBackUpdate" />
            <tag name="hook.event_listener" event="product.create-form" type="back" method="onBackCreate" />
        </hook>
    </hooks>
</config>

Donc aussi mon EventListner :

<?php

namespace MonStock\EventListeners;

use MonStock\Model\ProductFournisseurRef;
use MonStock\Model\ProductFournisseurRefQuery;
use Symfony\Component\Config\Definition\Exception\Exception;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Thelia\Core\Event\Product\ProductEvent;
use Thelia\Core\Event\TheliaEvents;
use Thelia\Core\Event\TheliaFormEvent;
use Thelia\Core\HttpFoundation\Request;
use Thelia\Core\Translation\Translator;

/**
 * Class MonStockEventListenerr
 * @package MonStock\EventListeners
 * @author Etienne Perriere - OpenStudio <eperriere@openstudio.fr>
 */
class MonStockEventListener implements EventSubscriberInterface
{
    protected $request;

    public function __construct(Request $request)
    {
        $this->request = $request;
    }

    public static function getSubscribedEvents()
    {
        return [
            TheliaEvents::FORM_AFTER_BUILD . '.thelia_product_creation' => ['RefFournisseurInput', 128],
            TheliaEvents::AFTER_CREATEPRODUCT => ['createRefFournisseur', 128],

            TheliaEvents::FORM_AFTER_BUILD . '.thelia_product_modification' => ['RefFournisseurInput', 128],
            TheliaEvents::AFTER_UPDATEPRODUCT => ['updateRefFournisseur', 128]
        ];
    }

    /**
     * Add ref input in forms
     * @param TheliaFormEvent $event
     */
    public function refFournisseurInput(TheliaFormEvent $event)
    {
        if ($this->request->fromApi() === false) {
            $data = $event->getForm()->getFormBuilder()->getData();

            // var_dump($data);
            // die();
            $productRef = null;

            if (!empty($data['id'])) {
                $productRef = ProductFournisseurRefQuery::create()->findOneById($data['id']);
            }

            // var_dump($productRef);
            // die();

            $event->getForm()->getFormBuilder()
                ->add("fournisseur_ref_id", "integer", array(
                    "label" => Translator::getInstance()->trans('Référence du produit'),
                    "label_attr" => array("for" => "fournisseur_ref_id"),
                ));

            // var_dump($event);
            // die();
        }
    }

    /**
     * Get ref from forms
     * @param ProductEvent $event
     */
    public function createRefFournisseur(ProductEvent $event)
    {
        if ($this->request->fromApi() === false) {
            // Get ref from input & format it
            $ref = $this->request->get('thelia_product_creation')['fournisseur_ref_id'];

            // Create a ref & save it
            $this->doCreateRefFournisseur($event, $ref);
        }
    }

    /**
     * Create a new Product ref
     * @param ProductEvent $event
     * @param \Integer $ref
     * @throws \Exception
     * @throws \Propel\Runtime\Exception\PropelException
     */
    public function doCreateFournisseurRef(ProductEvent $event, \Integer $ref)
    {
        (new ProductFournisseurRef())
            ->setProductId($event->getProduct()->getId())
            ->setFournisseurRefId($ref)
            ->save();
    }

    /**
     * Update an existing ref
     * @param ProductEvent $event
     * @throws \Exception
     * @throws \Propel\Runtime\Exception\PropelException
     */
    public function updateRefFournisseur(ProductEvent $event)
    {

        // var_dump("test");
        // die();
        if ($this->request->fromApi() === false) {
            
            // Get date from input depending on request origin (front or back)
            if ($this->request->fromFront() === true) {
                $ref = $this->request->get('thelia_product_modification')['fournisseur_ref_id'];
            } elseif ($this->request->fromAdmin() === true) {
                // var_dump("lol");
                // die();
                $ref = $this->request->get('thelia_product_modification')['fournisseur_ref_id'];
                // var_dump("lol");
                // die();
                // var_dump($ref);
                // die();
            } else {
                // var_dump("test");
                // die();
                throw new Exception('No form found');
            }
            
            // Check if the product already have a ref
            if (null === $productRef = ProductFournisseurRefQuery::create()->findOneById($event->getProduct()->getId())) {
                
                // Create a new birth date
                $this->doCreateFournisseurRef($event, $ref);
            } else {
                
                // Save it
                $productRef
                    ->setFournisseurRefId($ref)
                    ->save();
            }
        }
    }
    
}

Mes Hooks :

<?php

namespace MonStock\Hook;

use MonStock\MonStock;
use Symfony\Component\Routing\RouterInterface;
use Thelia\Core\Event\Hook\HookRenderEvent;
use Thelia\Core\Hook\BaseHook;
use Thelia\Core\Security\AccessManager;
use Thelia\Core\Security\SecurityContext;
use Thelia\Model\Base\ModuleQuery;

class MonStockHook extends BaseHook{

    public function onMainTopMenuTools(HookRenderEvent $event)
	{

			$event->add($this->render("menu-hook.html", $event->getArguments()));

	}

	/* BACK - CREATE */
    public function onBackCreate(HookRenderEvent $event)
    {
        $event->add($this->render(
            'product-add-reference.html',
            ['formName' => 'thelia.admin.product.creation']
        ));
    }

    /* BACK - UPDATE */
    public function onBackUpdate(HookRenderEvent $event)
    {
        $event->add($this->render(
            'product-add-reference.html',
            ['formName' => 'thelia.admin.product.modification']
        ));
    }

}

et mon template :

{form name=$formName}

    {form_field form=$form field='fournisseur_ref_id'}
    <div class="form-group col-md-6">
        <label for="">Fournisseur</label>
        <select onchange="getFournisseurId()" name="" id="fournisseurId" class="form-control">
            <option value="none" selected>Choisir un fournisseur</option>
            {loop name="testLoopFournisseur" type="fournisseur.view" fournisseur_id=$ID}
            <option value="{$ID}">{$NAME}</option>
            {/loop}
        </select>
    </div>
    <div class="form-group group-refour col-md-6">
        <label for="">Référence produit</label>
        <select name="{$name}" id="selectRefFournisseur" class="nonVisible form-control" aria-required="true" required>
            <option value="none" selected>Choisir une référence</option>
            {loop name="LoopFournisseurRef" type="fournisseur.ref.view" id=5 }
            <option value="{$ID}" class="{$FOURNISSEUR} fournisseurIdRef">{$TITLE}</option>
            {/loop}
        </select>
    </div>
    {/form_field}

    {/form}

Je vois bien mon template sur la page update des produits ou sur la page create, mais mon form n'est pas pris en compte. Quand je regarde dans la console de mon navigateur, dans l'onglet rréseaux, dans ma requete "save", je n'est pas thelia_product_modification[fournisseur_ref_id] et j'obtiens ce message d'erreur : "Notice: Undefined index: fournisseur_ref_id".

Voilà le topo...

Offline


Déjà, pour l'update le hook product-edit.bottom n'est pas dans la <form> de la page product-edit.html (plus précisément templates/backOffice/default/includes/product-general-tab.html), donc tes champs sont en dehors de toute form, tu ne vas pas pouvoir les récupérer. Il te faut utiliser product.modification.form-right.bottom ou product.modification.form_bottom.
Pour le create, ça devrait marcher.

Ensuite, dans updateRefFournisseur, les champs que tu as ajouté sont présents dans l'event, tu peux faire :

$id = $event->fournisseur_ref_id;

En effet, dans la controleurs admin (et dans les contr^^oleurs admin seulement), les champs de la form (TOUS les champs, y compris ceux que tu as ajouté) sont bindés à l'event par la methode \Thelia\Core\Event\ActionEvent::bindForm(), et les champs qui n'ont pas de setter sont automatiquement créés et valués.

Enfin, plutôt que de faire des var_dump, installe xdebug, configure ton IDE et debugue ton code comme un pro, tu gagneras BEAUCOUP de temps wink


OpenStudio Toulouse

Offline


Wouah ok le hook à tout fait !
Maintenant lors de l'update d'un produit tout fonctionne parfaitement !

Mais lors de la création il me reste une erreur : Type error: Argument 2 passed to MonStock\EventListeners\MonStockEventListener::doCreateFournisseurRef() must be of the type string, null given, called in /data/share/vhosts/preprod.opluba.com/local/modules/MonStock/EventListeners/MonStockEventListener.php on line 135.

Et pour xdebug j'ai déjà essayer de l'installer mais c'est un peu la galère vu que le site du client est sur un serveur distant il faut que je contact la boite qui gère et c'est un peu long...

Offline


Le message d'erreur est clair : Argument 2 passed to MonStock\EventListeners\MonStockEventListener::doCreateFournisseurRef() must be of the type string, null given

donc $ref est null lors de l'appel en ligne 135 : $this->doCreateFournisseurRef($event, $ref);

Par ailleurs tu es sûr de ça : public function doCreateFournisseurRef(ProductEvent $event, \Integer $ref) ?


OpenStudio Toulouse

Offline


Pour le Integer je l'avais déjà modifier en String, et en update tout fonctionne.

Ok donc je dois trouver pourquoi mon $ref est null, merci.

Offline


Parce que $this->request->fromFront() !== true et $this->request->fromAdmin() != true smile


OpenStudio Toulouse

Offline


J'ai enlevé le fromFront, car ça ne se fera jamais du front.
C'est cette ligne : $ref = $this->request->get('thelia_product_modification')['fournisseur_ref_id'];  qui me donne un NULL pour $ref

Offline


Je t'ai répondu un peu plus haut sur ce point.


OpenStudio Toulouse

Offline


            if ($this->request->fromFront() !== true) {
                $ref = $this->request->get('thelia_product_modification')['fournisseur_ref_id'];
            } elseif ($this->request->fromAdmin() != true) {
                $ref = $this->request->get('thelia_product_modification')['fournisseur_ref_id'];
            } else {
                throw new Exception('No form found');
            }

Maintenant j'ai ça, comme tu me l'as dit, mais toujours $ref = null

Offline


Je reviens juste pour dire que j'ai enlevé le fait de rajouté mon formulaire lors de la création d'un produit comme ça pas de problème.