Actions de contrôleur / DataObjects en tant que pages

Dans cette leçon, nous allons présenter le concept d’une action de contrôleur, qui est une route d’URL qui exécute une fonction sur un contrôleur.

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

Ce que nous allons couvrir

  • Que sont les actions du contrôleur et comment sont-elles utilisées?
  • Créer une action de contrôleur pour rendre un objet de données
  • Rendu d’un DataObject en tant que page
  • Ajout du comportement de pseudo-page à un objet de données

 

Comment fonctionnent les actions du contrôleur

Jusqu’à présent, dans notre projet, la plupart des pages se trouvaient sur une seule URL, qui pointait vers un contrôleur unique, qui restituait un seul $Layoutmodèle. Cependant, si vous repensez à notre leçon sur les formulaires, vous vous souviendrez peut-être que nous avons été en mesure d’étendre la route des URL pour notre contrôleur afin de générer et de restituer un formulaire. Nous avons fait cela en utilisant une action de contrôleur. Les formulaires ne sont que l’un des nombreux cas d’utilisation d’une action de contrôleur.

L’utilisation des actions du contrôleur est simple. Nous ne parlons que d’ajouter une partie d’URL à une URL existante qui correspond au nom d’une méthode accessible au public sur le contrôleur. Essayons.

Pour cet exemple, nous allons regarder notre page Régions. Vous verrez que cela se résout http://[your base url]/regions. Essayez d’ajouter un nouveau segment à l’URL, comme http://[your base url]/regions/test. Sans surprise, nous obtenons un 404.

Décomposition de la demande

La raison pour laquelle nous obtenons un 404 pourrait vous surprendre. Jetons un coup d’œil dans les coulisses et voyons comment SilverStripe résout ce problème. En utilisant la même URL, ajoutez ?debug_request.

Regardons ce qui se passe ici.

Testing '$Action//$ID/$OtherID' with 'test' on SilverStripe\Lessons\RegionsPageController

Dès le départ, nous pouvons constater que SilverStripe a résolu notre URL RegionsPageController, ce qui peut surprendre, car l’URL de cette page n’inclut pas /test/, mais il s’est passé que le gestionnaire de demandes a trouvé une correspondance pour l’URL et supposons qu’à partir de ce moment, tout ce qui se trouve dans l’URL est un paramètre transmis au contrôleur. Par défaut, un contrôleur vous donne trois paramètres supplémentaires à transmettre au-delà de son URL de base, comme nous pouvons le voir dans notre sortie de débogage.

  • $Action: Suit immédiatement l’URL. Dans ce cas, notre action est test.
  • $ID: Un identifiant que l’action du contrôleur peut vouloir utiliser. Cette valeur ne doit pas nécessairement être numérique. C’est arbitraire, et juste nommé IDparce que c’est un cas d’utilisation courant.
  • $OtherID: Identique à ID. Vous en avez deux.

Vous n’êtes pas limité à cette signature de paramètres. Dans les prochaines leçons, nous verrons comment créer des règles d’URL personnalisées, mais par défaut, c’est ce que vous obtenez et c’est souvent tout ce dont vous avez besoin.

Regardons la prochaine ligne de sortie de débogage.

Rule '$Action//$ID/$OtherID' matched to action 'handleAction' on SilverStripe\Lessons\RegionsPageController. Latest request params: array ( 'Action' => 'test', 'ID' => NULL, 'OtherID' => NULL, )

Donc nous en sommes là. Le gestionnaire de demandes a effectivement correspondu au $Action/$ID/$OtherIDmodèle et tente de résoudre notre action test. Dans le reste de la sortie, vous pouvez constater qu’il ne le fait pas et génère un ErrorPage.

Pourquoi a-t-il échoué? Comme nous l’avons dit précédemment, le $Actionparamètre devrait représenter une fonction accessible au public sur le contrôleur. Nous n’avons aucune méthode appelée en testce moment.

Ajoutons cette méthode de contrôleur maintenant.

app /src /RegionsPageController.php

 

namespace SilverStripe\Lessons;

use PageController;

class RegionsPageController extends PageController
{

  public function test()
  {
        die('it works');
    }

}

Actions autorisées

Maintenant, essayez d’accéder à l’URL /regions/test. C’est encore 404s. Que se passe t-il ici?

Si vous vous souvenez de notre tutoriel sur les formulaires de la leçon 11, nous n’avons pas encore terminé. Nous devons ajouter la testméthode à la liste blanche comme pouvant être invoquée via l’URL. Vous pouvez imaginer le risque de sécurité qui serait imposé en permettant à toutes les méthodes publiques d’un contrôleur d’être invoquées de manière arbitraire dans l’URL. Nous ne voulons pas ça. Par défaut, aucune méthode n’est autorisée à être appelée via des actions du contrôleur. Vous devez spécifier une liste de ceux qui se trouvent dans une variable statique privée appelée $allowed_actions.

 

 

namespace SilverStripe\Lessons;

use PageController;

class RegionsPageController extends PageController {

    private static $allowed_actions = [
        'test'
    ];

    public function test()
    {
        die('it works');
    }

}

 

$allowed_actionspeut effectivement devenir assez complexe. Vous pouvez mapper ces méthodes sur les niveaux d’autorisation requis, et même sur des fonctions personnalisées permettant d’évaluer si elles doivent être accessibles au moment de l’exécution, ce qui est très utile pour les contrôleurs complexes. Dans ce cas, nous voulons simplement nous assurer que quiconque peut invoquer l’ testaction.

Actualiser la page avec un ?flush , car nous avons changé une variable statique privée. Maintenant ça marche.

 

Création d’une action de contrôleur pour restituer un objet de données

L’utilisation la plus courante d’une action de contrôleur consiste à affecter une URL à un objet de données imbriqué dans une page. C’est, à mon avis, l’un des premiers jalons pour devenir un développeur SilverStripe qualifié.

Nous savons que DataObjects sont plus primitifs que les objets Page. Ils ne contiennent aucune des fonctionnalités permettant de rendre un modèle, ils n’ont pas de Link()méthode, pas de balises méta, pas de contrôleurs, etc. En bref, ils ne sont pas censés être rendus sous forme de pages complètes. Cela ne signifie toutefois pas que vous ne pouvez pas leur attribuer certaines des propriétés nécessaires pour le faire. En fait, cela fait souvent beaucoup de sens.

Gardons le focus sur notre RegionsPage. Nous avons une liste de RegionDataObjects qui sont liés à la page viahas_many . Nous voulons créer une vue détaillée pour chacune des régions de notre liste. L’utilisateur doit pouvoir cliquer sur l’une des régions et voir plus d’informations.

Ce n’est pas un cas d’utilisation idéal pour un objet de données sous forme de page. Ces objets Région pourraient tout aussi bien être des pages dans l’arborescence du site. Cela revient souvent à un jugement pour le développeur, guidé par ce qui fonctionnera le mieux pour l’éditeur de contenu. Dans un prochain tutoriel, nous verrons Propertycomment créer une page de détail pour notre DataObject, qui, en raison de son volume, sera beaucoup plus efficace que de le gérer en tant que pages.

 

Ajout d’une méthode Link ()

Nous pouvons commencer par l’exigence la plus fondamentale. Les régions doivent pouvoir créer un lien distinct vers leur page de détail. Ajoutons une Link()méthode à chaque région. Nous lui demanderons d’appeler une action de contrôleur que nous n’avons pas encore définie.

namespace SilverStripe\Lessons;

use SilverStripe\ORM\DataObject;

class Region extends DataObject
{
  //...
    public function Link()
    {
        return $this->RegionsPage()->Link('show/'.$this->ID);
    }
}

 

Nous obtenons le RegionsPagepropriétaire de cette région via la has_manyhas_oneparité et appelons sa méthode link. Nous transmettons des segments d’URL supplémentaires que nous souhaitons ajouter à son lien. Nous précisons un $Actionde spectacle et un $IDqui représente l’ID de la région.

Maintenant que nous avons cette méthode, nous l’appliquerons au modèle. Modifiez tous les liens de hachage (#) en $Link.

app / templates / SilverStripe / Lessons / Layout / RegionsPage.ss

 

<% loop $Regions %>
<div class="item col-md-12"><!-- Set width to 4 columns for grid view mode only -->
    <div class="image image-large">
        <a href="$Link">
            <span class="btn btn-default"><i class="fa fa-file-o"></i> Read More</span>
        </a>
        $Photo.CroppedImage(720,255)
    </div>
    <div class="info-blog">
        <h3>
            <a href="$Link">$Title</a>
        </h3>
        <p>$Description</p>
    </div>
</div>
<% end_loop %>

 

Essaie. Cliquez sur l’une des régions. Le résultat attendu devrait être un 404.

Obtenir le DataObject dans l’action

Heureusement, nous savons comment résoudre ce problème 404 maintenant. Créons une showméthode RegionsPageControlleret la mettons en liste blanche $allowed_actions.

 

// ...
use SilverStripe\Control\HTTPRequest;

class RegionsPageController extends PageController
{

    private static $allowed_actions = [
        'show'
    ];

    public function show(HTTPRequest $request)
    {

    }

}

 

Nous ne faisons rien de nouveau ici, sauf que nous nous assurions que la showméthode obtienne son HTTPRequestargument. Nous aurons besoin de cet objet pour obtenir l’identifiant.

Maintenant que nous avons le squelette de la façon dont cela va fonctionner, nous allons construire la showméthode pour extraire et renvoyer la région demandée.

 


    public function show(HTTPRequest $request)
    {
        $region = Region::get()->byID($request->param('ID'));

        if(!$region) {
            return $this->httpError(404,'That region could not be found');
        }

        return [
            'Region' => $region
        ];
    }

}

 

Cela devrait être assez intuitif, mais parcourons-le.

  • Nous obtenons la région par l’ID contenu dans le IDparamètre request. Si ce paramètre est null, nous n’avons pas à nous inquiéter. La byID()méthode échoue gracieusement.
  • Si une région n’existe pas, retournez un 404.
  • Renvoie une nouvelle variable $Regionau modèle. (nous en traiterons ensuite)

 

Rendu d’un DataObject en tant que page

Comme nous l’avons vu dans la sortie de débogage du gestionnaire de demandes, le $Actionparamètre est mappé à une méthode appelée handleActionsur notre contrôleur. Bien que notre méthode d’action elle-même soit conçue pour faire tout ce dont elle a besoin, la handleAction()méthode qui invoque cette méthode est quelque peu opinionée. Plus précisément, il sélectionnera automatiquement un modèle pour nous, sauf indication contraire de notre part.

Une action du contrôleur essaiera de rendre un modèle conformément à la convention de dénomination [PageType]_[actionName].ss. Dans notre cas, cela nous donne RegionsPage_show.ss. Créons ce modèle.

Copiez votre app/templates/Layout/Page.ssà app/templates/Silverstripe/Lessons/Layout/RegionsPage_show.ss. Supprimez le <div class="main ...">bloc et à sa place, restituez du contenu à partir de l’ $Regionobjet que nous avons transmis. C’est une excellente occasion d’utiliser le<% with %> bloc.

app / templates / SilverStripe / Lessons / Layout / RegionsPage_show.ss (ligne 5)

 

 

<div class="main col-sm-8">
    <% with $Region %>
        <div class="blog-main-image">
            $Photo.SetWidth(750)
        </div>
        $Description
    <% end_with %>
</div>

 

Essayez de cliquer sur une région maintenant et voyez que vous obtenez sa page de détail.

Ce qui est un peu étrange en ce moment, c’est que le $Descriptionchamp est présenté exactement de la même manière dans la vue liste que dans la vue détaillée, ce qui rend ce clic réellement inutile. Mettons à jour l’ Regionobjet de données pour qu’il stocke son Descriptionchamp en tant que HTMLTextchamp afin qu’il puisse éventuellement être beaucoup plus long.

app / src / Region.php

 

 

namespace SilverStripe\Lessons;

use SilverStripe\ORM\DataObject;

class Region extends DataObject
{

    private static $db = [
        'Title' => 'Varchar',
        'Description' => 'HTMLText',
    ];

Courez dev/build.

Nous devrons également mettre à jour le champ CMS pour Description.

    public function getCMSFields()
    {
        $fields = FieldList::create(
            TextField::create('Title'),
            HtmlEditorField::create('Description'),
            $uploader = UploadField::create('Photo')
        );
    //...
  }

 

Maintenant RegionsPage.ss, utilisons simplement$Description.FirstParagraph .

 

Ajout du comportement de pseudo-page à un objet de données

Il manque encore quelques éléments pour que cet objet de données devienne vraiment une page. Le problème le plus criant est que le titre de la page est toujours Régions , plutôt que le titre plus approprié de la région que nous examinons. Normalement, nous trouvions la $Titlevariable dans notre modèle et la changions simplement en $Region.Title, mais cette variable ne réside pas dans le RegionsPage_show.ssmodèle, nous devrons donc la remplacer dans le contrôleur.

 

Surcharge des propriétés du modèle dans le contrôleur

Rappelez-vous le tableau que nous avons passé au modèle contenant notre variable personnalisée $Region? Nous pouvons l’utiliser pour surcharger les propriétés que le modèle devrait normalement déduire du modèle. AjoutonsTitle à cette liste.

app / src / RegionsPageController.php

 

    public function show(HTTPRequest $request)
    {
    //...
        return [
            'Region' => $region,
            'Title' => $region->Title
        ];
    }

 

Actualisez la page et voyez que nous obtenons un nouveau titre.

Bien que le nouveau titre soit affiché sur la page elle-même, cela n’affecte pas la <title>balise. En effet, à la leçon 3, nous avons confié le contrôle de la balise de titre à $MetaTags. Dans cette leçon, nous avons discuté de la possibilité de passer un paramètre falseà la $MetaTagsfonction pour supprimer la balise de titre et de la personnaliser comme bon nous semble. Faisons cela maintenant.

app / templates / Page.ss (ligne 8)

 

    $MetaTags(false)
    <title>One Ring Rentals: $Title</title>

 

Actualisez la page et vérifiez que la balise de titre fonctionne maintenant.

 

Créer une navigation entre pairs

Une autre amélioration que nous pouvons apporter est la perception de la hiérarchie. Nous pouvons utiliser notre section de sous-navigation pour afficher toutes les régions homologues, avec certains états appliqués à la région actuelle.

app / templates / SilverStripe / Lessons / Layout / RegionsPage_show.ss (ligne 15)

 

<div class="sidebar gray col-sm-4">
    <h2 class="section-title">Regions</h2>
    <ul class="categories subnav">
        <% loop $Regions %>
            <li class="$LinkingMode"><a class="$LinkingMode" href="$Link">$Title</a></li>
        <% end_loop %>
    </ul>
</div>

 

N’oubliez pas que, même si le contenu est entièrement régi par l’ Regionobjet, nous sommes toujours dans la portée de RegionsPageController, nous intervenons donc <% loop $Regions %>pour obtenir la has_manyrelation que nous utilisons également dans la vue liste.

Actualisez la page et vérifiez que toutes les régions sont maintenant affichées.

 

Ajout d’état de navigation

Il nous manque encore l’état “actuel” de la région. En effet, la méthode $LinkingModen’existant pas par défaut sur un objet de données, nous devons donc écrire le nôtre.

app / src / Region.php

 

//..
use SilverStripe\Control\Controller;

class Region extends DataObject
{
  //...

    public function LinkingMode()
    {
        return Controller::curr()->getRequest()->param('ID') == $this->ID ? 'current' : 'link';
    }
}

 

Rappelez-vous que nous sommes dans le contexte d’un simple DataObject, nous ne sommes donc pas au courant de la demande. Controller::curr()est une méthode utile qui nous permet d’obtenir le contrôleur actuellement actif. A partir de cet objet, nous pouvons obtenir l’objet de requête qui lui a été attribué et le rechercher de ->param('ID')la même manière que dans notre show()action. Si l’ID dans l’URL correspond à cette région, nous retournons current, sinon nous revenons link. Nous n’avons pas à nous soucier sectionde quelque chose d’aussi simple.

Actualisez la page et vérifiez que la région actuelle est maintenant indiquée.

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