Archives mensuelles : septembre 2017

Symfony : Afficher toutes les erreurs d’un formulaire dans une liste

Mise à jour le 03/04/2020 pour fonctionner avec Symfony 5

Par défaut l’affichage des erreurs sur les formulaires dans symfony se fait de la manière suivante :

  • Les erreurs globales (qui ne concerne pas un champ particulier) sont affichés en haut.
  • Les erreurs concernant chaque champs, sont affiché au niveau du champ.

Dans certains cas, par exemple sur des longs formulaires, il peut être intéressant de retrouver la liste de toutes les erreurs au mêmes endroits. Voici ci-dessous un code permettant de le faire (pour un formulaire « form »)

{% if not form.vars.valid %}
    <ul class="alert alert-danger">
        {# on affiche en premier les erreurs globales (cas classiques) #}
        {% for error in form.vars.errors %}
            <li>{{error.message}}</li>
        {% endfor %}
        {# ainsi que les erreurs concernant chaque champs #}
        {% for child in form.children %}
            {# si le champ à des erreur #}
            {% if child.vars.errors is defined %}
                {% for error in child.vars.errors %}
                    <li>"{{child.vars.label}}" : {{error.message}} </li> {# on ajoute le label du champ devant l'erreur pour plus de précisions. #}
                {% endfor %}
            {% endif %}
        {% endfor %}
    </ul>
{% endif %}

PHP & Google Map API : Récupérer les détails d’une adresse (latitude, longitude, département, région…)

La semaine dernière nous avons vu une fonction permettant de calculer la distance entre deux coordonnées GPS, mais comment récupérer ces coordonnées (et d’autres informations) à partir d’une adresse ? Nous allons voir comment faire avec l’API google Map, il vous faudra tout d’abord récupérer une clé pour les appel à l’API (par ici).

Ensuite vous pouvez utiliser la classe et la fonction ci-dessous afin de récupérer les informations (adresse complète, latitude, longitude, vile, code postal, département, région, pays) correspondant à l’adresse passé au format texte.

class GmapApi {

    private static $apikey = 'VOTRE_API_KEY';

    public static function geocodeAddress($address) {
        //valeurs vide par défaut
        $data = array('address' => '', 'lat' => '', 'lng' => '', 'city' => '', 'department' => '', 'region' => '', 'country' => '', 'postal_code' => '');
        //on formate l'adresse
        $address = str_replace(" ", "+", $address);
        //on fait l'appel à l'API google map pour géocoder cette adresse
        $json = file_get_contents("https://maps.google.com/maps/api/geocode/json?key=" . self::$apikey . "&address=$address&sensor=false&region=fr");
        $json = json_decode($json);
        //on enregistre les résultats recherchés
        if ($json->status == 'OK' && count($json->results) > 0) {
            $res = $json->results[0];
            //adresse complète et latitude/longitude
            $data['address'] = $res->formatted_address;
            $data['lat'] = $res->geometry->location->lat;
            $data['lng'] = $res->geometry->location->lng;
            foreach ($res->address_components as $component) {
                //ville
                if ($component->types[0] == 'locality') {
                    $data['city'] = $component->long_name;
                }
                //départment
                if ($component->types[0] == 'administrative_area_level_2') {
                    $data['department'] = $component->long_name;
                }
                //région
                if ($component->types[0] == 'administrative_area_level_1') {
                    $data['region'] = $component->long_name;
                }
                //pays
                if ($component->types[0] == 'country') {
                    $data['country'] = $component->long_name;
                }
                //code postal
                if ($component->types[0] == 'postal_code') {
                    $data['postal_code'] = $component->long_name;
                }
            }
        }
        return $data;
    }

}

Par exemple en appelant la fonction de cette manière :

$data = GmapApi::geocodeAddress('151 avenue du pont trinquat 34070 Montpellier');
//on affiche les différente infos
echo '<ul>';
foreach ($data as $key=>$value){
    echo '<li>'.$key.' : '.$value.'</li>';
}
echo '</ul>';
/* va afficher
address : 151 Avenue du Pont-Trinquat, 34000 Montpellier, France
lat : 43.6008177
lng : 3.8873392
city : Montpellier
department : Hérault
region : Occitanie
country : France
postal_code : 34000
*/

On peux maintenant utiliser cette fonction pour trouver la distance entre 2 adresses, grâce à notre fonction de l’article précédent. Par exemple :

$data1 = GmapApi::geocodeAddress('151 avenue du pont trinquat 34000 montpellier');
$data2 = GmapApi::geocodeAddress('Avenue des cévennes 30360 vézénobre');
echo round(Misc::distance($data1['lat'], $data1['lng'], $data2['lat'], $data2['lng'])).' Km';
//Affiche : 54 Km

PHP : Calcul de la distance entre 2 coordonnées GPS (latitude, longitude)

La fonction toute prête afin de pouvoir la retrouver facilement, pas plus d’explications, c’est des maths, ça pique la tête !

class Misc {
    /**
     * Retourne la distance en metre ou kilometre (si $unit = 'k') entre deux latitude et longitude fournit
     */

    public static function distance($lat1, $lng1, $lat2, $lng2, $unit = 'k') {
        $earth_radius = 6378137;   // Terre = sphère de 6378km de rayon
        $rlo1 = deg2rad($lng1);
        $rla1 = deg2rad($lat1);
        $rlo2 = deg2rad($lng2);
        $rla2 = deg2rad($lat2);
        $dlo = ($rlo2 - $rlo1) / 2;
        $dla = ($rla2 - $rla1) / 2;
        $a = (sin($dla) * sin($dla)) + cos($rla1) * cos($rla2) * (sin($dlo) * sin($dlo));
        $d = 2 * atan2(sqrt($a), sqrt(1 - $a));
        //
        $meter = ($earth_radius * $d);
        if ($unit == 'k') {
            return $meter / 1000;
        }
        return $meter;
    }
}

Exemple d’utilisation :

echo round(Misc::distance(48.86417880,2.34250440,43.6008177,3.8873392), 3);//affiche 597.833 (pour 597,833 km entre les deux coordonnées fournit)

Il s’agit bien entendu de distance à vol d’oiseau.

L’article suivant explique comment obtenir les coordonnées latitude et longitude correspondant à une adresse grâce à l’API Google Map.

Rendez vous ici pour faire le calcul directement en MySql et dans Doctrine

source : http://www.phpsources.org/scripts459-PHP.htm

jQuery : Créer un « font picker » avec le plugin Select2

Créer une liste déroulante (select) proposant un choix parmi plusieurs polices de caractères, tout en permettant de prévisualiser le style d’écriture de la police dans cette liste n’est pas la chose la plus évidente à mettre en place.
Ci-dessous une image présentant le résultat recherché. Et ici une page de démonstration

font-picker

Pour réaliser cela nous allons utiliser le plugin jQuery select2 qui permet de transformer les listes déroulantes. On peux grâce à lui avoir un champs de recherche dans la liste -ce n’est pas la fonctionnalité qui nous intéresse- on peux aussi donner du styles aux options, c’est ce que l’on va utiliser.

On commence donc par importer jQuery et ce plugin sur notre page, ainsi que les polices que l’on va proposer, j’utilise ici l’outil google fonts pour cela.

<!-- google fonts -->
<link href="https://fonts.googleapis.com/css?family=Alfa+Slab+One|Amatic+SC|Anton|Cinzel|Cutive+Mono|Frijole|Great+Vibes|Indie+Flower|Josefin+Sans|Just+Another+Hand|Lobster|Monoton|Pacifico|Permanent+Marker|Playfair+Display|Raleway|Righteous|Roboto+Condensed|Roboto+Slab|Saira+Semi+Condensed|Sedgwick+Ave+Display" rel="stylesheet">
<!-- jquery + select2 -->
<script src="./js/jquery-3.2.1.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.3/js/select2.min.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.3/css/select2.min.css" rel="stylesheet" />
<!-- le script nous permettant de mettre en place le font picker -->
<script src="./js/font-picker.js"></script>

Dans la page on utiliser une balise select classique à laquelle on attribue un identifiant particulier (ici « select-font »)

<select id="select-font" class="form-control">
 <option value="Arial">Arial</option>
 <option value="Times New Roman">Times New Roman</option>
 <option value="Alfa Slab One">Alfa Slab One</option>
 <option value="Amatic SC">Amatic SC</option>
 <option value="Anton">Anton</option>
 ....
</select>

Et voici ci-dessous les quelques lignes de javascript permettant de faire fonctionner le système.

$(document).ready(function () {
    //on applique le plugin "select2" sur notre liste deroulante en lui indiquant d'utiliser un template particulier
    $("#select-font").select2({templateResult: formatFont}).on('change', function (e) {
        updateSelectFontStyle($(this));
    });
    //on initialise la liste au chargement de la page en fonction de la police sélectionné.
    updateSelectFontStyle($("#select-font"));
});

/**
 * Permet d'appliquer la bonne police sur l'option du select2
 */

function formatFont(opt) {
    if (!opt.id) {
        return opt.text;
    }
    var $state = $('<span style="font-family:\'' + opt.element.value + '\';"> ' + opt.text + '</span>');
    return $state;
}

/**
 * Donne la font family sélectionné à l'élément passé en paramètre
 */

function updateSelectFontStyle($el) {
    var font = $el.val();
    var id = '#select2-' + $el.attr("id") + '-container';
    $(id).css("font-family", "'" + font + "'");
}

Terminé !