THELIA Forum

Welcome to the THELIA support and discusssion forum

Announcement

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

Offline


Bonjour,

Est ce qu'il est possible d'ajouter une nouvelle variable qui est lié à l'entité Product dans l'événement AddCart ?

Merci,

Last edited by Seragan (02-11-2016 10:50:25)

Offline


Oui. Mais la façon de faire dépend de ce que veux-tu faire exactement.


OpenStudio Toulouse

Offline


Bonjour,

Je suis un ami de Seragan.
Et le problème c'est qu'on voudrait sur la page de la fiche Product, côté Front Office, je voudrais rajouter plusieurs champs texte par exemple.
Mais il faut toucher à l'entité(Model) Product pour ajouter ses champs souhaités, il faut rajouter les variables dans le schema.xml afin de les ajouter en base de données, les rajouter aussi dans le fonction buildForm(), etc....

C'est à dire s'inspirer du module "Commentaire de commande" sauf qu'au lieu qu'il démarre sur la page "panier", on aimerait le mettre en place sur la fiche produit tout simplement ?

Merci,
Mikius

Offline


je voudrais rajouter plusieurs champs texte par exemple

Utilise les caractéristiques c'est fait pour ça smile

Mais si tu préfères coder :

pour ajouter ses champs souhaités, il faut rajouter les variables dans le schema.xml

Non, il ne faut JAMAIS modifier les fichier de la distrib, car tu te coupes des mises à jour futures.
La bonne méthode est d'écrire un module qui gère une table qui contient les champs supplémentaires, et qui est liée à la table produit via une foreign key.

Ce module gère aussi une boucle, qui permet d'afficher les champs supplémentaires, et une form, qui permet de les saisir dans la fiche produit en back-office. Regarde le module Tags (https://github.com/roadster31/Tags) pour avoir un exemple.


OpenStudio Toulouse

Offline


Bonjour,

Merci pour les informations données, mais je voudrais ajouter côté front-office (un champs "message de personnalisation" du produit) sur la fiche produit.
Au moment de l'événement CartAdd, j'aimerais que cela l'enregistre direct en base de données.
Voilà à peu près ce que je souhaiterais faire.

Merci smile

Offline


C'est le même principe : une form, une table liée à la table produit, et une boucle.


OpenStudio Toulouse

Offline


Je suis tout à fait d'accord avec le processus que tu évoques, mais au moment d’exécuter le formulaire, lors de l'événement CartAdd, le message de personnalisation ne s'enregistre pas dans la base de données.

Est ce que tu serais intéressé de jeter un coup d’œil au module effectué ?

Merci

Offline


Pas trop le temps, mais poste le ici si tu veux, je regarderais si j'ai 2mn.


OpenStudio Toulouse

Offline


Nous avons comme but de créer un module "ProductComment", c'est à dire un champs où le client peux laisser un message/commentaire sur le produit.
En clair : Le client laisse un message dans le champs, ajoute le produit au panier et retourne sur le produit avec normalement en base, dans notre table dédié aux commentaires.
Nous n’arrivons pas à récupérer le commentaire saisi dans le champ et l'ajouter en base.
Merci d'avance.

config.xml :

    <loops>
        <loop name="product.comment.comment" class="ProductComment\Loop\ProductCommentLoop"/>
        <loop name="product.comment.session.comment" class="ProductComment\Loop\SessionProductCommentLoop"/>
    </loops>

    <forms>
        <form name="product.comment.form" class="ProductComment\Form\ProductCommentForm" />
    </forms>

    <services>
        <service id="product.comment.order.info" class="ProductComment\EventListeners\ProductCommentInfo" scope="request">
            <argument type="service" id="request" />
            <tag name="kernel.event_subscriber" />
        </service>
    </services>

    <hooks>
        <hook id="product.comment.hook.front" class="ProductComment\Hook\FrontHook" scope="request">
            <tag name="hook.event_listener" type="front" event="product.details-bottom" method="onProducDetailstBottom"/>
            <tag name="hook.event_listener" type="front" event="product.stylesheet" method="onProductIncludeCss"/>
            <tag name="hook.event_listener" type="front" event="product.after-javascript-include" method="onProductIncludeJs"/>
        </hook>
    </hooks>

Notre event listener :

class ProductCommentInfo implements EventSubscriberInterface
{
    protected $request;

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

    public static function getSubscribedEvents()
    {
        return [TheliaEvents::CART_ITEM_UPDATE_BEFORE => 'saveComment'];
    }

    public function saveComment(CartEvent $cartEvent)
    {
        $comment = $this->request->getSession()->get('product-comment');
        $cart = $cartEvent->getCart();
        $cartId = $cart->getId();

        if ($cartId != null && $comment != null) {
            $productComment = new ProductComment();
            $productComment->setOrderProductId($cartId);
            $productComment->setComment($comment);
            $productComment->save();
            $this->request->getSession()->set('product-comment', '');
        }
    }
}

Notre controler :

class ProductCommentController extends BaseFrontController
{
    public function setComment()
    {
        $message = false;
        $commentForm = new ProductCommentForm($this->getRequest());

        try {
            $form = $this->validateForm($commentForm);
            $data = $form->getData($form);
            $comment = $data['comment'];;

            if ($comment != null) {
                return $this->getRequest()->getSession()->set('product-comment', $comment);
            }

            return $this->generateRedirectFromRoute("product.view");

        } catch (FormValidationException $e) {
            $message = Translator::getInstance()->trans("Please check your input: %s", ['%s' => $e->getMessage()], Front::MESSAGE_DOMAIN);
        } catch (PropelException $e) {
            $this->getParserContext()->setGeneralError($e->getMessage());
        } catch (\Exception $e) {
            $message = Translator::getInstance()->trans("Sorry, an error occurred: %s", ['%s' => $e->getMessage()], Front::MESSAGE_DOMAIN);
        }

        if ($message !== false) {
            $commentForm->setErrorMessage($message);

            return $this->getParserContext()
                ->addForm($commentForm)
                ->setGeneralError($message)
            ;

            return $this->generateRedirectFromRoute("product.view");
        }
    }
}

Offline


Se baser sur TheliaEvents::CART_ITEM_UPDATE_BEFORE est problématique, car si le dispatcher n'a pas été passé à l'objet CartItem (ce qui arrive), l'event n'est pas dispatché. Je recommande d'utiliser plutôt CART_ADD_ITEM, avec une priorité basse (10) :

    public static function getSubscribedEvents()
    {
        return [
            TheliaEvents::CART_ADDITEM => ['saveComment', 10 ],
        ];
    }

Je ne comprends pas :
1) Comment tu te sers de la form ProductCommentForm
2) quand la méthode ProductCommentController::setComment() est appelée.


OpenStudio Toulouse

Offline


class ProductCommentForm extends BaseForm
{
    public function buildForm()
    {
        $this->formBuilder
            ->add('comment','textarea',
                array(
                    'required' => false
                )
            );
    }

    public function getName()
    {
        return "product_comment_form";
    }
}
class ProductCommentLoop extends BaseLoop implements PropelSearchLoopInterface
{
    /**
     * @return \Thelia\Core\Template\Loop\Argument\ArgumentCollection
     */
    protected function getArgDefinitions()
    {
        return new ArgumentCollection(
            Argument::createIntTypeArgument('order_product_id', null, true)
        );
    }

    /**
     * this method returns a Propel ModelCriteria
     *
     * @return \Propel\Runtime\ActiveQuery\ModelCriteria
     */
    public function buildModelCriteria()
    {
        $productCommentQuery = ProductCommentQuery::create()->filterByOrderId($this->getOrderId());

        return $productCommentQuery;
    }

    /**
     * @param LoopResult $loopResult
     *
     * @return LoopResult
     */
    public function parseResults(LoopResult $loopResult)
    {
        /** @var \ProductComment\Model\ProductComment $productComment */
        foreach ($loopResult->getResultDataCollection() as $productComment) {
            $loopResultRow = new LoopResultRow($productComment);

            $loopResultRow->set("PRODUCT_COMMENT", $productComment->getComment());
            $loopResult->addRow($loopResultRow);
        }

        return $loopResult;
    }
}
class SessionProductCommentLoop extends BaseLoop implements ArraySearchLoopInterface
{
    public function buildArray()
    {
        $item = ['comment' => $this->request->getSession()->get('product-comment')];

        return $item;
    }

    public function parseResults(LoopResult $loopResult)
    {
        $item = $loopResult->getResultDataCollection();

        $loopResultRow = new LoopResultRow();
        $loopResultRow->set('PRODUCT_COMMENT', $item['comment']);

        $loopResult->addRow($loopResultRow);

        return $loopResult;
    }

    public function getArgDefinitions()
    {
        return new ArgumentCollection();
    }
}

product-comment.html :

{form name="product.comment.form"}
    <form id="product-comment-form" action="{url path='/productcomment/set/comment'}" method="post">
        {form_hidden_fields form=$form}
        <div class="panel panel-default">
            <div class="panel-heading">
                {intl l="Add your comment" d="productcomment.fo.default"}
            </div>
            <div class="panel-body">
                {if $form_error}<div class="alert alert-danger">{$form_error_message}</div>{/if}

                <div id="alert-comment"></div>
                {form_field form=$form field='comment'}
                    <textarea class="form-control" name="{$name}" placeholder="{intl l='Type your message here' d='productcomment.fo.default'}">{loop type="product.comment.session.comment" name="session-product-comment" }{ifloop rel="session-product-comment"}{$PRODUCT_COMMENT}{/ifloop}{/loop}</textarea>
                {/form_field}
            </div>
        </div>
{/form}

Offline


C'est quoi le rapport avec le Cart ? A quel moment tu ajoutes un produit au panier ? Comment tu fais le lien avec le CartItem ?


OpenStudio Toulouse

Offline


Au moment où je clique sur le bonton "Add cart", je voudrais que le message personnalisé saisi s'enregistre dans la base de données.
Et le lien pour CartItem c'est par rapport à l'event CartEvent.

Est ce que ça te parle ou pas du tout ?

Offline


Bien sûr, mais  ce n'est pas ce que tu fais.


OpenStudio Toulouse

Offline


D'accord au moins c'est clair où est donc mon erreur dans mon raisonnement dans le code ?
J'imagine que c'est dans mon fichier ProductCommentInfo (EventListener) ?

Offline


Une question : a quoi sert ton contrôleur, et quand est il appelé ?


OpenStudio Toulouse

Offline


Désolé le contrôleur ne sert à rien c'était un test de notre part.

Offline


public function saveComment(CartEvent $cartEvent)
    {
        $comment = $this->request->getSession()->get('product_comment_form');
        $cart = $cartEvent->getCart();
        $cartId = $cart->getId();
        if ($cartId != null && $comment != null) {
            $productComment = new ProductComment();
            $productComment->setOrderProductId($cartId);
            $productComment->setComment($comment);
            $productComment->save();
            $this->request->getSession()->set('product-comment', '');
        }
    }

Dans cette partie là, du code je n'arrive pas à récupérer le commentaire saisi du formulaire donc je ne passe la condition if.
Et c'est à partir de ce moment que l'enregistrement en base de données et là, je suis vraiment perdu.

Merci

Offline


$comment = $this->request->getSession()->get('product_comment_form');

Comme à aucun moment "product_comment_form" n'est stocké en session, $comment ne peut qu'être null.


OpenStudio Toulouse

Offline


Voici le code de mon formulaire où j'ai ajouté l'input
Pardon c'était plutôt product-comment dans l'input

{form name="product.comment.form"}
    <form id="product-comment-form" action="{url path='/productcomment/set/comment'}" method="post">
        {form_hidden_fields form=$form}
        <div class="panel panel-default">
            <div class="panel-heading">
                {intl l="Add your comment" d="productcomment.fo.default"}
            </div>
            <div class="panel-body">
                {if $form_error}<div class="alert alert-danger">{$form_error_message}</div>{/if}

                <div id="alert-comment"></div>
                {form_field form=$form field='comment'}
                    <textarea class="form-control" name="{$name}" placeholder="{intl l='Type your message here' d='productcomment.fo.default'}">{loop type="product.comment.session.comment" name="session-product-comment" }{ifloop rel="session-product-comment"}{$PRODUCT_COMMENT}{/ifloop}{/loop}</textarea>
                {/form_field}
            </div>
        </div>
{/form}

Offline


Je comprends bien que tu as ajouté un formulaire, mais quand est-il envoyé au serveur ?


OpenStudio Toulouse

Offline


Il envoie une valeur NULL

Offline


A quel moment le formulaire product.comment.form qui est dans ta page est soumis (envoyé, POSTé, ...) au serveur ?


OpenStudio Toulouse

Offline


Je me rends qu'à aucun moment, le formulaire est soumis ou envoyé via le serveur.

Offline


Okay, on est d'accord smile

Le plus simple, c'est de placer dans la form d'ajout au panier un input, de le nommer "comment" (ou ce que tu voudras) :

<textarea class="form-control" name="comment"></textarea>

Et dans ton event handler, tu le récupères avec $this->request->get('comment')

C'est un peu cradoc, mais c'est le plus simple.


OpenStudio Toulouse