Introduction aux formulaires frontaux

Dans ce didacticiel, nous allons ajouter des formulaires à l’interface de notre site Web. Nous allons ajouter une nouvelle fonctionnalité qui permet aux utilisateurs de poster des commentaires sur nos articles.

Dépôt de code à télécharger

Comment SilverStripe gère les formulaires

Cette leçon concerne les formulaires frontaux, une distinction très importante à faire, car nous travaillons avec des formulaires depuis très tôt dans la CMS. Chaque fois que nous modifions des données dans le backend, nous utilisons un formulaire. La principale différence est que dans le CMS, seule une petite partie de cette forme est exposée à la classe de modèle via getCMSFields().

Lorsque vous réfléchissez à la manière dont un framework peut traiter la création de formulaire, vous pouvez imaginer un objet simple qui prend un tableau de champs de formulaire et finit par transférer du code HTML via une render()méthode ou quelque chose de similaire, mais l’une des caractéristiques les plus distinctives des formulaires dans SilverStripe est qu’ils soient traités comme des citoyens de première classe , c’est-à-dire qu’ils sont des objets intelligents qui fonctionnent avec tous les grands acteurs du cycle de demande.

 

Créer un formulaire simple

Regardons un constructeur de formulaire simple pour mieux comprendre comment cela fonctionnera. La méthode suivante serait placée dans n’importe quel Controller.

 

    public function ContactForm()
    {
        $myForm = Form::create(
            $controller,
            'ContactForm',
            FieldList::create(
                TextField::create('YourName','Your name'),
                TextareaField::create('YourComments','Your comments')
            ),
            FieldList::create(
                FormAction::create('sendContactForm','Submit')
            ),
            RequiredFields::create('YourName','YourComments')
        );

        return $myForm;
    }

 

Passons en revue chaque argument du constructeur:

  • $controllerUn formulaire doit être généré et géré par un contrôleur. Les avantages sont impressionnants et nous en verrons quelques-uns dans un instant. Etant donné que le contrôleur qui crée le formulaire gère généralement également sa soumission 99% du temps, ce premier argument sera $this.
  • ContactFormUne chaîne représentant le nom de la méthode qui crée le formulaire. Bizarre, non? Il est un peu inhabituel de traiter avec des méthodes de classe comme des chaînes, mais c’est une fonctionnalité vraiment essentielle. Le formulaire sera soumis à une URL qui appelle cette méthode, ce qui signifie que nous obtenons l’ Formobjet entièrement configuré à inspecter et à manipuler lors du traitement de la soumission. Nous pouvons ajouter des messages d’erreur, définir l’état et même manipuler les champs en fonction de la soumission de l’utilisateur. Comme cet argument décrit toujours le nom de la fonction dans laquelle vous vous trouvez, vous pouvez simplement utiliser la constante PHP __FUNCTION__ici.
  • Un FieldListobjet contenant tous les champs de formulaire acceptant les entrées utilisateur
  • Un FieldListobjet contenant toutes les actions de formulaire , ou les boutons, qui soumettent un formulaire. Souvent, vous n’aurez qu’une action. Le premier argument du FormActionconstructeur est la méthode sur le contrôleur qui sera invoquée lors de la soumission du formulaire.
  • Un RequiredFieldsobjet prend une liste de noms de champs de formulaire à valider. Comme vous le savez peut-être, la validation est infiniment complexe. Dans ce cas, nous effectuons une validation très basique qui garantit simplement que les champs contiennent des données valides. Chaque champ de formulaire se valide lui-même, donc un EmailFieldvalidera différemment d’un simple TextField.

 

Traitement de la soumission

Dans les FieldListactions de notre formulaire, nous avons spécifié une action de formulaire unique mappée à la méthode sendContactForm. Regardons ce que cette méthode pourrait faire. De nouveau, le code suivant pourrait être dans n’importe quelle Controllerclasse.

 

    public function ContactForm()
     {
        //...
    }

    public function sendContactForm($data, $form)
    {
        $name = $data['YourName'];
        $message = $data['YourMessage'];
        if(strlen($message) < 10) {
            $form->addErrorMessage('YourMessage','Your message is too short','bad');
            return $this->redirectBack();
        }

        return $this->redirect('/some/success/url');
    }

 

Deux méthodes sont définies pour notre méthode de gestionnaire de formulaire:

  • $datacontient un tableau de tous les noms de champs de formulaire mappés sur leurs valeurs, très similaire à ce que vous obtiendriez $_POST.
  • $formest l’objet formulaire que la ContactFormméthode nous a donné. Rappelez-vous que nous devions spécifier le nom de la fonction dans notre constructeur de formulaire? C’est pourquoi. Maintenant, notre gestionnaire de formulaire a pleinement accès à ce formulaire, qui est extrêmement utile.

Voilà donc la vision de haut niveau du fonctionnement des formulaires. Nous allons maintenant envisager de mettre en place un formulaire frontal fonctionnel dans notre projet.

 

Ajout d’un formulaire à un modèle

Examinons à ArticlePage.ssnouveau notre modèle et trouvons le formulaire de commentaire au bas de la page. Faisons de notre mieux pour reproduire ce formulaire dans notre contrôleur.

app / src / ArticlePageController.php

 

//...
use SilverStripe\Forms\Form;
use SilverStripe\Forms\FieldList;
use SilverStripe\Forms\TextField;
use SilverStripe\Forms\EmailField;
use SilverStripe\Forms\TextareaField;
use SilverStripe\Forms\FormAction;
use SilverStripe\Forms\RequiredFields;

class ArticlePageController extends PageController
{

    public function CommentForm()
    {
        $form = Form::create(
            $this,
            __FUNCTION__,
            FieldList::create(
                TextField::create('Name',''),
                EmailField::create('Email',''),
                TextareaField::create('Comment','')
            ),
            FieldList::create(
                FormAction::create('handleComment','Post Comment')
            ),
            RequiredFields::create('Name','Email','Comment')
        );

        return $form;
    }
}

 

Tout cela est très similaire à ce que nous avons fait dans l’exemple. Remarquez que nous laissons les étiquettes des champs délibérément vides. C’est parce que dans la conception, ils sont ajoutés avec des placeholderattributs. Faisons une petite mise à jour pour renseigner les espaces réservés des champs de formulaire.

app / src / ArticlePage.php

 

    public function CommentForm()
    {
        //...
            FieldList::create(
                TextField::create('Name','')
                    ->setAttribute('placeholder','Name*'),
                EmailField::create('Email','')
                    ->setAttribute('placeholder','Email*'),
                TextareaField::create('Comment','')
                    ->setAttribute('placeholder','Comment*')
            ),
        //...
    }

 

S’agissant d’une méthode publique sur le contrôleur, nous pouvons l’ajouter au modèle en appelant $CommentForm. Ajoutez cette variable à la place du balisage de formulaire statique. Actualisez la page et jetez un coup d’oeil.

Ça a l’air horrible, non? Un certain nombre de modifications doivent encore être apportées à notre formulaire afin de l’aligner sur le balisage fourni par le concepteur. Faisons quelques nouvelles mises à jour.

 

public function CommentForm()
{
    $form = Form::create(
        $this,
        __FUNCTION__,
        FieldList::create(
            TextField::create('Name','')
                ->setAttribute('placeholder','Name*')
                ->addExtraClass('form-control'),
            EmailField::create('Email','')
                ->setAttribute('placeholder','Email*')
                ->addExtraClass('form-control'),
            TextareaField::create('Comment','')
                ->setAttribute('placeholder','Comment*')
                ->addExtraClass('form-control')
        ),
        FieldList::create(
            FormAction::create('handleComment','Post Comment')
                ->setUseButtonTag(true)
                ->addExtraClass('btn btn-default-color btn-lg')
        ),
        RequiredFields::create('Name','Email','Comment')
    );

    $form->addExtraClass('form-style');

    return $form;
}

 

Nous utilisons les méthodes chaînables setAttributeet addExtraClasspour les champs principaux et pour le formulaire lui-même, et setUseButtonTagpour l’action de formulaire pour le forcer à rendre un <button>au lieu d’un <input>. Actualisez, et les choses devraient aller beaucoup mieux maintenant.

Cela devient un peu prolixe. Voyons si nous pouvons resserrer tout cela pour ajouter les classes et les espaces réservés supplémentaires de manière dynamique.

 

public function CommentForm()
{
    $form = Form::create(
        $this,
        __FUNCTION__,
        FieldList::create(
            TextField::create('Name',''),
            EmailField::create('Email',''),
            TextareaField::create('Comment','')
        ),
        FieldList::create(
            FormAction::create('handleComment','Post Comment')
                ->setUseButtonTag(true)
                ->addExtraClass('btn btn-default-color btn-lg')
        ),
        RequiredFields::create('Name','Email','Comment')
    )
    ->addExtraClass('form-style');

    foreach($form->Fields() as $field) {
        $field->addExtraClass('form-control')
               ->setAttribute('placeholder', $field->getName().'*');            
    }

    return $form;
}

 

Les méthodes de formulaire sont chaînables, tout comme les méthodes de champ de formulaire, nous avons donc chaîné addExtraClassau constructeur. Nous utilisons la Fields()méthode du formulaire pour obtenir chaque champ par référence, ajouter la classe supplémentaire à chacun et créer un espace réservé dynamique basé sur le nom du champ.

Il s’agit principalement d’une démonstration des méthodes de formulaire. Vous ne voudriez probablement pas faire quelque chose d’agressif dans le code de votre projet car il ne s’adapte pas bien. Imaginez, par exemple, si nous avions un nouveau champ inutile et que l’espace réservé ne devrait pas être accompagné d’un astérisque. Parfois, il est normal d’être verbeux et de se répéter un peu. Vous serez heureux de l’avoir fait lorsque vous devez effectuer de petites mises à jour et gérer les cas critiques.

Si vous êtes un peu consterné de devoir ajouter manuellement toutes les exigences de base pour Bootstrap, soyez assuré qu’il existe un bootstrap-formsmodule qui effectue automatiquement la plupart de ces mises à jour. Nous n’avons pas encore parlé de modules, c’est donc un peu hors de portée pour l’instant, mais sachez que c’est un peu plus complexe que nécessaire.

 

Création d’un modèle de données de commentaire

Lorsqu’un utilisateur soumet un commentaire, nous souhaitons l’enregistrer dans la base de données et l’ajouter à la page. Avant d’aller plus loin avec les formulaires, nous devrons faire une modélisation des données pour stocker tout ce contenu.

Créons un simple ArticleCommentDataObject. Nous avons vu tout cela auparavant. app / src / ArticleComment.php

 

namespace SilverStripe\Lessons;

use SilverStripe\ORM\DataObject;

class ArticleComment extends DataObject
{

    private static $db = [
        'Name' => 'Varchar',
        'Email' => 'Varchar',
        'Comment' => 'Text'
    ];

    private static $has_one = [
        'ArticlePage' => ArticlePage::class,
    ];
}

 

Notez que nous avons le $has_onedos ArticlePagepour établir une $has_manyrelation. Suivons maintenant avec ça.

app / src / ArticlePage.php

 

class ArticlePage extends Page
{

    //...
    private static $has_many = [
        'Comments' => ArticleComment::class,
    ];
    //...
}

 

Courez dev/buildet voyez que vous obtenez une nouvelle table.

Pendant que nous sommes ici, découpons le modèle et ajoutons une boucle pour tous les commentaires. Il n’y a pas de commentaires pour l’instant, mais il y en aura bientôt.

app / templates / Layout / ArticlePage.ss (ligne 72)

 

<div class="comments">
    <ul>
        <% loop $Comments %>                        
        <li>
            <img src="images/comment-man.jpg" alt="" />
            <div class="comment">                                
                <h3>$Name<small>$Created.Format('j F, Y')</small></h3>
                <p>$Comment</p>
            </div>
        </li>
        <% end_loop %>
    </ul>

 

Actualiser et le résultat attendu est qu’aucun commentaire n’apparaisse au-dessus du formulaire.

 

Traitement du formulaire de soumission

Maintenant que nos modèles de données sont configurés, nous pouvons commencer à les utiliser dans notre gestionnaire de formulaire. En regardant notre méthode de formulaire, le nom du gestionnaire que nous avons spécifié est handleComment(). Créons cette méthode, juste en dessous de la méthode de création de formulaire.

app / src / AriticlePageController.php

 

public function CommentForm()
{
    //...
}

public function handleComment($data, $form)
{
    $comment = ArticleComment::create();
    $comment->Name = $data['Name'];
    $comment->Email = $data['Email'];
    $comment->Comment = $data['Comment'];
    $comment->ArticlePageID = $this->ID;
    $comment->write();

    $form->sessionMessage('Thanks for your comment!','good');

    return $this->redirectBack();
}

 

Dans le gestionnaire, nous créons l’ ArticleCommentobjet de manière optimiste lors de la première opération. Nous pouvons le faire car, à ce stade, le formulaire a déjà passé la validation. Nous savons donc que tous les champs obligatoires sont dans le $datatableau. Vous ne pouvez pas toujours vouloir faire cela. Vous pouvez avoir une logique qui détermine le contraire en fonction des valeurs fournies, mais restons simple pour le moment.

Notez que nous créons cette $has_manyrelation en liant le commentaire à la ArticlePage. C’est une étape facile à oublier. Rappelez-vous que les $has_onechamps sont toujours suffixés ID$this->IDdans ce cas, fait référence à l’ID de la page actuelle. Toutes les propriétés d’une page (Title , ContentID, etc.) sont disponibles dans le contrôleur ainsi que le modèle grâce à de SilverStripe SilverStripe\CMS\Controllers\ModelAsControllerclasse.

Essayons de soumettre le formulaire et voyons ce qui se passe.

    Action 'CommentForm' isn't allowed on class SilverStripe\Lessons\ArticlePageController.

Beurk!

Qu’est-ce qu’il se passe ici? Nous arriverons à l’erreur dans un instant, mais pour le moment, il est important de comprendre où nous en sommes et ce que nous examinons.

Jetez un coup d’oeil à l’URL. travel-guides/sample-article-1/CommentForm. Les deux premiers segments sont facilement identifiables. C’est l’URL de notre page d’article actuelle. La dernière partie CommentFormest ce qu’on appelle une action de contrôleur . Par défaut, la partie URL qui suit immédiatement l’URL de la page indiquera au contrôleur d’appeler une méthode portant ce nom. Dans ce cas, nous voulons que la CommentForm()méthode sur notre contrôleur s’exécute, car elle crée leForm objet, qui est ensuite transmis à notre gestionnaire de soumission de formulaire. C’est là que l’essentiel de la magie des formes se déroule dans SilverStripe. Ils soumettent en fait une URL qui les recrée au fur et à mesure de leur rendu à l’utilisateur.

Vous avez peut-être remarqué que j’ai occasionnellement mentionné un détail alarmant du traitement des demandes dans SilverStripe – vous pouvez appeler des méthodes arbitraires dans l’URL. .

Exhaler. Ce n’est pas aussi simple.

En fait, c’est précisément pourquoi nous constatons cette erreur. Nous ne pouvons pas simplement exécuter des méthodes de contrôleur arbitraires à partir de l’URL. La méthode doit être ajoutée à la liste blanche à l’aide d’une variable statique appelée $allowed_actions. Faisons cela maintenant.

app / src / ArticlePage.php

 

//...
class ArticlePageController extends PageController {

    private static $allowed_actions = [
        'CommentForm',
    ];

    //...
}

 

Nous avons modifié une variable statique, nous devons donc exécuter ?flush. Retournez à la page de l’article (ie remove / CommentForm / de l’URL) et exécutez le vidage. Nous ne voulons pas faire cela au milieu d’une soumission de formulaire.

Essayez de soumettre le formulaire à nouveau. Vous devriez maintenant voir votre commentaire posté.

 

Liaison à un objet de données

Allons un peu plus loin. Nous avons parlé de la façon dont les formulaires sont des citoyens de première classe dans SilverStripe. Une partie de cela est d’être conscient du modèle. En regardant notre méthode de gestionnaire, nous voyons que tous les paramètres de formulaire portent le même nom que les ArticleCommentchamps de la base de données. Ceci est idéal, car cela signifie que nous pouvons tirer parti d’une méthode d’économie de temps considérable de la classe de formulaire connue sous le nom de saveInto().

Modifions notre fonction pour appeler saveInto()plutôt que d’affecter manuellement toutes les valeurs de formulaire.

app / src / ArticlePageController.php

 

    public function handleComment($data, $form)
    {
        $comment = ArticleComment::create();
        $comment->ArticlePageID = $this->ID;
        $form->saveInto($comment);
        $comment->write();

        $form->sessionMessage('Thanks for your comment','good');

        return $this->redirectBack();
    }

 

Notez que nous devons toujours attribuer manuellement le ArticlePageIDchamp, car il n’est pas présent dans les données du formulaire. Nous aurions pu le transmettre via une entrée masquée, ce qui éliminerait cette ligne de code.

L’avantage de cette méthode est qu’elle peut réellement répondre aux besoins d’un modèle spécifique. Si notre ArticleCommentobjet avait une méthode appelée saveComment()ousaveName() , il pourrait enregistrer les données de formulaire de manière spécifique. Cela peut donc ressembler à une approche au fusil de chasse, mais cela peut en fait être assez granulaire si vous le souhaitez.

Faire face à la validation

Notre formulaire accepte les soumissions et fonctionne comme prévu, ajoutons donc un peu de validation. Nous utilisons déjà RequiredFieldsnotre principale sentinelle pour lutter contre les données incorrectes, mais que faire si nous voulons ajouter une logique personnalisée qui va au-delà des simples contrôles de cohérence?

 

Ajout d’une logique de validation personnalisée au gestionnaire

Si la logique était vraiment compliquée, nous pourrions écrire notre propre validateur, que nous couvrirons dans le futur, mais pour une validation simple, il est correct de faire tout cela dans votre méthode de gestionnaire de formulaire. Lançons une vérification pour nous assurer que le commentaire de l’utilisateur n’a pas déjà été ajouté. Vous pourriez penser à cela comme une protection anti-spam vraiment élémentaire.

app / src / AritclePage.php

 

    public function handleComment($data, $form)
    {
        $existing = $this->Comments()->filter([
            'Comment' => $data['Comment']
        ]);
        if($existing->exists() && strlen($data['Comment']) > 20) {
            $form->sessionMessage('That comment already exists! Spammer!','bad');

            return $this->redirectBack();
        }        

        // ...
    }

 

Avant de créer l’ Commentobjet, nous inspectons d’abord le $datatableau pour voir si tout se passe bien. Nous recherchons spécifiquement sur cette page un commentaire contenant le même contenu et, le cas échéant, nous ajoutons un message en haut du formulaire. La valeur en 'bad'tant que deuxième argument lui donne une classe CSS appropriée. 'good'est l’autre option ici.

Pour filtrer les faux positifs, nous nous assurons que le commentaire comporte au moins 20 caractères. Il est plausible que plusieurs lecteurs puissent commenter un “bel article” ou un “bon travail” et nous ne voulons pas les punir.

Encore une fois, la leçon à tirer ici ne concerne pas la protection anti-spam, mais seulement la gestion de la validation de formulaire. N’acceptez pas cela comme un évangile sur la façon de sécuriser les commentaires de votre blog.

Essayez de soumettre le formulaire à nouveau avec un commentaire existant et vous verrez que nous générons un message d’erreur.

État de conservation

Il y a un problème de convivialité ici, et peut-être que nous ne devrions pas trop nous inquiéter à ce sujet, car nous ne sommes pas particulièrement motivés pour être gentils avec les spammeurs, mais pour enseigner le concept, il serait bien que le formulaire enregistre son état invalide. , de sorte que l’utilisateur ne doit pas repeupler un formulaire vide. Pour cela, la convention est d’utiliser l’ Sessionétat.

app / src / ArticlePageController.php

 

    public function handleComment($data, $form)
    {
        $session = $this->getRequest()->getSession();
        $session->set("FormData.{$form->getName()}.data", $data);
        //...
        $comment->write();

        $session->clear("FormData.{$form->getName()}.data");
        $form->sessionMessage('Thanks for your comment!','good');

        return $this->redirectBack();
    }

 

Nous créons une SKU en utilisant le nom du formulaire à utiliser comme jeton de session et stockons le $datatableau à cet emplacement. Si tout se vérifie, nous le désactivons pour que le formulaire soit rendu net lors du chargement de la page suivante. Sinon, nous allons vouloir que le formulaire rende les données de la session.

app / src / ArticlePageController.php

 

    public function CommentForm()
    {
        //...

        foreach($form->Fields() as $field) {
            $field->addExtraClass('form-control')
                  ->setAttribute('placeholder', $field->getName().'*');            
        }

        $data = $this->getRequest()->getSession()->get("FormData.{$form->getName()}.data");

        return $data ? $form->loadDataFrom($data) : $form;
    }

 

En utilisant l’opérateur ternaire, nous regardons pour voir s’il $dataexiste. Si c’est le cas, retournez le formulaire avec les données chargées en utilisant loadDataFrom. Sinon, retournez le formulaire tel quel. N’oubliez pas que la plupart des méthodes de formulaire renvoient toutes l’ Formobjet, il est donc normal de renvoyer le résultat d’ loadDataFrom()ici.

Testez votre formulaire et vérifiez qu’il conserve désormais son état après un échec de validation.

TOUT VOIR Ajouter une remarque
VOUS
Ajoutez votre commentaire
 
© Academy EdTech. 2019 All rights reserved.
X