# nulib\schema

objet: s'assurer que des données soit dans un type particulier, en les
convertissant si nécessaire. la source de ces données peut-être diverse:
formulaire web, résultat d'une requête SQL, flux CSV, etc. mais en définitive,
les données qui sont traitées par du code PHP sont du bon type et au bon
format, ou une erreur est levée.

les données dont on peut modéliser le schéma sont de 3 types:
* scalaire
* liste (tableau séquentiel)
* tableau associatif

chaque type de données a une syntaxe spécifique pour la définition du schéma.

## Nature de schéma

Un schéma se présente sous la forme d'un tableau associatif avec des clés qui
dépendent de la nature du schéma. La nature du schéma est indiquée avec la clé
`""` (chaine vide), e.g
~~~php
const SCHEMA = [
  "" => NATURE,
];
~~~

La nature indique le type de données représenté par le schéma.
* nature scalaire: modélise une donnée scalaire
  ~~~php
  const SCALAR_SCHEMA = [
    "" => ["scalar"],
    ...
  ];
  ~~~
* nature liste: modélise une liste de valeurs du même type
  ~~~php
  const LIST_SCHEMA = [
    "" => ["list",
      "title" => "libellé de la valeur",
      "required" => false,
      "nullable" => true,
      "desc" => "description de la valeur",
      "name" => "identifiant de la valeur",
    ],
    ITEM_SCHEMA,
  ];
  ~~~
* nature tableau associatif: modélise un tableau associatif
  ~~~php
  const ASSOC_SCHEMA = [
    "" => ["assoc",
      "title" => "libellé de la valeur",
      "required" => false,
      "nullable" => true,
      "desc" => "description de la valeur",
      "name" => "identifiant de la valeur",
    ],
    KEY => VALUE_SCHEMA,
    ...
  ];
  ~~~

## Schéma d'une valeur scalaire

Une valeur scalaire est modélisée de cette manière:
~~~php
const SCALAR_SCHEMA = [
  "type" => "types autorisés de la valeur",
  "default" => "valeur par défaut si la valeur n'existe pas",
  "title" => "libellé de la valeur, utilisable par exemple dans un formulaire",
  "required" => "la valeur est-elle requise? si oui, elle doit exister",
  "nullable" => "si la valeur existe, peut-elle être nulle?",
  "desc" => "description de la valeur",
  "checker_func" => "une fonction qui vérifie une valeur et la classifie",
  "parser_func" => "une fonction qui analyse une chaine pour produire la valeur",
  "messages" => "messages à afficher en cas d'erreur d'analyse",
  "formatter_func" => "une fonction qui formatte la valeur pour affichage",
  "format" => "format à utiliser pour l'affichage",
  "" => ["scalar"],
  "name" => "identifiant de la valeur",
];
~~~

L'ordre des clés du schéma indique la clé associé à une valeur si elle fournie
dans un tableau séquentiel. Par exemple, les deux schéma suivants sont équivalents:
~~~php
const SCALAR_SCHEMA1 = [
  "string", null, "une valeur chaine",
];
const SCALAR_SCHEMA2 = [
  "type" => "string",
  "default" => null,
  "title" => "une valeur chaine",
  "" => ["scalar"],
];
~~~

Si la nature du schéma n'est pas spécifiée, on considère que c'est un schéma de
nature scalaire si:
* c'est une chaine, qui représente alors le type, e.g `"string"`
* c'est un tableau avec un unique élément à l'index 0 de type chaine, qui est
  aussi le type, e.g `["string"]`
* c'est un tableau avec un élément à l'index 0, ainsi que d'autres éléments,
  e.g `["string", null, "required" => true]`

message indique les messages à afficher en cas d'erreur d'analyse. les clés sont
normalisées et correspondent à différents états de la valeur tels qu'analysés
par `checker_func`
~~~php
const MESSAGE_SCHEMA = [
  "missing" => "message si la valeur n'existe pas dans la source et qu'elle est requise",
  "unavailable" => "message si la valeur vaut false dans la source et qu'elle est requise",
  "null" => "message si la valeur est nulle et qu'elle n'est pas nullable",
  "empty" => "message si la valeur est une chaine vide et que ce n'est pas autorisé",
  "invalid" => "message si la valeur est invalide",
];
~~~

## Schéma d'une liste (tableau séquentiel)

Une liste est modélisée de cette manière:
~~~php
const LIST_SCHEMA = [
  ITEM_SCHEMA,
  "" => ["list"],
];
~~~
où ITEM_SCHEMA est le schéma des éléments de la liste

Si la nature du schéma n'est pas spécifiée, on considère que c'est un schéma de
nature liste si:
* c'est un tableau avec un unique élément de type tableau à l'index 0, e.g
  `[["string", null, "required" => true]]`

## Schéma d'un tableau associatif

Un tableau associatif est modélisée de cette manière:
~~~php
const LIST_SCHEMA = [
  KEY => VALUE_SCHEMA,
  ...
  "" => ["assoc"],
];
~~~
où l'ensemble des occurrences de `KEY => VALUE_SCHEMA` définit le schéma de la
valeur dont la clé est `KEY`

Si la nature du schéma n'est pas spécifiée, on considère que c'est un schéma de
nature associative si:
* c'est un tableau uniquement associatif avec aucun élément séquentiel, e.g
  `["name" => "string", "age" => "int"]`

VALUE_SCHEMA peut-être un schéma de nature scalaire, liste ou associative.

S'il s'agit d'une valeur scalaire, il y a quelques clés de définitions
supplémentaires:
~~~php
const VALUE_SCHEMA = [
  ...
  "pkey" => "chemin de clé de la valeur dans le tableau associatif",
  "header" => "nom de l'en-tête s'il faut présenter cette donnée dans un tableau",
  "composite" => "ce champ fait-il partie d'une valeur composite?",
];
~~~

Pour une liste, il y a quelques clés de définitions supplémentaires:
~~~php
const VALUE_SCHEMA = [
  "" => ["list",
    ...
    "pkey" => "chemin de clé de la valeur dans le tableau associatif",
  ],
];
~~~

Pour une tableau associatif, il y a quelques clés de définitions supplémentaires:
~~~php
const VALUE_SCHEMA = [
  "" => ["assoc",
    ...
    "pkey" => "chemin de clé de la valeur dans le tableau associatif",
  ],
];
~~~

-*- coding: utf-8 mode: markdown -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8:noeol:binary