jeudi 9 octobre 2014

[JOOMLA] Suivi création de composant 3.x

Bonjour,

Je dévelope actuellement un composant qui permettra aux clients d'envoyer des messages anonymes à un groupe d'administrateur charger de s'occuper de ces gens.

J'ai suivi la docs officiel qui propose de crée un petit helloworld.




Premier problème le tri des colonnes dans la partie admin ne fonctionnait pas, j'ai reussi à résoudre ce probléme en farfouillant dans les composant joomla (com_banners)

J'ai ensuite voulu ajouter les filtres j'ai donc suivi ce tuto :http://docs.joomla.org/J2.5:How_to_a..._to_components

Que j'ai adapter à la version 3.x en utilisant encore une fois ce que j'ai pu voir dans com_banners.Cela ne fonctionne pas.

Le problème :

aprés l'ajout du code le tri ne fonctionne plus (on clique une fois ca tri en asc, on reclick ca trie en desc, on reclik encore ca remet en asc puis ca ne change plus)

Le probléme viens, je pense, du fullordering :

ma consol me dit : public 'list.fullordering' => string 'null ASC' (length=8)

Dans Admin/forms j'ai ajouter ceci a mon fichier xml :


Code HTML:
 <fields name="list">
  <field
   name="fullordering"
   type="list"
   label="JGLOBAL_SORT_BY"
   statuses="*,0,1,2,-2"
   description="JGLOBAL_SORT_BY"
   onchange="this.form.submit();"
   default="id ASC"
   >
   <option value="">JGLOBAL_SORT_BY</option>
   <option value="id ASC">JGRID_HEADING_ID_ASC</option>
   <option value="id DESC">JGRID_HEADING_ID_DESC</option>
  </field>
  <field
   name="limit"
   type="limitbox"
   class="input-mini"
   default="25"
   label="COM_ONLINEHELPS_LIST_LIMIT"
   description="COM_ONLINEHELPS_LIST_LIMIT_DESC"
   onchange="this.form.submit();"
  />
 </fields>
Je presume que ce fichier xml est appeler par le populatestate?
Actuellement ma fonction populatestate ressemble a ceci :

Code PHP:
 protected function populateState($ordering null$direction null)
        {
            
// Initialise variables.
            
$app JFactory::getApplication('administrator');
    
            
// Load the filter state.
            
$search $this->getUserStateFromRequest($this->context '.filter.search''filter_search');
            
$this->setState('filter.search'$search);
    
            
$state $this->getUserStateFromRequest($this->context '.filter.state''filter_state''''string');
            
$this->setState('filter.state'$state);
    
            
// Load the parameters.
            
$params JComponentHelper::getParams('com_letest');
            
$this->setState('params'$params);
    
            
// List state information.
            
parent::populateState('id''asc');
        }  
Je ne suis pas trés doué en php j'ai donc du mal a comprendre comment appeler mon fichier xml? (en partant du principe que c'est ca le problème biensure)

Edit: après quelques manipulations sur le com_banners j'ai decouvert que mon problème ne vient pasdu fullordering je repars à 0 

EDIT 07/10/14

J'ai reussi a faire fonctionner le tri avec les filtre par defaut de joomla (state et search) en revanche j'ai ajouter un nouveau filtre 'section' qui correspond a la colonne 'section' de ma table.Cette colonne peut contenir 3 valeurs (jeune / adulte / prof) l'idée c'est de pouvoir aficher que les lignes qui correspondent a jeune (par exemple) mais je bloque.

ma fonction getoption (admin/models/fields/monfichier.php): 


Code PHP:
protected function getOptions()
        {
                
// Initialize variables.
                
$options = array();

                
$db     JFactory::getDbo();
                
$query  $db->getQuery(true)

            ->
select('id As value, section As text')
            ->
from('#__matable AS a')
            ->
order('a.section');

                
// Get the options.
                
$db->setQuery($query);

                
$options $db->loadObjectList();

                
// Check for a database error.
                
if ($db->getErrorNum()) {
                        
JError::raiseWarning(500$db->getErrorMsg());
                }

                return 
$options;
        }  
Ce que j'ai rajouter dans mon fichier xml de filtre :

Code:
                 <field
   name="section"
   type="monfichier"
   label="COM_MONFICHIERS_FILTER_SECTION"
   description="COM_MONFICHIERS_FILTER_SECTION_DESC"
   onchange="this.form.submit();"
   >
   <option value="">COM_MONFICHIERS_SELECT_SECTION</option>
  </field>
Et enfin l'ajout dans ma fonction getListQuery (admin/models/monfichiers.php) :

Code PHP:
if ($section $this->getState('filter.section'))
        {
            
var_dump($this->getState('filter.section'));
            
$query->where('section = ' $db->quote($section));
            echo 
$query;
        }  
EDIT (09/10/14)

Les filtres fonctionnent j'ai crée un fichier php par filtre spécifiques pour les filtres 'globaux' j'ai pu utiliser les librairies joomla voiciun exemple d'un fonction getOptions() pour un filtre spécifique :

Code PHP:
protected function getOptions()
        {

        
$db JFactory::getDbo();
        
$query $db->getQuery(true)
            ->
select ('distinct section As value, section As text')
            ->
from('#__matable AS a')
            ->
group('value');

        
// Get the options.
        
$db->setQuery($query);

        try
        {
            
$options $db->loadObjectList();
        }
        catch (
RuntimeException $e)
        {
            
JError::raiseWarning(500$e->getMessage());
        }

        
// Merge any additional options in the XML definition.
        // $options = array_merge(parent::getOptions(), $options);

        
array_unshift($optionsJHtml::_('select.option''0'JText::_('COM_MONCOMPOSANT_SECTION')));

        return 
$options;
        }
}  
a retenir : beaucoup de tuto/forum et cie disent qu'il faut utiliser la fonctions populatestate, aprés plusieurs test voila ma fonction populatestate actuel :


Code PHP:
  protected function populateState($ordering null$direction null)
        {
            
// List state information.
            
parent::populateState('id''asc');
        }

Pour mes filtres perso voilà ma démarche :
- si ils 'agit d'un filtre spécifique : création d'un fichier php dans admin/models/fileds avec la fontions getoptions qui va bien (voir plus haut)

-ajout du field XML dans le fichier filter_tonfiltre.xml (admin/models/forms)

-ajout du filtre dans le fichier php toncomposants.php (admin/models) comme suit (exemple pour un filtre spécifique et un filtre qui utilise les lib joomla):


Code PHP:
 // Filter by published state
                
$published $this->getState('filter.published');
          
                if (
is_numeric($published))
                {
                    
$query->where('published = ' . (int) $published);
                }
                elseif (
$published === '')
                {
                    
$query->where('(published IN (0, 1))');
                }
  
                
//filter by section
                
if ($section $this->getState('filter.section'))
                {
                    
$query->where('section = ' $db->quote($section));
                }  
(PS: n'oublier pas d'afficher le tout dans votre vue (le code qui suit est a placé aprés la balise ouvrante <form>: )


Code PHP:
<div class="row-fluid">
        <div class="span12">
            <?php echo JText::_('COM_ONLINEHELP_ONLINEHELPS_FILTER'); ?>             <?php
                
echo JLayoutHelper::render(
                    
'joomla.searchtools.default',
                    array(
'view' => $this)
                );
            
?>         </div>
    </div>


Je m'attaque au coté client actuellement j'ai un formulaire de ce type : 


Code HTML (la vue) :
<form id="form_oh" method="post" action="components\com_onlinehelp\controllers\formulaire.php">
 <fieldset>
  <p><label for="pseudo">Ton pseudo :</label><input type="text" id="pseudo" name="pseudo" required /></p>
  <p><label for="genre">Tu es :</label>
  <input type="radio" id="genre_m" name="genre"  /> un garçon</p>
  <input type="radio" id="genre_f" name="genre"  /> une fille</p>
  <p><label for="age">Ton âge :</label><input type="number" id="age" name="age" required /></p>
  <p><label for="question">Ta question :</label><textarea id="question" name="question" required cols="30" rows="8"></textarea></p>
  Ici tu peux écrire le texte de ta demande. Tu peux nous écrire en français, en allemand, en anglais.

  Tu peux agrandir le champ texte en tirant avec le pointeur sur l'angle en bas à droite
 </fieldset>
 

  
 
 <div style="text-align:center;"><input type="submit" name="envoi" value="Envoyer ma question" /></div>
</form>

Code PHP (controlleur):
if(isset($_POST['pseudo']))      $pseudo=$_POST['pseudo'];
else      
$pseudo="";

if(isset(
$_POST['genre']))      $genre=$_POST['genre'];
else      
$genre="";

if(isset(
$_POST['age']))      $age=$_POST['age'];
else      
$age="";

if(isset(
$_POST['question']))      $question=$_POST['question'];
else      
$question=""// On vérifie si les champs sont vides if(empty($pseudo) OR empty($genre) OR empty($age) OR empty($question))
{
    echo 
'<font color="red">Attention, tous les champs sont obligatoires !</font>';

}  

l'idée c'est d'utiliser les outils joomla (genre Jinput) pour rendre le tout plus safe (pasque la bonjour les injections !)

Donc le frontend fonctionne voici les modif faite sur le code :


Code PHP (la vue):
<div class="composant-form">
    <form id="composant-form" action="<?php echo JRoute::_('index.php'); ?>" method="post" class="form-validate form-horizontal">
        <fieldset>
            <legend><?php echo JText::_('COM_COMPOSANT_FORM_LABEL');?></legend>
            <div class="control-group">
                <div class="control-label"><?php echo $this->form->getLabel('section'); ?></div>
                <div class="controls"><?php echo $this->form->getInput('section'); ?></div>
            </div>
            <div class="control-group">
                <div class="control-label"><?php echo $this->form->getLabel('pseudo'); ?></div>
                <div class="controls"><?php echo $this->form->getInput('pseudo'); ?></div>
            </div>
            <div class="control-group">
                <div class="control-label"><?php echo $this->form->getLabel('genre'); ?></div>
                <div class="controls"><?php echo $this->form->getInput('genre'); ?></div>
            </div>
            <div class="control-group">
                <div class="control-label"><?php echo $this->form->getLabel('age'); ?></div>
                <div class="controls"><?php echo $this->form->getInput('age'); ?></div>
            </div>
            <div class="control-group">
                <div class="control-label"><?php echo $this->form->getLabel('question'); ?></div>
                <div class="controls"><?php echo $this->form->getInput('question'); ?></div>
            </div>

        </fieldset>
            <div class="form-actions">
                <button class="btn btn-primary validate" type="submit"><?php echo JText::_('COM_COMPOSANT_COMPOSANT_SEND'); ?></button>
                <input type="hidden" name="option" value="com_composant" />
                <input type="hidden" name="task" value="composant.submit" />
                <?php echo JHtml::_('form.token'); ?>             </div>
 
</form>
</div>
 Ensuite voila a quoi ressemble mon fichier view.html.php :

Code PHP (view.html.php) il récupére le form et le passe à la vue ce qui permet de faire les traitements:
class OnlineHelpViewOnlineHelp extends JViewLegacy // Overwriting JView display method
        
function display($tpl null)
        {     
                
// Assign data to the view
                
$this->form $this->get('Form');

                
// Check for errors.
                
if (count($errors $this->get('Errors')))
                {
                        
JLog::add(implode('<br />'$errors), JLog::WARNING'jerror');
                        return 
false;
                }
                
// Display the view
                
parent::display($tpl);
        }
}  

Ensuite j'ai eu besoin de crée une page qui, aprés l'envoi du formulaire, affiche un message de confirmation ainsi que le pseudo et un code unique pour l'utilisateur, j'ai donc du recup les données.La première idée fu de passer mes 2 param dans l'url et de les recupéré avec un $_GET, cette variable n'étant pas 'safe' le Jinput fait son retour :

pour pouvoir utiliser tout correctement et surtout proprement j'ai crée 2 fonctions dans mon model :

Code PHP (confirmation.php : le model) :
            /**
             * Get the pseudo
             * @return string The pseudo to be displayed to the user
             */
            
public function getPseudo()
            {
                
$jinput JFactory::getApplication()->input;
                if (!isset(
$this->pseudo))
                {
                    
$this->pseudo $jinput->get('pseudo');
                }
                return 
$this->pseudo;
            } 
         
            
/**
             * Get the code question
             * @return string The code unique to be displayed to the user
             */
         
            
public function getCode_unique()
            {
                
$jinput JFactory::getApplication()->input;
                if (!isset(
$this->code_unique))
                {
                    
$this->code_unique $jinput->get('code_unique');
                }
                return 
$this->code_unique;
            }  

Ensuite j'ai rajouter la génération d'un code unique dans mon tableau de donnée que je crée dans mon controllers dans ma fonction submit:

Code PHP:
$data[code_question] = uniqid();  

Ainsi a la fin de mon submit je redirige vers une URL qui contient mes 2 valeurs :

Code PHP:
$this->setRedirect(JRoute::_('index.php?option=com_composant&view=confirm&pseudo='.$data[pseudo].'&code_unique='.$data[code_question],false));  
Ensuite on assigne nos données a la vue (via le fichier view.html.php de notre vue 'confirm)

Code PHP (view.html.php):
class ComposantViewConfirm extends JViewLegacy // Overwriting JView display method
        
function display($tpl null)
        {         

         
             
                // Assign data to the view
                
$this->pseudo $this->get('Pseudo');
                
$this->code_question $this->get('Code_unique');

                
// Check for errors.
                
if (count($errors $this->get('Errors')))
                {
                        
JLog::add(implode('<br />'$errors), JLog::WARNING'jerror');
                        return 
false;
                }
                
// Display the view
                
parent::display($tpl);
        }

On peut donc utiliser notre pseudo et notre code unique sans soucis dans la vue (et surtout sans $_GET et de manière sécurisée)

Code PHP:
<p><?php echo JText::_('COM_COMPOSANT_MSG_CONFIRMATION_PSEUDO');  echo $this->pseudo ;  ?></p>
<p><?php echo JText::_('COM_COMPOSANT_MSG_CONFIRMATION_CODE_UNIQUE');  echo $this->code_unique;  ?></p>
 (les longue chaine de majuscules sont des label, j'utilise un fichier de traduction il n'y a donc aucun texte en dur dans le code)

Aller on attaque la création du module !

1 commentaire:

  1. J'attaque la création du module lié à ce composant, j'ai crée un suivi de la même manière disponible ici: http://nep-dev.blogspot.com/2014/10/joomla-suivi-de-creation-de-module-3x.html

    RépondreSupprimer