Skip to content

Latest commit

 

History

History
509 lines (363 loc) · 14.8 KB

vuejs.md

File metadata and controls

509 lines (363 loc) · 14.8 KB

PHP 8

En préambule, quelques explications sur les nouveautés PHP8 et PHP8.1

Les références :

https://stitcher.io/blog/new-in-php-8 https://stitcher.io/blog/php-8-match-or-switch https://stitcher.io/blog/new-in-php-81 https://stitcher.io/blog/php-enums https://stitcher.io/blog/php-81-in-8-code-blocks

VueJS

Objectif : Mettre en place une application simple, basée sur VueJS, permettant d'afficher un catalogue, et de le gérer (DUTAF pour les MMI). Pour cela on va se baser sur un fournisseur d'API basé sur APIPlaform et Symfony mis en place lors de la séance précédente. Vous devrez peut être modifier et adapter le code pour fournir les données nécessaires.

Installation de VueJS

Le plus simple est de passer par Vue-Cli (que vous avez peut être déjà installé sur la séance précédente).

Pour créer un nouveau projet, tapez la commande suivante :

vue create votre-projet

Et répondez aux différentes questions. Activez le "router" (Vue Router).

Vous pouvez sauvegarder le preset pour d'autres projets si besoin.

/!\ Vous pourriez aussi utiliser vue ui pour obtenir une interface graphique.

Explications des fichiers et de la structure

Premières manipulations.

Dans le composant App.vue qui est créé par défaut, et qui est le point d'entrée de votre application, nous allons faire les premiers tests.

Nous allons définir une liste de 3 éléments, par exemple :

<ul>
  <li>Note sur Symfony : 19</li>
  <li>Note en intégration : 12</li>
  <li>Note en réseau : 14</li>
</ul>

Si on souhaite rendre cette liste "dynamique", on peut définir des variables pour les notes. La syntaxe est identique à Twig pour les variables...

<ul>
  <li>Note sur Symfony : {{ symfony }}</li>
  <li>Note en intégration : {{ integration }}</li>
  <li>Note en réseau : {{ reseau }}</li>
</ul>

Si vous testez de nouveau ce code, vous aurez une erreur car les variables n'existent pas. Nous devons les définir.

Pour cela, dans la partie javascript de notre fichier App.vue, nous allons définir une "entrée" data, qui va contenir nos valeurs.

La déclaration pourrait être :

<script>
export default {
  name: 'App',
  data: () => {
    return {
      symfony: 6,
      integration: 2,
      reseau: 8,
    }
  },
}
</script>

Exercice

Ajoutez une quatrième ligne qui calcule la moyenne de ces 3 notes.

Les boucles

Cette solution, fonctionnelle, n'est pas très pratique car se limite à 3 notes. On peut donc manipuler des objets ou tableaux. Pour cela, on va définir un objet notes, contenant plusieurs notes.

La déclaration d'un objet se fait de manière classique en javascript, dans la partie data de votre partie script. Exemple :

<script>
export default {
  name: 'App',
  data: () => {
    return {
      notes: {
        "Symfony": 12,
        "Réseau": 14,
        "Intégration": 8,
        "Maths": 19,
        "Anglais": 12
      }
    }
  },
}
</script>

L'affichage avec une boucle, nommée v-for dans VueJs se ferait par exemple de la manière suivante :

<ul>
  <li v-for="(matiere, note) in notes" :key="matiere">Note sur {{matiere}} : {{ note }}</li>
</ul>

Exercice

Calculez la moyenne des notes.

  • Une solution consiste à faire de nouveau une boucle pour calculer la moyenne dans la partie "html", pas conseillé,
  • Une autre solution consiste à utiliser les Propriétés calculées, en vous basant sur la documentation, proposez une méthode pour calculer la moyenne et afficher le résultat.

Tests

Les tests se font avec l'instruction v-if. Exemple, issue de la documentation :

<h1 v-if="awesome">Vue est extraordinaire !</h1>

Affichera le message selon la valeur de la variable "awesome". Concrétement, le titre H1 sera visible si awesome est vrai. Dans le cas contraire, rien ne s'affiche (et le code n'existe pas dans la source HTML !).

Il existe un v-else, et on pourrait écrire :

<h1 v-if="awesome">Vue est extraordinaire !</h1>
<h1 v-else>Oh non 😢</h1>

Le v-if (tout comme le v-for), peut s'appliquer sur toutes les balises HTML. Y compris la balise . Les tests peuvent bien sûr être plus complexe que simplement une variable booléenne, et la syntaxe des conditions et des opérateurs est identique au javascript.

Il existe de manière assez identique l'instruction v-show, qui fonctionne de manière assez similaire, mais qui laisse le code apparaître dans la source HTML (masqué ou non (display:none) selon l'état de la condition).

Vous trouverez sur ce lien des éléments d'explications sur comment et quand choisir v-if ou v-show.

Créer des composants

Tout l'intéret des framework du type VueJs est la notion de composant, qui sont des "morceaux" de page, qui contiennent une logique (du HTML, du js et du CSS). Ces composants peuvent être très simplement réutilisés, en récupérant des "paramètres".

Exemple :

Composant "Bonjour"

<template>
  <p>Bonjour</p>
</template>

<script>
export default {
  name: 'Bonjour'
}
</script>

<style scoped>
p {
  color: #42b983;
}
</style>

Et son utilisation dans une page (ou d'autres composants)

...
<Bonjour />
...

Il est possible de passer des paramètres :

<template>
  <p>{{ msg }}</p>
</template>

<script>
export default {
  name: 'Bonjour',
  props: {
    msg: String
  }
}
</script>

<style scoped>
p {
  color: #42b983;
}
</style>

Et son utilisation dans une page (ou d'autres composants)

...
<Bonjour msg="Bonjour !" />
<Bonjour msg="VueJs C'est super" />
...

Exercices

Créer des composantes pour :

  • Un champ de formulaire de type "text" comprenant :
    • un label, une zone de saisie, et une classe, si le champ est obligatoire ou non
  • Une liste déroulante de formulaire comprenant :
    • Un label, des données (tableau json), et une classe, si le champ est obligatoire ou non

Créer des routes

Principes

La logique de route dans VueJs est la suivante. Vous devez définir une "zone" où seront chargées les pages en fonction des URL (<router-view></router-view>). Les liens (<router-link></router-link>) feront le lien entre un composant (une partie de page), et l'endroit où l'insérer.

Installation

Documentation officielle : https://router.vuejs.org/

Pour ajouter vue-router (déjà fait normalement lors de l'installation) :

npm install vue-router

Il faut ensuite l'activer dans votre projet :

  
import Vue from 'vue'
import VueRouter from 'vue-router'

Vue.use(VueRouter)

On peut ensuite l'utiliser comme par exemple dans le code ci-dessous qui définit deux routes :

<div id="app">
  <h1>Hello App!</h1>
  <p>
    <!-- use router-link component for navigation. -->
    <!-- specify the link by passing the `to` prop. -->
    <!-- `<router-link>` will be rendered as an `<a>` tag by default -->
    <router-link to="/foo">Go to Foo</router-link>
    <router-link to="/bar">Go to Bar</router-link>
  </p>
  <!-- route outlet -->
  <!-- component matched by the route will render here -->
  <router-view></router-view>
</div>

Le router-view est l'endroit ou se chargera la page associée au lien. Vous devez donc le placer au bon endroit dans votre structure de site. Les balises router-link sont les liens, vous devez les placez dans votre menu ou dans l'endroit désiré. l'attribut to, permet de définir l'URL du composant à chargé. On pourrait aussi manipuler un nom de route.

Dans l'état rien ne se passera, car l'url /foo ou /bar n'est pas associé à un composant. Vous devez donc ajouter le javascript associé :

Exemple, en définissant les routes dans le main.js

  // 0. If using a module system (e.g. via vue-cli), import Vue and VueRouter
// and then call `Vue.use(VueRouter)`.

// 1. Define route components.
// These can be imported from other files
const Foo = { template: '<div>foo</div>' }
const Bar = { template: '<div>bar</div>' }

// 2. Define some routes
// Each route should map to a component. The "component" can
// either be an actual component constructor created via
// `Vue.extend()`, or just a component options object.
// We'll talk about nested routes later.
const routes = [
  { path: '/foo', component: Foo },
  { path: '/bar', component: Bar }
]

// 3. Create the router instance and pass the `routes` option
// You can pass in additional options here, but let's
// keep it simple for now.
const router = new VueRouter({
  routes // short for `routes: routes`
})

// 4. Create and mount the root instance.
// Make sure to inject the router with the router option to make the
// whole app router-aware.
const app = new Vue({
  router
}).$mount('#app')

// Now the app has started!

Autres concepts

Il est bien sûr possible d'avoir des fichiers js contenant l'ensemble de nos routes, et d'importer ce fichier dans le main.js pour le charger dans notre projet.

Exercice

Créer les routes permettant de gérer les articles, les fournisseurs et la page d'acceuil. Créer les composants des différentes "pages" nécessaires.

Repartir sur des bonnes bases.

Pour avoir la même base et la même solution, vous allez refaire un projet Symfony. On va utiliser la version "website" qui contient toutes les dépendances nécessaires.

composer create-project symfony/website-skeleton nomDuProjet
cd nomDuProjet
composer require api
cp .env .env.local
nano .env.local (modifier votre ligne de connexion à la BDD).
bin/console d:d:c (création de la BDD)

Créer deux entités.

  • Category

  • Un libellé, texte, non null

  • Une couleur, texte, non null

  • Message

  • Un titre, texte, non null

  • Une date de publication, datetime

  • Un message, longtext, non null

  • Une catégoie (ManytoOne)

Associez ces deux entités à ApiPlatform. Insérez quelques données dan la base de données (directement en phpMyAdmin), et testez que tout fonctionne avec Postman.

Installation d'Axios

On va utiliser la librairie Axios pour faire des requêtes à notre API (on pourrait utiliser Fetch).

La librairie se trouve ici : https://www.npmjs.com/package/axios

Et l'installation se fait avec la ligne suivante (en étant dans le répertoire de votre projet)

npm install axios

(vous pouvez utiliser Yarn).

Manipulation de l'API

Axios permet d'effectuer toutes les requêtes REST classique :

Extrait de la documentation
Request method aliases
For convenience aliases have been provided for all supported request methods.

axios.request(config)
axios.get(url[, config])
axios.delete(url[, config])
axios.head(url[, config])
axios.options(url[, config])
axios.post(url[, data[, config]])
axios.put(url[, data[, config]])
axios.patch(url[, data[, config]])

Création d'un service

Une bonne pratique consiste à définir un fichier contenant nos "requêtes" Axios (ou appels à une API de manière général). Généralement un fichier par "entité".

Le fichier ci-dessous, permet d'executer quelques requêtes vers une entité Article de notre API

import axios from 'axios'

const BASE_URL = 'http://localhost:8888/lpdev2021/public/index.php/api/articles'

async function getArticles()
{
    return await axios.get(BASE_URL);
}

async function getArticle(id)
{
  return await axios.get(BASE_URL+'/'+id);
}

async function postArticle(data)
{
  return await axios.post(BASE_URL, data);
}

export {getArticles, getArticle, postArticle}

L'interet est de n'avoir qu'une seule fois l'URL de notre API pour article, et donc de pouvoir rapidement mettre à jour. On pourrait même centraliser ces URL dans un seul et unique fichier. Ce fichier est à mettre dans un repertoire nommé services ou api, ...

Exercices

En reprenant l'exemple ci-dessous.

Ecrire un fichier pour récupérer vos messages et vos catégories (ou équivalent avec le sujet "avancé").

Ces fichiers vont contenir les méthodes suivantes :

  • Récupérer tous les éléments (get)
  • Récupérer un élément par id (get)
  • Créer un élément (post)
  • Supprimer un élément par id (delete)
  • Modifier un élément par id (put)

Dans un premier temps ajouter les méthodes dans les deux fichiers et ajuster les lignes avec axios pour gérer les différents cas.

Récupérer les Catégories

Dans une page Categorie.vue importez le fichier js permettant de manipuler l'API.

Vous pourriez avoir une page de ce type :

<template>
  <div class="about">
    <h1>Liste des Catégories</h1>
    ...Afficher les catégories ici ...
  </div>
</template>

<script>
import { getCategories } from '../services/categories';

export default {
  name: 'Categories',
  data () {
    return {
      categories: null
    }
  },
  async mounted () {
    this.categories = await getCategories()
  }
}
</script>

Ajouter une catégorie

Ajouter une route et le composant associé afin de pouvoir ajouter une catégorie. Utiliser les composants créés plus tôt pour faire un formulaire permettant de créer une nouvelle catégorie.

Les données des champs se font par l'intermédiaire des v-model

Il faut ensuite construire un objet que vous allez passer à votre méthode pour faire un ajout (post).

Exemple :

methods: {
    addCategorie: function() {
      
      postCategorie({
        libelle: this.libelle
      })
    }
  }

On pourra créer un composant pour afficher une catégorie

Exercice

Un fois que les catégories fonctionnent, faites de même pour les messages. Un message dépend d'une catégorie, vous devez donc récupérer la liste des catégories pour alimenter une liste déroulante. Pour ajouter les données avec APIPlatform, il faut passer l'URI comme "id" de la catégorie. APIPlatform se chargera de faire le lien entre les entités.

On pourra créer un composant pour afficher un message

Mise à jour et suppression

En vous inspirant des pages précédentes, permettre la modification et la suppression d'un message et d'une catégorie.

Page recherche

Sur le home, ajoutez la possibilité de faire une recherche et de récupère les messages correspondant.

Vous pourriez avoir besoin de créer une route spécifique dans ApiPlatform. Vous pouvez regarder dans cette partie de la documentation : https://api-platform.com/docs/core/filters/

/!\ Attention la documentation utilise les annotations PHP8. Ce qui n'est probablement pas votre cas. Vous devez transposer avec la notation "classique" de Symfony.