Les flux PHP et la création aisée de fichiers CSV

Dans de nombreux projets sur lequel j’ai travaillé, j’ai été confronté à la problématique de générer des fichiers qui doivent par la suite être transmis au client.
Bien sûr, tout dépend de environnement dans lequel on se trouve mais dans la majorité des cas, je passais par un fichier temporaire que je lisais par la suite pour l’injecter dans la réponse :

$filePath = tempnam(sys_get_temp_dir(), 'myApp');
$fp = fopen($filePath, 'w');
[...]
fclose($fp);

Autant cette méthode est viable à mes yeux, autant une récente découverte m’a permis de trouver une approche bien plus séduisante selon moi.

PHP gère nativement certains flux comme par exemple php://stdin, php://stdout, php://stderr. Depuis la version 5.1.0, de nouveaux flux ont fait leur apparition: php://memory et php://temp.
Les deux wrappers permettent d’ouvrir des flux en mémoire mais tout l’intérêt du second réside dans sa capacité à basculer automatiquement vers un fichier temporaire lorsqu’une taille maximale est atteinte :

$fp = fopen('php://temp/maxmemory:1024', 'r+');

J’y ai trouvé un intérêt tout particulier en associant cette technique à la fonction fputscsv qui permet de générer aisément un fichier CSV ligne par ligne.
Avec une source de donnée Doctrine, cela devient vraiment plaisant :

$twoMBs = 2 * 1024 * 1024;
$out = fopen("php://temp/maxmemory:$twoMBs", 'w');
foreach(Doctrine::getTable('myWidget')->findAll() as $widget) {
  fputscsv($out,  $widget->toArray(), ';', '"');
}
fclose($out);

Mocker la console Firebug

Dans le développement d’un site web, je pense qu’une grande partie des développeur JS/CSS utilisent cette (merveilleuse) extension qu’est Firebug.

Une problématique qui se pose régulièrement toutefois est le fait qu’il arrive de laisser des appels à la méthode console.log, ce qui engendre parfois de nombreuses erreurs si l’on se rend sur le site avec un navigateur ne disposant pas de l’extension (soit, à peu près tous les utilisateurs non développeurs).

Une solution qui m’a été proposée et que je trouve assez sexy consiste simplement à moquer la console de firebug en début de page :

// Mock Firebug console if no exist
 if(!window.console) var console = {log : function(msg){},warn : function(msg){},error : function(msg){}};

Réalisation d’un tri pour les éléments d’une relation avec Doctrine

Bonjour tout le monde

Une problématique qui se pose régulièrement dans le développement avec le framework Doctine (ou tout ORM) est l’ordre dans lequel les entités récupérées seront triées.

Une réponse à cette problématique proposée sur le site test.ical.ly permettant de définir l’ordre de tri directement dans la définition du modèle en YAML :

Read the rest of this entry »

Upload de fichiers via Post en Java

Un billet complet pour un simple lien vers un howto dont je me suis servi pour me faire un petit programme java permettant d’uploader des fichiers via un formulaire PHP en POST.

Read the rest of this entry »

Contrainte unique multi-colonnes avec propel en YAML

Dans le cadre d’un projet de sondage, il me fallait mettre en place une contrainte d’unicité sur deux colonnes.
Il s’agit d’un projet Symfony 1.1 avec Propel et je n’ai pas trouvé de doc qui mentionne exactement la démarche.
Voici comment j’ai procédé en me basant sur une interprétation simple de la mise en place des index avec Propel.

  store_contribution:
    id:                     { type: integer, primaryKey: true, required: true, autoIncrement: true, sequence: seq_store_contribution }
    store_id:               { type: integer, required: true, foreignTable: store, foreignReference: id }
    year:                   { type: integer, required: true }
    employees_voters_qty:   { type: integer }
    executives_voters_qty:  { type: integer }
    _uniques:
      - [store_id, year]


Sources:

Ant & SVN

Pour automatiser mes déploiements, j’avais besoin de réaliser un SVN export depuis un fichier de build Ant.
Une petite recherche sur la toile et je suis tombé là dessus.
C’est une bonne base pour créer ses propres scripts je trouve.

build.properties:

####START of SVN Properties ####
svn.repository.url=http://xyz.com/repos/somereponame
svn.project.base.path=someprojectname
svn.username=user name to access repo
svn.password=password to access repo
#This shall be name of the tag,
#This property should always be updated before build starts
#This property shall be used to export
tag.name=SOME_TAG_NAME_12222008
#This shall be name of new branch,
#this property should be used only when new branch is to be created
new.branch.name=NEW_BRANCH_12222008
####END of SVN Properties ####

build.xml














  

  
    
  











  
  







  
    SVN-ANT is not available, cannot perform tagging or checkout/export svn ant task.
  






    




  
  
  

  
    
  






    



  
  
    
  






    




  
  
  

  
    
  

Source: http://java.dzone.com/articles/how-use-svn-tasks-with-ant

Singleton et Injection de dépendance

L’idée est d’avoir un Singleton d’une classe contenant des informations provenant d’un webservice. Puisque la méthode forward aboutie à une nouvelle instance de la classe sfActions, seul le Singleton nous permet de conserver une instance de notre classe de stockage sans passer par les variables de session.

interface DomainInfosRetrievable
{
  /**
   *
   * @param DomainInfos $oDomainInfos
   * @return DomainInfos
   */
  public function getDomainInfos(DomainInfos $oDomainInfos);
}

class DomainInfos
{
  /*
   * Singleton with Dependency Injection
   */

  protected static $oInstance;

  protected function __construct()
  {
    // Singleton constructor
  }

  public static function getInstance(DomainInfosRetrievable $oDomainInfosRetrievable)
  {
    if(is_null(self::$oInstance)) {
      self::$oInstance = $oDomainInfosRetrievable->getDomainInfos(new self());
    }
    return self::$oInstance;
  }
}

classMyActions extends sfActions implements DomainInfosRetrievable
{
  /**
   * @var DomainInfos
   */
  protected $oDomainInfos;

  /**
   * Executes an application defined process prior to execution of this action
   */
  public function preExecute() {
    $this->oDomainInfos = DomainInfos::getInstance($this);
  }
}

Utilisation de la classe sfPager avec un simple tableau PHP

La classe héritant de sfPager :

class myArrayPager extends sfPager
{
  protected $resultsArray = null;

  public function __construct($class = null, $maxPerPage = 10)
  {
    parent::__construct($class, $maxPerPage);
  }

  public function init()
  {
    $this->setNbResults(count($this->resultsArray));

    if (($this->getPage() == 0 || $this->getMaxPerPage() == 0))
    {
     $this->setLastPage(0);
    }
    else
    {
     $this->setLastPage(ceil($this->getNbResults() / $this->getMaxPerPage()));
    }
  }

  public function setResultArray($array)
  {
    $this->resultsArray = $array;
  }

  public function getResultArray()
  {
    return $this->resultsArray;
  }

  public function retrieveObject($offset) {
    return $this->resultsArray[$offset];
  }

  public function getResults()
  {
    return array_slice($this->resultsArray, ($this->getPage() - 1) * $this->getMaxPerPage(), $this->maxPerPage);
  }

}

Et son utilisation :

$myArrayOfThings = array('first', 'second', 'and so on');
$this->pager = new myArrayPager(null, 15);
$this->pager->setResultArray($myArrayOfThings);
$this->pager->setPage($this->getRequestParameter('page',1));
$this->pager->init();

Source : http://snippets.symfony-project.org/snippet/177

Création de miniatures lors de l’upload d’images avec l’Admin Generator de Symfony

Surcharger la méthode processUploadedFile d’une classe héritant de sfFormDoctrine :

  protected function processUploadedFile($field, $filename = null, $values = null)
  {
    $fn = parent::processUploadedFile($field, $filename, $values);
    if ($filename != "")
    {
      $thumbnails[] = array('dir' => '128x128', 'width' => 128, 'height' => 128);
      foreach ($thumbnails as $thumbParam)
      {
        $currentFile = sfConfig::get('sf_upload_dir').'/media/'.$thumbParam['dir'].'/'. $fn;
        if (is_file($currentFile)) unlink($currentFile);
      }
      foreach ($thumbnails as $thumbParam)
      {
        $thumbnail = new sfThumbnail($thumbParam['width'], $thumbParam['height'],true,false);
        $thumbnail->loadFile(sfConfig::get('sf_upload_dir').'/media/'.$fn);
        $thumbnail->save(sfConfig::get('sf_upload_dir').'/media/'.$thumbParam['dir'].'/'.$fn, 'image/jpeg');
      }
    }
    return $fn;
  }

Source : http://snippets.symfony-project.org/snippet/101

Gallerie d’image flottante

Une gallerie photo flottante en HTML/CSS librement inspirée des albums picasa web de Google :

Feuille de styles :

html > body .floatingBlockContainer {
    display: -moz-inline-box;
    display: inline-block
}

.floatingBlockContainer {
    position: relative;
    display: inline-block
}

* html .floatingBlockContainer {
    display: inline
}

*:first-child + html .floatingBlockContainer {
    display: inline
}

.floatingBlocksContainer {
    width: 100%;
    height: 100%
}

.floatingBlockContainer {
    text-align: center;
    vertical-align: middle;
    margin: 0 5px 12px 5px
}

.floatingBlock img {
    border: 1px solid #aaa;
    vertical-align: top;
}

.floatingBlock span {
    display: block;
    margin-left: auto;
    margin-right: auto;
    overflow: hidden
}

.floatingBlock {
    width: 128px;
    height: auto
}

Page HTML :

Source : http://picasaweb.google.com/home

←Older