Mots-clé : développement

MySQL

Voici quelques astuces dont je me sers souvent, pour ne pas avoir à systématiquement les rechercher, je m’en suis fait une copie dans un petit champ texte :

Création d’une base de données

CREATE DATABASE z DEFAULT CHARACTER SET utf8;

Créer un utilisateur pour une base de données (la manière sale)

Important : d’abord sans le ‘.*’ sinon ça ne fonctionne pas, et puis refaire avec le '.*'.
Très important : ici on autorise tout à l’utilisateur qui va être crée. C’est donc une méthode rapide mais de bourrin et ce n’est pas la bonne méthode si vous voulez faire un utilisateur proprement, destiné à exister pour longtemps. Dans ce cas il faut faire quelque chose de plus précis afin de ne pas tout lui autoriser.
GRANT ALL PRIVILEGES ON bd TO 'nomutilisateur'@'192.168.2.16' IDENTIFIED BY 'motdepasse';
GRANT ALL PRIVILEGES ON bd.* TO 'nomutilisateur'@'192.168.2.16' IDENTIFIED BY 'motdepasse';

Initialisation d’une variable via une requête :

SELECT @MON_ID:= ID FROM matable WHERE CHAMP='champ_recherche';
puis on se ressert de cette variable pour faire une insertion en base de données :
INSERT INTO autre_table (ID_CLE_EXTERNE, DESCRIPTION, DOCUMENT) VALUES
(@MON_ID, 'valeur1', './valeur2');

Relancer le service MySQL

  1. service mysqld stop
  2. attendre une trentaine de secondes afin que le cache soit vidé et que toutes les allocations mémoires soient correctement libérées
  3. service mysqld start

Convertir une table en utf8 :

Très important : si vous tapez ce qui suit avec pour objectif de convertir la table et les données cela ne fonctionnera pas :
ALTER TABLE tbl_name CONVERT TO CHARACTER SET charset_name;
Ce n’est qu’en utilisant les ordres suivants que la conversion sera faite par MySQL !
ALTER TABLE t1 CHANGE c1 c1 BLOB;
ALTER TABLE t1 CHANGE c1 c1 TEXT CHARACTER SET utf8;

Renommer un champ :

Ici, je renomme la clé primaire « ID » et je la passe en minuscules (« id« ) :
ALTER TABLE ville CHANGE ID id int(11) NOT NULL auto_increment;

Modification des AUTO_INC

Pour changer la valeur d’un auto_inc (‘réinitialiser la valeur’, comme on le dit dans MySQL ici) :
ALTER TABLE tbl_name AUTO_INCREMENT = N;

PhpStorm, Windows / WAMP et xdebug : howto – la solution

Si jamais vous êtes comme moi, et que vous n’avez pas réussi à faire fonctionner PhpStorm avec xdebug sous Windows avec WAMP, vous avez peut-être le même problème que moi à savoir : le serveur Apache semble mal configuré – ou configurable, et incapable d’utiliser Php correctement avec xdebug.

Je passe toutes les étapes de configuration « classiques », parce qu’elles sont simples et bien documentées – y compris dans PhpStorm. Malgré tout ça, il se peut que cela ne fonctionne pas.

La solution :

Solution PhpStorm RunDebug Configurations pour Windows - WAMP

En fait il faut configurer PhpStorm pour qu’il ne passe pas par Apache, mais qu’il lance le serveur Php intégré (si, Php a un serveur HTTP, cherchez dans la documentation).

Et ainsi, le déboguage en ligne fonctionnera.

C’est grâce à cette vidéo que j’ai eu l’idée d’essayer :

http://www.youtube.com/watch?v=LUTolQw8K9A

Bien sûr, si vous essayez xdebug sous Linux, vous aurez nettement moins de difficultés :).

Symfony 2 Notice: Undefined offset: 0 in vendor/…/Hydration/SimpleObjectHydrator.php line 103

Voici un petit problème que j’ai résolu.

Supposons que vous ayez plusieurs entités qui descendent d’une seule.
Dans l’entité mère, vous précisez ce qui va différencier les autres via la propriété DiscriminatorColumn :

/**
 * @ORM\Entity
 * @ORM\Table(name="table_de_base")
 * @ORM\InheritanceType("JOINED")
 * @ORM\Entity(
 *   repositoryClass="SOCIETE\Bundle\MegaSuperBundle\Repository\PersonRepository"
 * )
 * @ORM\DiscriminatorColumn(name="person_type", type="integer")
 * @ORM\DiscriminatorMap({"1" = "PersonneBoss", "2" = "PersonneLarbin"})
 */
abstract class Personne extends BaseUser
{
...
}

Cela signifie en clair : l’entité «PersonneBoss», descendante de «Personne», aura aura la valeur «1» dans le champ person_type, et l’entité descendante «PersonneLarbin», de «Personne», aura la valeur «2» dans le champ person_type. C’est, comme son nom l’indique, un «discriminateur».

Si jamais vous vous retrouvez avec une erreur de ce type : Notice: Undefined offset: 0 in vendor/doctrine/orm/lib/Doctrine/ORM/Internal/Hydration/SimpleObjectHydrator.php line 103, alors il se peut, comme c’était le cas pour moi, que les valeurs pour le «discriminateur» n’aient pas été correctement renseignées : dans mon cas, les valeurs étaient soit null, soit 0 et en fait cette valeur sert apparemment d’indice dans une table afin de pouvoir faire la jointure avec les descendants : donc il essayait de chercher une table avec l’indice 0, alors que je n’ai précisé que 1PersonneBoss») ou 2PersonneLarbin»)… donc pour la valeur 0, forcément, Symfony sort un Notice: Undefined offset: 0.

Bref, si vous avez une erreur comme celle-là, vérifiez que les valeurs en base de données sont cohérentes avec vos déclarations !

Packtlib : Mastering ExtJS : impressions à chaud

Pour les Anglais uniquement, vous serez sûrement intéressées :

Le livre Mastering ExtJS.

Mastering Ext JS montre aux lecteurs comment utiliser le potentiel de Ext JS au complet et créer une application au complet en partant de rien, mais explique aussi comment créer un thème WordPress avec ExtJS. Cette dernière section est assez surprenante, mais semble efficace.

  • Chapter 1. Getting Started
    Les bases pour installer ExtJS (LAMP, ou pour les newbies WAMP etc)
  • Chapter 2. The Login Page
    La plupart des applications ont une page d’identification. L’auteur explique comment faire l’identification « classique » avec ExtJS.
  • Chapter 3. Logout and Multilingual
    La plupart des applications ont une page de déconnexion, et en 2013, il faut savoir rapidement implémenter une autre langue. L’auteur explique comment faire cela : déconnexion et gestion du multilangue.
  • Chapter 4. Advanced Dynamic Menu
    Comment créer des menus dynamiques, qui sont constitués en fonction des droits de la personne connectée (cf chapitres 2 et 3).
  • Chapter 5. User Identification and Security
    Création d’une page de gestion complètes des identifications : comment donner les permissions à des utilisateurs (lister tous les utilisateurs, créer, éditer et supprimer des utilisateurs et aperçu d’une image d’un utilisateur qui va être envoyée).
  • Chapter 6. MySQL Table Management
    Création d’un système modulaire appelé « données statiques ». Liste de toutes les informations d’une table MySQL. Créer de nouveaux enregistrements dans la table. Live search sur les tables. Mettre en place des filtres. Éditer et supprimer des enregistrements. Créer un composant abstrait réutilisable pour toutes les tables.
  • Chapter 7. Content Management
    Gestion de contenu complexe avec ExtJS : comment gérer les associations many-to-many. Comment gérer et faire des formes avec les associations. Explication pour faire des composants réutilisables.
  • Chapter 8. Adding Extra Capabilities
    Possibilités supplémentaires. Comment imprimer des champs d’un panneau de type grille (GridPanel). Comment exporter des champs d’un panneau de type grille (GridPanel) en PDF ou au format Excel. Comment créer des graphiques /courbes. Comment utiliser des composants tiers ou des plugins.
  • Chapter 9. The E-mail Client Module
    Cette partie explique comment développer un client Web mail avec ExtJS. Comment dessiner le client email. Comment lister les emails. Comment créer la boîte de réception (gestion d’un TreePanel). Comment gérer le drag’n’drop entre deux composants (grid et tree). Améliorer le GridPanel de manière impressionnante (customisation).
  • Chapter 10. Preparing for Production
    Comment créer un thème personnaliser. Comment préparer (packager) l’application pour qu’elle soit prête pour la production. Comment utiliser le packager. Il peut sembler y avoir peu de choses dans ce chapitre, mais les explications sont longues et détaillées et j’ai appris énormément de choses.
  • Chapter 11. Building a WordPress Theme
    Je pensais que l’idée était de faire à la main un thème WordPress, mais non : l’idée est d’utiliser tout l’habillage au complet ExtJS, ainsi que le code JavaScript qui va avec, afin de l’intégrer dans une application WordPress. Comment fonctionne WordPress. Comment créer un thème, un header, un footer, une page principale, une Sidebar, une page d’articles et enfin une page de type « Page » (par opposition aux pages de type « Article »)
  • Chapter 12. Debugging and Testing
    C’est un des chapitres les plus pratiques pour la vie quotidienne : la plupart des outils avancés et peu connus y sont, pourtant il sont très utiles : comment déboguer une application ExtJS. Comment tester les applications ExtJS. Les outils utiles (JSLint, YSlow, Sas, Less, YUI Compressor…). Comment passer de ExtJS à une version mobile. Composants tiers et plugins utiles pour développer rapidement. Résumé

Au final, ce livre comporte beaucoup de choses intéressantes, et (à mon sens), même si vous êtes développeur avancé ExtJS, les trois derniers chapitres sont super intéressants et rien que pour ces trois derniers, même si vous trouvez qu’acheter un livre c’est trop cher (ce que je comprends ;)), les quelques 17 € que vous coûteront la version en ligne seront rapidement rentabilisés.

D’ailleurs en parlant de version en ligne, ils ont complètement refait leur reader en ligne, et ce dernier est très bien fait : moi qui suis très critique, je n’ai rien trouvé à redire !

Développement : Coding contest !

Challenge de codeurs !

C’est pour le fun, essayez vous aussi 

Le principe est simple

Vous aurez deux puzzles de programmation à résoudre.

Pour ce faire, vous pourrez choisir votre langage favori parmi ceux-ci : Java, C, C++, C#, Javascript, PHP, Python, Ruby, Objective-C, Haskell and Go.
La durée moyenne d’un challenge est de 2 heures et 30 minutes.

J’y serai, le 28 septembre !

Php : challenge ASCII art

J’ai fait un pari. Petit challenge à réaliser : faire un script (peu importe le langage) qui prend en paramètre un fichier image, et qui en sort de l’ASCII art.
Il faut qu’il soit rapidement paramétrable sur la taille des fontes.

Je l’ai fait « théorique » en 59 minutes, mais entièrement fonctionnel en une heure trente. J’ai fait deux scripts : un qui génère le fichier des fontes, et le principal qui lit le fichier image des fontes, et le fichier image en paramètre, et sort de l’ASCII art.

Exemple de résultat (si si c’est bien du texte, vous pouvez le sélectionner et copier coller en tant que texte !) :

BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBMBBBBBBBBBBBB
BBBBBBBBBBBBBBBBBBBBBBBBBBBBBB¨ MBBBBBBMM0BBB
BBBBBBBBBBBBBBBBBBBBBBBBBP'`BB  ,BBBP¨    MBB
BBBBBBBBBBBBBBBBBBBBBBBBB&  %BMBPBBL  ,a  ¨BB
BBBBBBBBBBBBBBBBBBBBBBBBBB  jBB  MBBaBBP   BB
BBBBBBBBBBBBBBBBBBBBBBBBPM   BB  ¨BBB^  ,  0B
BBBBBBBBBBBBBBBBBBBBBBP`     BBb  BB'  mB  jB
BBBBBBB@P'BBBBBB@M@BBB   mB  $BK  0B  jBP  ¨B
BBBBBBBK  BBBP^`   MBB  dBB  MBB  jB   ¨ L,aB
B^¨ 'BBB  %BB  ,a   BB  &BBL  BB   Bh  ,WBBBB
B    ¨BB  jBB,mBM^  $B  'BBF  BBL  BBBBBBBBBB
BL    `BL  BBBP¨    jB   ^^   %B&mBBBBBBBBBBB
B&  w  ¨&  BBP  wB   B&    wamBBBBBBBBBBBBBBB
BB  %w     MBL  BB¨  BBBwamBBBBBBBBBBBBBBBBBB
BB  MBw    ¨BK  ¨`, ,&BBBBBBBBBBBBBBBBBBBBBBB
BBL  BBN    BB,  aBBBBBBBBBBBBBBBBBBBBBBBBBBB
BB&  BBBh   0BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
BBB  MBBBhwmBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
BBB  OBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB

Ne regardez pas la suite si vous voulez essayer de le faire pour vous !

<?php
function usage_et_exit($message = '', $exit_error = -1) {
    global $argv;
    if ($message != '') {
        echo $message."\n";
    }
    echo $argv[0]." {image gif reference} {image noir et blanc jpg}\n";
    exit($exit_error);
}

function noir_ou_blanc($r, $g, $b) {
    /* http://stackoverflow.com/questions/254388/how-do-you-convert-an-image-to-black-and-white-in-php */
    if (((0.299*$r) + (0.587*$g) + (0.114*$b))> 0x7F) {
        return 0xFFFFFF;
    } else {
        return 0x000000;
    }
}

function cherche_meilleure_correspondance(
    $img_src, $x, $y, $img_fonts, $font_size, $tab_base
) {
    $meilleur = -1;
    $retour = '';
    foreach ($tab_base as $idx => $ch) {
        $match = 0;
        for ($t_y=0; $t_y<$font_size; $t_y++) {
            for ($t_x=0; $t_x<$font_size; $t_x++) {
                if (imagecolorat($img_src, $t_x+$x, $t_y+$y)
                    != imagecolorat(
                        $img_fonts,
                        ($idx*$font_size) + $t_x, $t_y
                    )
                ) {
                    $match++;
                }
            }
        }
        if ($match>$meilleur) {
            $retour = $ch;
            $meilleur = $match;
        }
    }
    return $retour;
}

function convert_img_noir_et_blanc($filename, $img)
{
    list($width, $height, $type, $attr) = getimagesize($filename);
    /* Conversion en noir et blanc */
    for ($y=0; $y<$height; $y++) {
        for ($x=0; $x<$width; $x++) {
            $rgb = imagecolorat($img, $x, $y);
            $r = ($rgb >> 16) & 0xFF;
            $g = ($rgb >> 8) & 0xFF;
            $b = $rgb & 0xFF;
            $nb = noir_ou_blanc($r, $g, $b);
            imagesetpixel($img, $x, $y, $nb);
        }
    }
}

$tab_base = array(
    '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
    'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c',
    'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q',
    'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4',
    '5', '6', '7', '8', '9', '&', '\'', ',', ';', ':', '?', '.', '/', '!',
    '%', '^', '¨', '$', '~', '#', '(', ')', '[', ']', '|', '-', '`', ' '
);
$font_size = 14;
$min_width  = 400;
$min_height = 400;

if ($argc!=3) {
    usage_et_exit("Arguments invalides", -1);
}

$img_tmp = imagecreatefromstring(file_get_contents($argv[1]));
$width = imagesx($img_tmp);
$height = imagesy($img_tmp);
$img_fonts = imagecreatetruecolor($width, $height);
imagecopy($img_fonts, $img_tmp, 0, 0, 0, 0, $width, $height);
imagedestroy($img_tmp);
unset($img_tmp);
if ($img_fonts===false) {
    usage_et_exit("Erreur chargement de ".$argv[1], -1);
}

/* Conversion en noir et blanc des fontes */
convert_img_noir_et_blanc($argv[1], $img_fonts);
imagepng($img_fonts, './resultat_fonts.png', 0);

list($width, $height, $type, $attr) = getimagesize($argv[2]);
if ($width<$min_width) {
    usage_et_exit("Largeur trop petite de ".$argv[1].", taille min = ".$width_min, -1);
}
if ($width<$min_height) {
    usage_et_exit("Hauteur trop petite de ".$argv[1].", taille min = ".$width_min, -1);
}

$img_src = imagecreatefromjpeg($argv[2]);
if ($img_src===false) {
    usage_et_exit("Erreur chargement de ".$argv[2], -1);
}
convert_img_noir_et_blanc($argv[2], $img_src);
/* Ok on a l'image en noir et blanc. Parcourir toute l'image */
imagepng($img_src, './resultat_noir_et_blanc.png', 0);

$y = 0;
$max_result = 0;
while (($y + $font_size) < $height) {
    $x = 0;
    while (($x + $font_size) < $width) {
        echo cherche_meilleure_correspondance(
            $img_src, $x, $y, $img_fonts, $font_size, $tab_base
        );
        $x += $font_size;
    }
    echo "\n";
    $y += $font_size;
}
echo "Done.\n";
?>

Et le fichier qui génère les fontes (22 minutes de perdues à le faire…) :

<?php
$tab_base = array(
    '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
    'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c',
    'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q',
    'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4',
    '5', '6', '7', '8', '9', '&', '\'', ',', ';', ':', '?', '.', '/', '!',
    '%', '^', '¨', '$', '~', '#', '(', ')', '[', ']', '|', '-', '`', ' '
);
$x=0;
$font_size = 14;
$width = count($tab_base)*$font_size;
echo 'width='.var_export($width,true)."\n";
$height = $font_size*4;
$img = imagecreatetruecolor($width, $height);
if ($img===false) {
    throw new Exception("Erreur");
}
imagefilledrectangle($img, 0, 0, $width, $height, 0xFFFFFF);
foreach ($tab_base as $idx => $char) {
    $ok = imagettftext(
        $img,
        $font_size, 0,
        $idx * $font_size, $font_size,
        0x000000,
        './consola.ttf', $char
    );
}
imagegif($img, './test.gif');
echo "Done.\n";
?>

PhpDocumentor 2 : howto et résultats exceptionnels

Après plusieurs échanges avec le développeur principal de PhpDocumentor 2, celui-ci a corrigé plusieurs bogues et maintenant la version alpha tourne, et j’ai pu la lancer sur mon framework.

Résultats tout simplement exceptionnels (pas pour mon framework, mais pour PhpDocumentor).

Ce qui m’a le plus bluffé c’est le schéma de diagramme de classes : non seulement il est beau et pratique, mais il est clair.

Donc une vue globale de mon diagramme de classes :

Image petite du diagramme de classes

Et quand on clique pour zoomer, le rendu est tout aussi exceptionnel :

Image petite du zoom du diagramme de classes

C’est pratique, grâce à ça, je vois tout ce qui manque. Par exemple, les ListeXXX ne sont pas dans une classe générique, alors que les ItemXXX oui, des petites évolutions à faire pour rendre un peu tout ça plus propre, mais c’est un bon début !

Ensuite, viennent les classes et la documentation générée : de la même façon, si tout est correctement organisé, le rendu est vraiment très bon et la documentation est enfin utilisable !

Image petite de l'exemple de documentation de classes

Php : day of week – jour de la semaine. Astuce

Oui, on peut facilement imaginer plusieurs choses :

Les jours de la semaine sont numérotés de 1 à 7. Faux.

Ils sont numérotés de 0 à 6.

Enfin pour l’astuce qui pourrait certainement vous faire gagner du temps :
Les jours de la semaine commencent à lundi. Faux.

Si on lit la documentation : 0 (pour dimanche) à 6 (pour samedi).

Bon à savoir !

ExtJS et grids : double click, comment faire, howto ?

Cela fait une bonne heure que je cherche comment avoir le double click sur une grid générée dynamiquement.

C’est très simple :

Ce code ne fonctionnait pas, donc si vous êtes dans le même cas que moi, n’ayez pas peur :

this.gridAttributs = Ext.create('Ext.grid.Panel', { 
    border: 0,
    store: this.store,
    columns: [ 
        { text: "id", dataIndex: 'id', sortable: true },
        { ... },
        { ... }
    ],
    celldblclick: function(evt, elem, opts ) { 
        console.log('dblclick');
    }
});

Voici le code qui fonctionne :

this.gridAttributs = Ext.create('Ext.grid.Panel', { 
    border: 0,
    store: this.store,
    columns: [ 
        { text: "id", dataIndex: 'id', sortable: true },
        { ... },
        { ... }
    ]
});
this.gridAttributs.on('cellDblClick', function(evt, elem, opts ) {
    console.log('dblclick');
});

J’espère vous avoir évité de perdre l’heure que moi même j’ai perdu ! 😉