Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Exercices] Liste des exercices à réaliser #1

Open
hhamon opened this issue Jan 15, 2016 · 1 comment
Open

[Exercices] Liste des exercices à réaliser #1

hhamon opened this issue Jan 15, 2016 · 1 comment

Comments

@hhamon
Copy link
Owner

hhamon commented Jan 15, 2016

Travaux Pratiques à Réaliser

Les sections suivantes décrivent les différents exercices à réaliser et à rendre sous la forme d'une pull request Github avant le mardi 23 février 2016 à 23:59:59, heure de Paris.

Exercice 1 : Routes au Format YAML ou JSON

Le framework actuel supporte la définition des routes de l'application dans les formats de configuration PHP et XML. Il vous est demandé d'implémenter, au choix, le support des routes au format JSON ou YAML. Néanmoins, la contrainte imposée pour ces formats consiste à suivre le formalisme suivant :

# app/config/routes.yml
homepage:
    path: /home
    params: { _controller: "Application\\Controller\\HomePageAction" }
    methods: [ GET, POST ]

# ...
# app/config/routes.json
{
    "routes": {
        "homepage": {
            "path": "/home",
            "params": {
                "_controller": "Application\\Controller\\HomePageAction"
            },
            "methods": [ "GET", "POST" ]
        }
    }
}

Vous devrez bien sûr livrer avec le code qui réalise cette fonctionnalité les tests unitaires qui prouvent son bon fonctionnement comme c'est le cas actuellement dans le dépôt de code.

Exercice 2 : Création de Blog Post

L'application doit proposer une page pour ajouter un nouveau blog post à la liste actuelle. Pour cet exercice, il vous est demandé de répondre aux exigences suivantes :

  • Vérifier que tous les champs du formulaire soient bien remplis,
  • Réafficher le formulaire avec les bons messages d'erreur en cas d'erreur,
  • Insérer les données de l'article en base de données avec une transaction SQL,
  • Rediriger l'utilisateur vers la page de l'article inséré.

Pour cet exercice, vous serez évalué sur le respect du principe MVC. Vous devrez faire attention à mettre le code au bon endroit.

Astuce : N'hésitez pas à créer de nouveaux composants génériques dans l'espace de nommage du framework !

Exercice 3 : Articles en Markdown

Dans cet exercice, il vous est demandé de stocker les contenus des articles au format Markdown. Markdown est le format textuel utilisé pour écrire et formater les différentes parties du fichier README.

Pour ne pas réinventer la route, vous devrez choisir une bibliothèque de code tierce pour analyser du Markdown et le transformer en chaîne HTML correspondante.

De plus, la base de données devra contenir pour chaque article, le contenu Markdown et sa version HTML. La version Markdown sert à pouvoir éditer l'article tandis que la version HTML sert à alimenter la vue Twig.

Vous devrez répondre aux exigences suivantes pour réaliser cet exercice :

  • Mettre à jour le schéma de votre base de données et conserver dans un fichier SQL la requête de modification du schéma,
  • Télécharger une bibliothèque de code PHP tierce de votre choix pour transformer du contenu Markdown en contenu HTML,
  • Transformer le contenu Markdown en HTML à chaque nouvelle sauvegarde de l'article en base de données,
  • Afficher dans la vue la version HTML correspondant au Markdown sauvegardé.

Astuce : pensez à utiliser Composer et le site Packagist.org pour gérer le code tiers !

Exercice 4 : Sécurité des Accès

Afin de sécuriser certaines pages du site, il est demandé de réaliser un système d'authentification et de gestion de droits d'accès. Chaque compte utilisateur doit avoir au moins un identifiant unique, un mot de passe et une liste de permissions associées. Le mot de passe doit obligatoirement être encrypté avec un algorithme de hachage de votre choix (md5, sha1, bcrypt, etc.) et une graine aléatoire (seed ou salt).

Vous êtes libre de stocker les identifiants utilisateurs et les permissions associées où vous le souhaitez (fichier YAML, fichier XML, base de données, etc.).

Seulement deux pages doivent être sécurisées par le système :

  • La page à l'URL /dashboard nécessite seulement d'être identifié, peu importe les permissions associées au compte utilisateur,
  • La page de création d'un blog post créée à l'exercice 2 nécessite d'être authentifié avec une permission AUTHOR.

Le système d'authentification doit répondre aux deux exigences suivantes :

  • Si l'on tente d'accéder à une page sécurisée sans être authentifié, la requête est automatiquement redirigée vers la page de connexion (url: /login).
  • Si l'on tente d'accéder à une page sécurisée en étant authentifié mais sans avoir les bonnes permissions, la requête est redirigée ou génère une réponse de type 403 (Forbidden). Une vue personnalisée doit être développée pour ce type de réponse.

Astuce : pensez à utiliser le gestionnaire d'événements et l'événement KernelEvents::REQUEST pour brancher le système de sécurité. Aussi, le nouveau service session peut vous aider pour la persistance des données entre deux requêtes HTTP.

Exercice 5 : Générateur d'URLs

Pour ce cinquième exercice, il vous est demandé de modifier le composant Routing afin de proposer un service de génération d'URLs basé sur la configuration des routes. Cet objet doit être disponible depuis n'importe quel contrôleur (action) de votre application afin de pouvoir générer des URLs.

Vous devez proposer une implémentation de l'interface Framework\Routing\UrlGeneratorInterface capable de générer des urls en fonction de la configuration des routes.

Considérez la route suivante :

<?xml version="1.0" encoding="UTF-8" ?>
<routes>
    <route name="blog_post" path="/blog/article-{id}.html" methods="GET">
        <param key="_controller">Application\Controller\Blog\GetPostAction</param>
        <requirement key="id">\d+</requirement>
    </route>
</routes>

Pour chaque route configurée de votre application, votre implémentation de générateur d'URL doit être capable de se comporter de la manière suivante :

# Invalid, must throw exception for missing required parameters.
$url = $generator->generate('blog_post');

# $url == '/index.php/blog/article-42.html'
$url = $generator->generate('blog_post', ['id' => '42']);

# $url == '/index.php/blog/article-42.html?page=2'
$generator->generate('blog_post', ['id' => '42', 'page' => 2]);

# $url == 'http://your-domain-name.tld/index.php/blog/article-42.html'
$url = $generator->generate('blog_post', ['id' => '42'], UrlGeneratorInterface::ABSOLUTE_URL);

# $url == 'http://your-domain-name.tld/index.php/blog/article-42.html?page=2'
$generator->generate('blog_post', ['id' => '42', 'page' => 2], UrlGeneratorInterface::ABSOLUTE_URL);

Dans l'URL générée, le contrôleur frontal index.php ne doit pas apparaître si l'URL appelée dans votre navigateur ne le contient pas. C'est le cas par exemple si votre serveur Apache (ou NGinx) est configuré pour faire de la réécriture automatique d'URLs grâce à un fichier de configuration .htaccess.

Pour valider que votre classe de générateur d'URL fait bien son travail, vous devrez fournir avec une série de tests unitaires qui couvrent notamment les exemples donnés juste au dessus.

En guise de bonus, les plus téméraires d'entre vous peuvent s'essayer à l'écriture d'une classe d'extension Twig (voir documentation officielle) qui fournit deux nouvelles fonctions path() et url() dans tous les templates. La première doit générer des URLs relatives tandis que la seconde doit générer des URLs absolues. Le bout de code ci-dessous illustre le fonctionnement de ces deux nouvelles fonctions Twig :

<a href="{{ path('blog_post', { 'id': 42, 'page': 2 }) }}">Read</a>
{# <a href="/index.php/blog/article-42.html?page=2">Read</a> #}

<a href="{{ url('blog_post', { 'id': 42, 'page': 2 }) }}">Read</a>
{# <a href="http://your-domain-name.tld/index.php/blog/article-42.html?page=2">Read</a> #}

Enfin, profitez-en pour refactoriser dans votre code tous les endroits dans lesquels vous auriez manuellement généré des URLs en remplaçant ces appels manuels par ceux de votre service de génération d'URLs.

Astuce : pensez à réutiliser, voire enrichir, les objets RouteCollection et RequestContext du composant Routing.

Exercice 6 : Syntaxe Alternative des Contrôleurs

Dans ce dernier exemple, il s'agit au framework de vous proposer une syntaxe alternative pour configurer vos routes et leurs contrôleurs associés. Par exemple, au lieu de spécifier le chemin complet de la classe, il serait plus judicieux de proposer la syntaxe alternative abstraite suivante :

<?xml version="1.0" encoding="UTF-8" ?>
<routes>
    <route name="homepage" path="/" methods="GET">
        <param key="_controller">App:Homepage</param>
    </route>
    <route name="blog_post" path="/blog/article-{id}.html" methods="GET">
        <param key="_controller">App:Blog:GetPost</param>
        <requirement key="id">\d+</requirement>
    </route>
</routes>

Au chargement des routes, c'est alors au framework de se charger d'analyser la syntaxe alternative et d'en déduire la vraie classe de contrôleur à instancier. Ce mécanisme à développer doit être capable de traduire le chemin App:Homepage en Application\\Controller\\HomepageAction et le chemin App:Blog:GetPost en Application\\Controller\\Blog\\GetPostAction.

Bien sûr le comportement actuel doit toujours être garanti ! Par conséquent, si une route est configurée avec un vrai namespace de classe, il est alors inutile de chercher à l'analyser et le transformer.

Pour valider vos changements dans le code du framework, il vous est aussi demandé de livrer une suite de tests unitaires. Cette suite de tests unitaires doit toujours faire passer les anciennes configurations de route avec des namespaces de classes de contrôleurs ainsi que les nouvelles avec la notation raccourcie abstraite.

Astuce : attention à ne pas surcharger les responsabilités de l'objet ControllerFactory !

LGiry referenced this issue in LGiry/lpdim2016 Feb 22, 2016
JosePathe pushed a commit to JosePathe/lpdim2016 that referenced this issue Feb 22, 2016
RomainOliva added a commit to RomainOliva/lpdim2016 that referenced this issue Feb 22, 2016
@hhamon
Copy link
Owner Author

hhamon commented Mar 13, 2016

La correction des 6 exercices se trouve dans la branche correction - #11

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant