Catégorie : développement

Tout ce qui concerne le développement en général, que ce soit des choses générales, ou des choses bien précises. Cela va de la gestion de projet à la recherche du fonctionnement de pointeurs en C.

JavaScript : comment faire un truncate

L’idée est ingénieuse, mais il fallait y penser.

Le principe est d’utiliser une fonction d’opération sur les bits.

Comme JavaScript ne peut que faire une opération sur des entiers, il est « forcé » de convertir ce qui n’est pas un entier en entier.

Donc :

"6874654" | 0

forcera JavaScript à convertir les deux opérandes en entier. Dans la réalité c’est carrément des entiers sur 32 bits, donc ce principe ne peut pas s’appliquer à des chiffres supérieurs à (2^32)-1.

Par contre, si, comme moi, vous n’avez que des petits chiffres à convertir, surtout n’hésitez pas, c’est la méthode la plus rapide.

Ainsi, vous aurez :

"6874654" | 0 = 6874654
"6.87" | 0 = 6
"8.999" | 0 = 8
"azazea" | 0 = 0

L’idée vient de stackoverflow, bien sûr ! 😉

De la nourriture pour le cerveau !

Pris ici, et traduit en français par moi même.

C’est mon site favori.

Je le visite presque tous les jours.

Il n’est pas « responsive ». Il n’est pas optimisé pour iPhone.
Il a l’air flou sur un affichage de type Retina.
Il n’utilise pas le tout dernier framework HTML5/CSS3.
Il n’a pas un « rythme vertical réfléchi pour être agréable ».
Les fontes n’ont rien d’original. Ni Le skeuomorphique ni plat.
Il n’a pas son propre favicon.
Il n’a aucune application native Twitter ou Instagram.
Il n’utilise ni d’AJAX ni de SCRUM ou de node.js ou de Sinatra.
Il n’a pas sa propre API ou son suivi RSS, et pas de VC funding.
Il n’a jamais été numéro un sur un blog technique connu et n’a jamais gagné un seul concours.

Il me dit comment faire la soupe du jour.

Une information donnée gratuitement, qui est pratique pour la personne qui le lit.

C’est ça, le web design.

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 : une boucle qui incarne une des pires horreurs possibles

Voici une horreur qu’on peut trouver, en plein milieu du code sur lequel on m’a demandé de travailler.
Si vous faites mieux dans la série « la pire horreur en Php », n’hésitez pas à en donner un exemple en commentaire…

for ($i=0; $i<count($tab); $i++)
{
    if ($tab[key($tab)]==true) {
        $montableau2[][key($tab)]='code';
    }
    next($tab);
}

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";
?>

PHPExcel : comment générer des cellules avec des styles différents

PHPExcel est un outil pour génerer des fichier Excel en Php.

Il y a beaucoup d’exemples, et tout est bien censé fonctionner. Comme les méthodes sont très parlantes et que c’est bien écrit, j’ai voulu faire un code qui crée plusieurs cellules avec des styles différents.

Ce qui n’est pas expliqué dans la documentation c’est ce qui suit : les « pages » Excel (« tabsheets ») ont des groupes de styles, et chaque cellule référence un de ces styles (sachant qu’il y a un style par défaut). Donc ce que j’ai fait était faux : j’ai essayé d’appliquer directement un style à une cellule, puis un autre style à une autre cellule. Le code exécuté ne correspondait pas du tout à ce que je pensais. Le code faisait ceci : je recherche le style à appliquer parmi tous les styles qui sont recensés dans le « tabsheet » courant. Comme le style n’existait pas, alors il remplaçait le style par défaut du « tabsheet » courant par celui que je demandais à appliquer. Donc comme toutes les cellules référençaient le même style, elles avaient toutes les mêmes propriétés, et évidemment, la dernière « application de style » modifiait en conséquence toutes les cellules. La solution est simple, mais elle n’est pas documentée, et de plus, la fonction à appeler (« duplicateStyle() ») n’est pas très parlante, contrairement à la totalité de l’outil PhpExcel (ce qui est d’autant plus déroutant).

Voici mon code, et je vous explique après pourquoi ça ne fonctionnait pas, et ce qu’il faut faire pour que cela fonctionne.

(1) Je crée deux tableaux différents, de styles différents :

$styleParDefaut = array(
    'font' => array(
        'name'   => 'Bernard MT Condensed',
        'size'   => 10,
        'italic' => false,
        'bold'   => false,
    ),
    'alignment' => array(
        'horizontal' => PHPExcel_Style_Alignment::HORIZONTAL_LEFT,
        'wraptext' => false
    )
);
$styleDonneesTelechargeesLe = array(
    'font' => array(
        'name'   => 'Arial',
        'size'   => 10,
        'italic' => true,
        'bold'   => false,
    ),
    'alignment' => array(
        'horizontal' => PHPExcel_Style_Alignment::HORIZONTAL_LEFT,
        'wraptext' => false
    )
);

(2) Puis je tente de les assigner, un par cellule, comme ça je pensais obtenir deux cellules avec deux styles différents :

function setText($sheet, $colonne, $ligne, $style, $text)
{
    $cell->setValue($text);
    $cell = $sheet->getCellByColumnAndRow($colonne, $ligne);
    $cell->getStyle()->applyFromArray($style);
    $cell->setValue($text);
}

Et le code par cellule :

setText(
    $sheet,
    $colonne, $ligne + 3,
    $styleParDefaut,
    'Texte 1'
);
setText(
    $sheet,
    $colonne, $ligne + 5,
    $styleDonneesTelechargeesLe,
    'Texte 2'
);

Eh bien ça ne fonctionne pas du tout comme cela. En lisant le code, il faut générer dynamiquement les style, et les passer via duplicateStyle().

Donc :

(1) Créer les styles :

$styleParDefaut = new PHPExcel_Style();
$styleParDefaut->applyFromArray(array(.. même chose que précedemment ..));
$styleDonneesTelechargeesLe = new PHPExcel_Style();
$styleDonneesTelechargeesLe->applyFromArray(array(.. même chose que précedemment ..));

(2) Les réutiliser via duplicateStyle()

$cell = $sheet->getCellByColumnAndRow($colonne, $ligne);
$sheet->duplicateStyle($style, $cell->getCoordinate());
$cell->setValue($text);

Symfony: The form’s view data is expected to be of type scalar, array or an instance of \ArrayAccess, but is…

J’ai eu l’erreur qui est le titre de mon post.

Pourtant, j’avais tout fait correctement. J’avais mis en place une collection ManyToMany simple : un partenaire peut être relié à une ou plusieurs personnes et une personne peut être reliée à un ou plusieurs partenaires.

Sur symfony 2.1, tout fonctionnait correctement, et j’ai fait la mise à jour sur symfony 2.3 (pour rester à la pointe 😉 ) mais là une erreur apparaissait :

« The form’s view data is expected to be of type scalar, array or an instance of \ArrayAccess, but is an instance of class HQF\Bundle\PizzasBundle\Entity\Personne. You can avoid this error by setting the « data_class » option to « HQF\Bundle\PizzasBundle\Entity\Personne » or by adding a view transformer that transforms an instance of class HQF\Bundle\PizzasBundle\Entity\Personne to scalar, array or an instance of \ArrayAccess. »

Après un bon moment de recherche, j’ai trouvé ma solution ici.

Dans mon bundle j’avais mon fichier « Bundle/Form/Type/PartenaireType.php » dans lequel j’avais déclaré tout comme il fallait :

    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder->add('nom',                    'text');
        $builder->add('site_actif',             'checkbox');
        $builder->add('afficher_img_produits',  'checkbox');
        $builder->add('commande_en_ligne',      'checkbox');
        $builder->add('livraison',              'checkbox');
        $builder->add('livraison_delai',        'integer');
        $builder->add(
            'personnes',
            'collection',
            array(
                'type' => new PersonneType(),
            )
        );
    }

Tout était parfait, et fonctionnait sous Symfony 2.1. Mais lors de la mise à jour, ça ne fonctionnait plus. Il manquait cela : préciser à nouveau que la PersonneType était liée à un type Personne :

'options' => array('data_class' => 'HQF\Bundle\PizzasBundle\Entity\Personne')

Donc dans mon code ça donne ça :

    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder->add('nom',                    'text');
        $builder->add('site_actif',             'checkbox');
        $builder->add('afficher_img_produits',  'checkbox');
        $builder->add('commande_en_ligne',      'checkbox');
        $builder->add('livraison',              'checkbox');
        $builder->add('livraison_delai',        'integer');
        $builder->add(
            'personnes',
            'collection',
            array(
                'type' => new PersonneType(),
                'options' => array(
                    'data_class' => 'HQF\Bundle\PizzasBundle\Entity\Personne'
                ),
            )
        );
    }

Un grand merci à Stackoverflow, sinon j’aurais mis bien plus de temps à m’en sortir, je pense !

jQuery et la ré organisation de div / cartes

Si jamais vous voulez faire plein de petits « cartes », ou « article », voire des photos, et que vous vouliez qu’ils soient automatiquement réorganisés, voici ce qu’il vous faut :

Ce plugin en JavaScript pour jQuery est absolument génial : http://masonry.desandro.com/. Essayez de redimensionner les fenêtres et vous verrez comment tout ça est réorganisé.

Css inutilisé : comment supprimer toute information inutile – how to

Si jamais vous avez un site qui utilise plein d’outils et que vous pensez que beaucoup de votre CSS n’est pas utilisé, alors allez jeter un coup d’oeil ici : http://unused-css.com/.

C’est un site qui aide pour dire quels sont tous les styles CSS déclarés, et lesquels ne sont pas utilisés.
Extrêmement pratique.

Notez tout de même que si jamais vous construisez dynamiquement des objets DOM (notamment en jQuery) qui utilisent un CSS particulier, et que ce dernier n’est pas utilisé ailleurs, alors je pense que ça trompe le vérificateur et qu’il pense que ce CSS n’est jamais utilisé.

Symfony 2 : mon site de démonstration est sorti : livrepizzas

Mon site de démonstration pour l’utilisation du framework Symfony 2 est sorti.

http://www.livrepizzas.fr

Ce n’est qu’un site de démonstration, il est loin d’être parfait !

  • Bien sûr il est optimisé pour google et pour les mobiles et tablettes.
  • Bien sûr il est compatible w3c.
  • Bien sûr il est moderne et utilise du HTML5.
  • Bien sûr il est en responsive design.
  • Bien sûr c’est facile à faire. 🙂

Si vous avez des commentaires ou suggestions à faire, n’hésitez pas !