JeuWeb - Crée ton jeu par navigateur
Gérer plusieurs plateformes différentes au sein de Symfony2 - Version imprimable

+- JeuWeb - Crée ton jeu par navigateur (https://jeuweb.org)
+-- Forum : Discussions, Aide, Ressources... (https://jeuweb.org/forumdisplay.php?fid=38)
+--- Forum : Programmation, infrastructure (https://jeuweb.org/forumdisplay.php?fid=51)
+--- Sujet : Gérer plusieurs plateformes différentes au sein de Symfony2 (/showthread.php?tid=6761)



Gérer plusieurs plateformes différentes au sein de Symfony2 - qwarnant - 08-02-2014

Bonjour à tous,

Dans le cadre du développement de Cygnus, je suis amené à développer trois interfaces.
  1. L'interface que je nommerais "desktop" qui est basée sur une vue 3D avec WebGL. Cette vue pourra être désactivée pour les PC trop lents et sera complètement indisponible sur smartphones et tablettes.
  2. Le suivante est une interface responsive complète, dédiée à ceux qui désactivent la vue 3D ou qui surfent sur leur tablette et leur mobile grâce à un navigateur sur le jeu.
  3. Enfin, une troisième interface sera une interface responsive épurée dédiée à une application Android native que je chargerai via une webview Android avec du JS adapté permettant de faire du binding entre une classe Java dans l'application et le JS de la page.

Voici mon problème : toutes ses vues ont des fonctionnements différents au niveau de la navigation. La vue desktop représente du "single-page" navigation, on ne peut pas recharger les assets de ThreeJS à chaque fois, tous les call de rafraichissements sont donc faits en Ajax via des controllers REST. La seconde est une interface avec navigation classique, avec des menus déroulants, plusieurs controllers et était anciennement la première interface du jeu pour les tests. La dernière est à mi-chemin entre les deux, car elle n'aura pas toutes les options de la vue complète mais elle ne sera pas non plus en 3D.
Du coup .. C'est un peu le jeu de piste dans mes bundles et mon projet Sf2 en général. Je dois gérer 3 façons différentes de naviguer au sein du jeu, ce qui implique des controllers Ajax, des controllers "normaux" et le code présent dans ces controllers se répète souvent, étant donné que le traitement est pratiquement le même, sauf que pour Ajax je renvoie un code d'erreur et pour les autres interfaces je fais un forward avec un message dans le flashbag de la session Sf2. J'ai aussi des includes de templates alors que dans une autre interface c'est des héritages ... Et au final, c'est loin d'être propre.

Est-ce que quelqu'un a déjà eu l'expérience de tels projets, si oui comment a-t-il fait pour fournir une architecture propre et efficace pour résoudre ce genre de problèmes ?

Merci d'avance,

Cordialement


RE: Gérer plusieurs plateformes différentes au sein de Symfony2 - Sephi-Chan - 08-02-2014

J'ai eu une fois affaire à ce genre de problématique où j'avais vraiment 2 variantes d'interface à rendre selon des conditions diverses (essentiellement basée sur la requête elle-même : paramètre d'URL, Cookies, Header, User Agent, etc.). Dans ton cas, ces conditions sont :
  • Une machine peu performante. On peut supposer que tu stockes ça dans un cookie, pour que ça reste propre à la machine en cours) ou dans les préférences de ton utilisateur courant (s'il fait ce choix de manière globale) ;
  • Les tablettes et smartphones. Tu peux utiliser le user agent pour identifier ces machines ;
  • L'utilisation du site via l'application Android, là je suppose que l'application peut définir un cookie, utiliser un user agent particulier, transmettre un header ou une variable dans l'URL. : quoi qu'il en soit le choix est facile pour chaque requête.

L'idée, c'est que quand une requête arrive, ton contrôleur détermine quel template rendre selon la variante de l'application demandée. Il peut également faire des traitements spécifiques pour une variante ou une autre.

Du coup c'est plutôt simple et tu restes DRY : tu utilises le tronc commun de code que tu désires pour chaque action, et tu as des templates différents pour les différentes vues, ce qui t'épargne de la logique conditionnelle (= complexité) dans celles-ci.

Ça vaut ce que ça vaut, mais la récente release de Rails 4.1 intègre un mécanisme de variant de ce style (honnêtement, c'est juste une façon d'intégrer le pattern que j'ai énoncé au framework, donc c'est vraiment pas spécifique à Ruby). Ça peux t'inspirer : Ruby on Rails 4.1 - Action Pack Variants.


RE: Gérer plusieurs plateformes différentes au sein de Symfony2 - qwarnant - 08-02-2014

Bonjour Sephi,

Merci pour ta réponse. J'avais déjà pensé utiliser ce type de mécanisme en analysant le user-agent en cherchant un peu sur stackoverflow, c'est ce que la majorité des gens font en chargeant des templates avec une extension différente pour chaque type de plateforme supportée, je sais que je dois continuer dans cette voie.

Ma question portait également sur le côté architecture entre la version 3D/Ajax et les versions de navigation classique. Pour les vues, ok pas de soucis on peut utiliser le user-agent. Mais pour les parties du code similaires entre les call Ajax et le call HTTP ... Pour le moment, je duplique les controllers dans chaque bundle : je fais un AjaxController et un MonBundleController qui sont presque identiques, sauf pour la gestion de fin de méthode, retourne un code d'erreur pour Ajax ou forward de la request dans le cas de la navigation classique. C'est dans cette partie de ma question initiale que j'attends le plus de retour, car je ne pense pas que ce soit la meilleur façon de faire, hélas j'ai pas trouvé mieux pour l'instant.

Un cas d'utilisation simple : Le joueur veut modifier sa production.
Sur l'interface classique, c'est simplement un formulaire, une soumission sur un controller, et une modification de la production avec un message de confirmation après redirection.
Sur l'interface 3D, je bloque la soumission via JS, et au je fais un call post avec jQuery sur le controllerAjax/REST, qui fait exactement le même travail sauf qu'il renvoie un code d'erreur. En fonction du code, je fais une alert Bootstrap différente.

Un autre cas d'utilisation : Le joueur développe un niveau de bâtiment.
Sur l'interface classique, même fonctionnement si ce n'est qu'à la redirection, il y a rafraichissement des listes de constructions et le bâtiment en construction est affiché.
Sur l'interface 3D, je bloque le onclick sur les liens, et même fonctionnement, je fais un call sur le ControllerAjax/REST qui renvoie un code d'erreur. Mais ici, il faut en plus rajouter le bâtiment dans les listes de construction en plus si la construction a été acceptée, ce qui équivaut à un deuxième call pour récupérer une liste, parsée selon un certain template pour ajouter l'HTML produit à la page. Pour le moment, je fais un .html() en jQuery sur le div des listes pour ajouter le contenu de la liste reçue par le call, mais je doute que ce soit une façon optimisée de faire. Mais je suis obligé pour obtenir le template de la liste ...

Une meilleure idée ?


RE: Gérer plusieurs plateformes différentes au sein de Symfony2 - Sephi-Chan - 08-02-2014

L'idée est d'avoir une seule action. Par exemple imaginons un contrôleur Building qui a une action update. Peu importe qui l'appel, il fait le même boulot (le fameux tronc commun dont je parlais), il peut également faire des traitements spécifiques à la variante utilisée (disons par exemple que tu veux updater un compteur du nombre d'utilisation de l'API REST, mais ça pourrait être n'importe quoi). Ce qu'il retourne en réponse peut varier.

Un exemple d'action différentes selon le type de format/variantes (oui c'est du Rails, mais je pense que Symfony est assez proche pour que tu t'en inspires) :


class BuildingsController < ApplicationController
# PATCH /buildings/:id.
def update
building = current_user.buildings.find(params[:id])
building.raise_level(params[:building][:level])

respond_to do |format|
format.json do
API.increment_uses_counter

if building.errors.any?
render(json: { status: 'error', errors: building.errors })
else
render(json: { status: 'success' })
end
end


# Sur l'interface responsive tu rediriges et tu ajoutes les éventuelles erreurs au "flashbag" pour les afficher.
format.html.responsive do
flash[:error] = building.errors if building.errors.any?
redirect_to(building_path(building))
end

# Sur l'interface classique, tu redirigie ou tu rends le formulaire de saisie (en cas d'échec).
format.html.none do
if building.errors.any?
render(Confusedome_view)
else
redirect_to(building_path(building))
end
end
end
end
end



RE: Gérer plusieurs plateformes différentes au sein de Symfony2 - qwarnant - 08-02-2014

C'est ça, c'était les deux choix possibles que j'avais, soit je dupliquais les appels dans un autre controller dédié à l'Ajax, soit j'utilisais la même méthode et je gérais les différentes provenances de la requête !

Parfait, merci beaucoup d'avoir répondu ! Big Grin

Dernière petite question ...

(08-02-2014, 11:54 AM)MicroDev a écrit : Mais ici, il faut en plus rajouter le bâtiment dans les listes de construction en plus si la construction a été acceptée, ce qui équivaut à un deuxième call pour récupérer une liste, parsée selon un certain template pour ajouter l'HTML produit à la page. Pour le moment, je fais un .html() en jQuery sur le div des listes pour ajouter le contenu de la liste reçue par le call, mais je doute que ce soit une façon optimisée de faire. Mais je suis obligé pour obtenir le template de la liste ...

Une meilleure idée ?

Merci !


RE: Gérer plusieurs plateformes différentes au sein de Symfony2 - Sephi-Chan - 09-02-2014

Si tu veux garder une réponse JSON dans ton API JSON, tu peux toujours envoyer ton fragment de HTML avec la réponse (donc l'objet de réponse sera donc tel que { status: 'success', html: '<div>...</div>' }).

Tu peux également — si tu fais du templating client-side — envoyer une structure JSON que ton client utilisera pour créer le DOM requis.


RE: Gérer plusieurs plateformes différentes au sein de Symfony2 - qwarnant - 09-02-2014

Merci Sephi, c'était les deux options que j'avais retenue également.

Néanmoins, mes templates étant assez complexes, j'ai retenu la réponse à fragment HTML parce que ce serait trop fastidieux, je pense, de faire du DOM sur un réponse JSON pour rafraichir les listes ou tout autre élément de la page !

Merci en tout cas Wink


RE: Gérer plusieurs plateformes différentes au sein de Symfony2 - Sephi-Chan - 09-02-2014

Je pense que tu fais le bon choix, le plus pragmatique. Le templating client-side est adapté pour une application cliente (Backbone ou assimilé), mais faire du templating des deux côtés est assez pénible (et très chronophage).