http://www.fri-dev.com/index.php?

Aller au contenu | Aller au menu | Aller à la recherche

lundi, novembre 30 2009

symfony android client

A small client to send requests from android to your symfony apps (symfony's REST pattern compliant).

sfClient (singleton to store session) :

  1. package org.me.sfBackendClient;
  2.  
  3. import org.apache.http.impl.client.DefaultHttpClient;
  4.  
  5. /**
  6.  * symfony application client singleton
  7.  * thanks to Cansin http://senior.ceng.metu.edu.tr/2009/praeda/2009/01/11/a-simple-restful-client-at-android/
  8.  * @author jean-philippe serafin <jean-philippe.serafin@dev-solutions.fr>
  9.  */
  10. public class sfClient{
  11. private static sfClient instance;
  12. protected DefaultHttpClient httpClient;
  13. /**
  14.   * constructor
  15.   */
  16. private sfClient(){
  17. this.httpClient = new DefaultHttpClient();
  18. }
  19. /**
  20.   * instance accessor
  21.   */
  22. public static sfClient getInstance(){
  23. if(null == instance){
  24. instance = new sfClient();
  25. }
  26. return instance;
  27. }
  28. /**
  29.   * creating new request
  30.   */
  31. public sfRequest createRequest(){
  32. sfRequest request = new sfRequest(this.httpClient);
  33. return request;
  34. }
  35. }

sfRequest :

  1. package org.me.sfBackendClient;
  2. //IO
  3. import java.io.BufferedReader;
  4. import java.io.IOException;
  5. import java.io.InputStream;
  6. import java.io.InputStreamReader;
  7. //utils
  8. import java.util.List;
  9. import java.util.ArrayList;
  10. //apache
  11. import org.apache.http.HttpEntity;
  12. import org.apache.http.HttpResponse;
  13. import org.apache.http.client.ClientProtocolException;
  14. import org.apache.http.client.entity.UrlEncodedFormEntity;
  15. import org.apache.http.client.methods.*;
  16. import org.apache.http.NameValuePair;
  17. import org.apache.http.message.BasicNameValuePair;
  18. import org.apache.http.impl.client.DefaultHttpClient;
  19.  
  20. /**
  21.  * symfony request
  22.  * thanks to Cansin http://senior.ceng.metu.edu.tr/2009/praeda/2009/01/11/a-simple-restful-client-at-android/
  23.  * @author jean-philippe serafin <jean-philippe.serafin@dev-solutions.fr>
  24.  */
  25. public class sfRequest{
  26. protected String url;
  27. protected String method;
  28. protected List<NameValuePair> params;
  29. protected HttpGet getRequest;
  30. protected HttpPost postRequest;
  31. protected HttpResponse response;
  32. protected String result;
  33. protected DefaultHttpClient httpClient;
  34.  
  35. /**
  36.   * constructor
  37.   */
  38. public sfRequest(DefaultHttpClient client){
  39. this.httpClient = client;
  40. this.params = new ArrayList<NameValuePair>(2);
  41. }
  42. public void setUrl(String url){
  43. this.url = url;
  44. }
  45. public String getUrl(){
  46. return this.url;
  47. }
  48. public void setMethod(String method){
  49. this.method = method;
  50. }
  51. public String getMethod(){
  52. return this.method;
  53. }
  54. /**
  55.   * Adding parameter
  56.   * @param key
  57.   * @param value
  58.   */
  59. public void addParam(String key, String value){
  60. this.params.add(new BasicNameValuePair(key, value));
  61. }
  62. /**
  63.   * getting response text
  64.   * @return String response
  65.   */
  66. public String getResult(){
  67. return this.result;
  68. }
  69. /**
  70.   * executing request
  71.   */
  72. public void execute(){
  73. try {
  74. if(this.method.compareToIgnoreCase("GET") == 0){
  75. this.getRequest = new HttpGet(this.getUrl());
  76. this.response = this.httpClient.execute(this.getRequest);
  77. }else if(this.method.compareToIgnoreCase("POST") == 0
  78. || this.method.compareToIgnoreCase("PUT") == 0
  79. || this.method.compareToIgnoreCase("DELETE") == 0){
  80. this.addParam("sf_method", this.getMethod());
  81. this.postRequest = new HttpPost(this.getUrl());
  82. this.postRequest.setEntity(new UrlEncodedFormEntity(this.params));
  83. this.response = this.httpClient.execute(this.postRequest);
  84. }
  85. HttpEntity entity = response.getEntity();
  86. if(entity != null){
  87. InputStream inputStream = entity.getContent();
  88. this.result = convertStreamToString(inputStream);
  89. }
  90. } catch (ClientProtocolException e) {
  91. //e.printStackTrace();
  92. this.result = e.getMessage();
  93. } catch (IOException e) {
  94. this.result = e.getMessage();
  95. }
  96. }
  97. /**
  98.   * converting stream reader to string
  99.   * @return String
  100.   */
  101. private static String convertStreamToString(InputStream is) {
  102. StringBuilder stringBuilder = new StringBuilder();
  103.  
  104. String line = null;
  105. try {
  106. while ((line = reader.readLine()) != null) {
  107. stringBuilder.append(line + "\n");
  108. }
  109. } catch (IOException e) {
  110. e.printStackTrace();
  111. } finally {
  112. try {
  113. is.close();
  114. } catch (IOException e) {
  115. e.printStackTrace();
  116. }
  117. }
  118. return stringBuilder.toString();
  119. }
  120. }

Usage :

  1. sfRequest request = sfClient.getInstance().createRequest();
  2. request.setUrl("http://xxxxxxxxx/androidConnect/connect");
  3. request.setMethod("POST");
  4. request.addParam("login", loginField.getText().toString());
  5. request.addParam("password", passwordField.getText().toString());
  6. request.execute();
  7. String message = request.getResult();

thanks to Cansin

jeudi, novembre 19 2009

sfCmsSolution overview

Our new symfony powered CMS : sfCmsSolution

  • login : guest
  • password : guest

sfGridSolution beta 3 | grid state persistance

Another GridSolution beta introducing datagrid state persistance in cookie : samples.

  1. svn co http://svn-gridsolution.dev-solutions.fr/tags/beta-3

dimanche, octobre 11 2009

GridSolution beta

We've just tagged a beta release of sfGridSolutionPlugin our mootools datagrid.

You can checkout the symfony plugin :

  1. svn co http://svn-gridsolution.dev-solutions.fr/tags/beta-1

or just javascript files for use outside symfony

  1. svn co http://svn-gridsolution.dev-solutions.fr/tags/beta-1/sfGridSolutionPlugin/web/js/

we're now working on optimisation, documentation and samples.

GridSolutionCookie will be released ASAP for view state persistance.

mardi, septembre 8 2009

sfGridSolutionPlugin alpha

Ca y est, voici la première version téléchargeable de sfGridSolutionPlugin. Attention, il s'agit d'une version alpha pas encore vraiment débuggée sur IE, des fonctionnalités risquent fortement de changer.

Vous pouvez jeter un oeil sur la démo.

Exemple d'implémentation :

Dans votre contrôleur symfony :

  1. /**
  2.   * getting main data
  3.   * @param sfWebRequest $request A request object
  4.   */
  5. public function executeGetData(sfWebRequest $request)
  6. {
  7. //initialise
  8. $gridAction = new sfGridSolutionQuery($request);
  9. //defining get datas query
  10. $gridAction->setQuery(
  11. Doctrine_Query::create()
  12. ->select('*')
  13. ->from('Exemple e')
  14. );
  15. die($gridAction->execute());
  16. }
  17. /**
  18.   * Showing demo grid
  19.   * @param sfRequest $request A request object
  20.   */
  21. public function executeIndex(sfWebRequest $request)
  22. {
  23. //init grid
  24. $this->grid = new sfGridSolution('grid', 'mygrid', array(
  25. 'showHeader' => true,
  26. 'resizeColumns' => true,
  27. 'selectRow' => true,
  28. 'sortOn' => 'id',
  29. 'sortBy' => 'DESC',
  30. 'getDataUrl' => 'Exemple/getData', // => route to find datas
  31. 'saveDataUrl' => 'Exemple/saveData', // => route to save data
  32. 'getDataMethod' => 'post',
  33. 'page' => 1,
  34. 'perPageOptions' => array(10, 15, 20, 50),
  35. 'perPage' => 20,
  36. 'height' => 300,
  37. 'imagesPath' => 'sfGridSolutionPlugin/images'
  38. ));
  39. //adding id
  40. $this->grid->addGroup(
  41. new sfGridSolutionGroup(
  42. 'label' => '&nbsp;',
  43. 'isResizable' => true,
  44. 'cssClass' => 'group',
  45. 'columns' => array(
  46. new sfGridSolutionColumn(
  47. 'label' => 'id',
  48. 'model' => 'id',
  49. 'align' => 'right',
  50. 'filterable' => true,
  51. 'sortable' => true,
  52. 'width' => '90',
  53. 'actions' => array(
  54. new sfGridSolutionAction(
  55. 'title' => 'Show details',
  56. 'method' => 'showDetails', // => will call javascript showDetails() method
  57. 'icon' => 'viewmag.png'
  58. )
  59. )
  60. )
  61. )
  62. )
  63. )
  64. )
  65. )
  66. );
  67. //group1
  68. $this->grid->addGroup(
  69. new sfGridSolutionGroup(
  70. 'label' => 'group1',
  71. 'isResizable' => true,
  72. 'cssClass' => 'group',
  73. 'collapsable' => 'true',
  74.  
  75. 'collapse' => false,
  76. 'columns' => array(
  77. new sfGridSolutionColumn(
  78. 'label' => 'int_field1_1',
  79. 'model' => 'int_field1_1',
  80. 'align' => 'right',
  81. 'filterable' => false,
  82. 'sortable' => true,
  83. 'width' => '90'
  84. )
  85. ),
  86. new sfGridSolutionColumn(
  87. 'label' => 'char_field1_2',
  88. 'model' => 'char_field1_2',
  89. 'align' => 'right',
  90. 'filterable' => true,
  91. 'sortable' => true,
  92. 'editable' => true,
  93. 'width' => '90'
  94. )
  95. ),
  96. new sfGridSolutionColumn(
  97. 'label' => 'date_field1_3',
  98. 'model' => 'date_field1_3',
  99. 'editable' => true,
  100. 'align' => 'left',
  101. 'filterClass' => 'DateFilter',
  102. 'filterable' => true,
  103. 'sortable' => true,
  104. 'width' => '130'
  105. )
  106. )
  107. )
  108. )
  109. )
  110. );

Dans la vue :

  1. <h1>Demo Data Grid</h1>
  2.  
  3. <div id="mygrid" style=""></div>
  4.  
  5. <?php echo $grid->render();?>
  6.  
  7. <script type="text/javascript">
  8. function showDetails(event, action, cell){
  9. cell.row.buildExpandTip('Exemple/getDetails?id=' + cell.row.datas['id'].value);
  10. }
  11. </script>

Un peu plus de doc verra le jour au fur et à mesure du développement.

vendredi, septembre 4 2009

Monkey Physics datepicker : keyboard navigation fix

Monkey Physics datepicker is the best mootools datepicker ever. The problem with this picker is that there's no way for keyboard navigation.

We made a patch to fix it :

jeudi, août 13 2009

GridSolution : mootools object oriented datagrid

Pour des besoins de saisie / recherche / modification de données complexes, une datagrid simple et rapide à mettre en place est indispensable. Après quelques recherches, on s'aperçoit rapidement que l'offre des datagrid sur mootools est très réduite. La seul Grid qui sort du lot à mon goût est celle d'omindatas : omnigrid. Cependant malgré la simplicité du concept, on se retrouve très vite limité dans les évolutions et l'ajout de fonctionnalités.

C'est donc de ce constat qu'est née GridSolution, une grille orientée objet de manipulation de données.

Ce script n'en est qu'à ses prémisses mais s'avère assez prometteur.

Les objectifs pour une première version tagguée "stable" sont :

- pouvoir instancier des groupes de colonnes :

  1. var myGroup = new GridSolutionGroup({
  2. label : 'my group',
  3. isResizable : true,
  4. cssClass : 'group'
  5. });

- pouvoir instancier des colonnes :

  1. var myColumn = new GridSolutionColumn({
  2. label : 'id',
  3. model : 't.id', // => alias du modèle de données
  4. cssClass : 'right',
  5. sortable : true, //=> autorise le classement vertical
  6. width : 40
  7. });

- grouper des colonnes :

  1. myGroup.options.columns = [myColumn];

- instancier la grille :

  1. window.addEvent("domready", function(){
  2. var datagrid = new GridSolution($('mygrid'), {
  3. showHeader : true,
  4. resizeColumns : true,
  5. selectRow : true,
  6. sortOn : 'id',
  7. sortBy : 'DESC',
  8. getDataUrl : 'getData.php',
  9. getDataMethod : 'post',
  10. page : 1,
  11. perPageOptions : [10, 15, 20, 50],
  12. perPage : 20,
  13. header : myGroup,
  14. height : 300,
  15. imagesPath : '/grid/sfGridSolutionPlugin/images'
  16. });
  17. });

- filtrer les colonnes par type de données :

  1. var myColumns = new GridSolutionColumn({
  2. label : 'Sended at',
  3. model : 't.charging_at',
  4. filterable : true, // => initialise le filtre
  5. dataType : 'dateTime', // => génère un dateTimePicker
  6. sortable : true,
  7. width : 200,
  8. tip : ''
  9. });

filter.png

- éditer les lignes de façon asynchrone :

  1. myColumn.options.editable = true;
  2. datagrid.options.setDataUrl = 'setData.php';

- affichage des erreurs renvoyées par le serveur :

validator.png

- afficher le détail d'une ligne :

expend.png

- une manipulation des données orientées opérateurs de saisies (100% manipulable sans le pointeur de la souris).

Ce sont les fonctionnalités actuellement présentes sur la version de développement.

Pour le date picker, j'ai choisi datepicker, mais ce choix reste sous réserve pour des questions de compatibilité IE6 (/performances) et d'ergonomie (il n'est pas 100% navigable au clavier).

Je vous laisse faire un tour sur la démo en attendant une version stable et téléchargeable sous license MIT qui devrait voir le jour début septembre après arrêt des nouvelles fonctionnalités, débug, tests et optimisations du code. A noter qu'en parallèle, un plugin pour symfony / doctrine est en cours de réalisation pour permettre des développements rapides d'interfaces complexes.